We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 3749
    • 24,544 Posts
    On a cached page, when an uncached snippet call returns a chunk with $chunk->process(), it will return a cached version of the chunk in Revolution.

    $chunk = $modx->getObject('modChunk',array(
        'name' => $spfresponseTpl
        ));
        if ($chunk == null) {
            die ($modx->lexicon('no-template'). $spfresponseTpl);
        }
        return ($chunk->process());

    Maybe this is expected, but it caught me by surprise (and I don’t want to admit how many hours it took to figure it out). embarrassed

    If the chunk were placed in a page with tags, it could be marked as uncached. Is there an equivalent for grabbing it uncached in an uncached snippet? Making the resource uncached solved it, but I expected it to take on the caching of the snippet that retrieved it.

    This could make for some very weird behavior in uncached snippets on cached pages.

      Did I help you? Buy me a beer
      Get my Book: MODX:The Official Guide
      MODX info for everyone: http://bobsguides.com/modx.html
      My MODX Extras
      Bob's Guides is now hosted at A2 MODX Hosting
      • 22303 MODX Staff
      • 10,725 Posts
      Quote from: BobRay at Oct 18, 2008, 12:29 AM

      On a cached page, when an uncached snippet call returns a chunk with $chunk->process(), it will return a cached version of the chunk in Revolution.

      Maybe this is expected, but it caught me by surprise (and I don’t want to admit how many hours it took to figure it out). embarrassed

      If the chunk were placed in a page with tags, it could be marked as uncached. Is there an equivalent for grabbing it uncached in an uncached snippet? Making the resource uncached solved it, but I expected it to take on the caching of the snippet that retrieved it.

      This could make for some very weird behavior in uncached snippets on cached pages.
      Hmmm, not sure if it is expected, and will certainly take some getting used to, but the cache control and flexibility gained IMO should be worth it. I think it’s more natural for anything cacheable within non-cacheable content to remain cacheable rather than being forced to non-cacheable automatically, especially now that all Elements and [most] Tags can be non-cacheable explicitly.

      That said, it seems there is not a proper way to set this through the API at the moment, though the private modElement->_cacheable field controls this. So, for now, you can control the cacheability by simply doing this:
      <?php
      $chunk = $modx->getObject('modChunk',array(
          'name' => $spfresponseTpl
      ));
      $chunk->_cacheable = false;
      return ($chunk->process());
      ?>

      and I’ll add that to the getChunk() and parseChunk() API calls to prevent this behavior until we can decide on the best way to control this consistently across all Elements moving forward. I was considering making it a parameter of process() so that the function can make local decisions on this which override the actual _cacheable property of the object, though I also need to consider that a cacheable field in the database will be added to all Element tables. A simple duo of getter and setter functions for determining and controlling the runtime cacheability, taking into account the persistent setting in the database as well as other factors, is likely the best solution to this, i.e.:
      <?php
      $chunk = $modx->getObject('modChunk',array('name' => $spfresponseTpl));
      if ($chunk->isCacheable()) {
          $chunk->setCacheable(false);
      }
      ?>

      Also note, that Elements (and/or Tags) are cached into a Resource by their tag signature, and this signature is generated from the properties that are set for that Element (as opposed to calling them via tags where properties are already passed as part of the tag). If you pass in an array of properties to $modx->getChunk() or to the $chunk->process() function directly, your tag signatures will reflect those key/value pairs and each instance will not be pulled from cache so long as the properties are different.
        • 3749
        • 24,544 Posts
        I think the setCacheable() solution is a good one. There should probably be a checkbox on the create/edit chunk page so set the default.

        I realized this morning that I didn’t describe the problem as clearly as I should have. The real problem is that the chunk is being cached after the placeholders have been replaced. When I set new values for the placeholders, retrieve the chunk with getObject(), and return $chunk->process(), I get the old placeholder values, presumably because there are no placeholder tags in the cached chunk I retrieved.

        Again, I’m not sure what should happen in this situation, but I think it’s natural for snippet writers to assume that if you set a placeholder and return a chunk containing that placeholder that you’d see the value you just set in the output. Having that work sometimes and not others (depending on whether the page is cached) might lead people to avoid using tpl chunks altogether and just generate the output in the snippet.

        The solution you gave, BTW, does work for getting the current placeholder values into the returned output:

        $chunk->_cacheable = false;
          Did I help you? Buy me a beer
          Get my Book: MODX:The Official Guide
          MODX info for everyone: http://bobsguides.com/modx.html
          My MODX Extras
          Bob's Guides is now hosted at A2 MODX Hosting
          • 3749
          • 24,544 Posts
          As I wrote in the post above, the real problem in this case was with getting cached versions of the placeholders. I was glancing at the listing of the new Revolution tags pushpinned above my screen and noticed the line: "Anything can be cached ..."

          I changed the placeholders to [[!+placeholder]] and the problem seems to be solved regardless of the cacheable status of the chunk they are in.

          My complements to the chef !! grin

          I think this makes the issue of un-caching chunks somewhat less critical. It’s still important for people who want to specify which chunk is used on the fly, but in many cases, just having the placeholders fresh is perfect.

          Just out of curiosity, in this case where the page is cached, the snippet is called uncached, the chunk is cached and the placeholders are uncached. Is the chunk really coming from the cache?
            Did I help you? Buy me a beer
            Get my Book: MODX:The Official Guide
            MODX info for everyone: http://bobsguides.com/modx.html
            My MODX Extras
            Bob's Guides is now hosted at A2 MODX Hosting
            • 22303 MODX Staff
            • 10,725 Posts
            Quote from: BobRay at Oct 20, 2008, 01:24 AM

            As I wrote in the post above, the real problem in this case was with getting cached versions of the placeholders. I was glancing at the listing of the new Revolution tags pushpinned above my screen and noticed the line: "Anything can be cached ..."

            I changed the placeholders to [[!+placeholder]] and the problem seems to be solved regardless of the cacheable status of the chunk they are in.

            My complements to the chef !! grin
            FWIW, placeholders can never be cached technically; this behavior is only because you are delaying the processing of the placeholder tags by introducing the non-cacheable token ( ! ) to them. They are not processed until all cacheable content (which is reachable through cacheable processing) has been processed. However, when loaded from the Resource cache file, any tags that were processed as cacheable before the Resource was cached will be cached along with it, and this, when loaded from the cache, the chunk tag would have been loaded from the elementCache, since it is cacheable, but the non-cacheable placeholders tags would not have been removed since they are processed in the final step and only stored in the output which is generated by the additional non-cacheable processing performed in modResponse::outputContent().

            Quote from: BobRay at Oct 20, 2008, 01:24 AM
            I think this makes the issue of un-caching chunks somewhat less critical. It’s still important for people who want to specify which chunk is used on the fly, but in many cases, just having the placeholders fresh is perfect.
            IMO, passing placeholders intended for a chunk directly to it as properties, e.g. $modx->getChunk(’MyChunk’, array(’placeholder1’ => ’value1’)) is the best approach, as this ensures the scope of those placeholders is only that chunk (or anything contained in it). This approach will not work with the delayed global non-cacheable placeholder idea however, since the placeholders will only technically be in place for the scope of the chunk and not beyond it, but this completely depends on how you set up the placeholders and when. For chunks that are called repetitively in the same page, passing them as properties is the best way.

            BTW, this is equivalent to calling $modx->parseChunk(’MyChunk’, array(’placeholder1’ => ’value1’)) except that they are actually set in $modx->placeholders temporarily during the processing of the chunk, and removed immediately after.

            Quote from: BobRay at Oct 20, 2008, 01:24 AM

            Just out of curiosity, in this case where the page is cached, the snippet is called uncached, the chunk is cached and the placeholders are uncached. Is the chunk really coming from the cache?
            I believe so; you can see everything that was cached by looking at the Resource cache file. You would look in core/cache/web/resources/1.php for the Resource with id 1 in the default web context.
              • 3749
              • 24,544 Posts
              Quote from: OpenGeek at Oct 20, 2008, 10:13 AM

              FWIW, placeholders can never be cached technically; this behavior is only because you are delaying the processing of the placeholder tags by introducing the non-cacheable token ( ! ) to them. They are not processed until all cacheable content (which is reachable through cacheable processing) has been processed. However, when loaded from the Resource cache file, any tags that were processed as cacheable before the Resource was cached will be cached along with it, and this, when loaded from the cache, the chunk tag would have been loaded from the elementCache, since it is cacheable, but the non-cacheable placeholders tags would not have been removed since they are processed in the final step and only stored in the output which is generated by the additional non-cacheable processing performed in modResponse::outputContent().

              If I’m understanding this correctly (a statistically very unlikely event), it seems to contradict what I observed with an uncached snippet on a cached page. The snippet grabs a chunk with getObject, sets a placeholder with setPlaceholder() and returns $chunk->process(). What I’m seeing is that the placeholder value is the one set in a previous visit to the page. IOW, (I assume) the chunk was saved to the cache after the placeholder was replaced. Delaying the processing of placeholders can’t help if they’re not in the cached version of the chunk to begin with, no?

              IMO, passing placeholders intended for a chunk directly to it as properties, e.g. $modx->getChunk(’MyChunk’, array(’placeholder1’ => ’value1’)) is the best approach, as this ensures the scope of those placeholders is only that chunk (or anything contained in it). This approach will not work with the delayed global non-cacheable placeholder idea however, since the placeholders will only technically be in place for the scope of the chunk and not beyond it, but this completely depends on how you set up the placeholders and when. For chunks that are called repetitively in the same page, passing them as properties is the best way.
              I get the first sentence here, but the second one came close to actually melting my brain. If I’m right above and the chunk is being cached after the placeholders are replaced, passing placeholders in the getChunk call wouldn’t work since there would be no placeholders in the returned object (unless I set _chacheable to false -- which solves the problem even without the second argument). I guess I should try it to make sure.

              To back up a little, this is a problem that will be faced by anyone with a snippet that has tpl chunks and values for the placeholders in those chunks that might change (e.g. Ditto, Wayfinder, MaxiGallery, etc.). It looks like we have a number of solutions that ensure that placeholder values will be the one’s most recently set by setPlaceholder() in cases where there is no [[!$chunk]] tag because the chunk is pulled by a snippet, plugin, or module:

              1. Have a "cacheable" checkbox for chunks, like the one for snippets.
              2. Set _cacheable to false.
              3. Use [[!+placeholder]] for the placeholders in the tpl.
              4. Pass the placeholder values to getChunk.
              5. Provide an "uncached" argument for getChunk() and getObject().
              6. Have getChunk() and getObject() respond to getChunk(’!chunkName’).

              Number 3 seems to me to be the most consistent with the MODx cache scheme, easiest for the developer, understandable, and intuitive. Is it reliable, or could it be made reliable?
                Did I help you? Buy me a beer
                Get my Book: MODX:The Official Guide
                MODX info for everyone: http://bobsguides.com/modx.html
                My MODX Extras
                Bob's Guides is now hosted at A2 MODX Hosting
                • 22303 MODX Staff
                • 10,725 Posts
                Working on all the recent refactorings we’ve been discussing in branches/revolution-elements/ and I have already applied setCacheable(false) in the version of getChunk() and runSnippet() (same issue there) so that API calls will not be cached, as expected. I will be merging this back into the main branch once I finish a few more changes to the default properties editor tabs that will soon appear when adding/editing any Element.

                My concern is that when caching is enabled and placeholders are involved, we have to think about scope in complex ways. Is some other script responsible for setting those placeholders cached? Then what? As long as we never cache calls from the API (which doesn’t make sense anyway), I believe we will be ok, and we can leave all the complex decision making out of the developer’s heads; then they can decide when it’s appropriate to use [[! ]] vs. passing properties to the chunk or TV for local replacement (allowing the parent chunk or TV tag to control the ultimate cacheability).

                Adding cacheable fields (and matching checkboxes) to all elements is coming, along with the ability to pull in config settings from namespaces.
                  • 3749
                  • 24,544 Posts
                  I confirmed that, contrary to my expectations, passing the value to getChunk() does work -- no surprise to you, I’m sure. wink

                  If I only pass one placeholder name and value that way, what’s the effect on the other placeholders in the chunk if the chunk is cached? Do they remain cached?

                  Ultimately, I’d like to have some placeholders in a chunk cached and others not. There could easily be a large cached chunk with lots of placeholders that should be cached and only one or two that need to be uncached. Using [[!+placeholder]] would be a nice easy way of accomplishing that in a cached chunk. Is that a possible scenario?

                    Did I help you? Buy me a beer
                    Get my Book: MODX:The Official Guide
                    MODX info for everyone: http://bobsguides.com/modx.html
                    My MODX Extras
                    Bob's Guides is now hosted at A2 MODX Hosting
                    • 22303 MODX Staff
                    • 10,725 Posts
                    Quote from: BobRay at Oct 20, 2008, 06:16 PM

                    If I only pass one placeholder name and value that way, what’s the effect on the other placeholders in the chunk if the chunk is cached? Do they remain cached?
                    It’s literally added to the placeholder array during processing of the chunk and removed after processing, so a chunk that is cached will never set the placeholders from the properties when loaded from the cache.

                    Quote from: BobRay at Oct 20, 2008, 06:16 PM

                    Ultimately, I’d like to have some placeholders in a chunk cached and others not. There could easily be a large cached chunk with lots of placeholders that should be cached and only one or two that need to be uncached. Using [[!+placeholder]] would be a nice easy way of accomplishing that in a cached chunk. Is that a possible scenario?
                    You could do that, as long as those placeholder values were not set by properties passed to the chunk. This would not work, since these local property placeholders are removed after processing and any colliding placeholders in the previous scope restored. So [[!+placeholder]] would basically prevent it from being processed in the local scope of the chunk, even when uncached. Using the non-cacheable token (i.e. ! ) always delays processing until all cacheable processing is completed by either the Template attached to a Resource, or the Content of a Resource itself if no Template is specified.
                      • 3749
                      • 24,544 Posts
                      Quote from: OpenGeek at Oct 20, 2008, 06:49 PM

                      Quote from: BobRay at Oct 20, 2008, 06:16 PM

                      If I only pass one placeholder name and value that way, what’s the effect on the other placeholders in the chunk if the chunk is cached? Do they remain cached?
                      It’s literally added to the placeholder array during processing of the chunk and removed after processing, so a chunk that is cached will never set the placeholders from the properties when loaded from the cache.
                      I must be misunderstanding this because what I see seems to contradict this. My chunk is in a cached page and should be cached by default (causing my original problem). But it *does* set the placeholder from the properties sent in the getChunk() call even though I don’t use _cachable=false or the ! token in the placeholder tags.

                      Quote from: BobRay at Oct 20, 2008, 06:16 PM

                      Ultimately, I’d like to have some placeholders in a chunk cached and others not. There could easily be a large cached chunk with lots of placeholders that should be cached and only one or two that need to be uncached. Using [[!+placeholder]] would be a nice easy way of accomplishing that in a cached chunk. Is that a possible scenario?
                      You could do that, as long as those placeholder values were not set by properties passed to the chunk. This would not work, since these local property placeholders are removed after processing and any colliding placeholders in the previous scope restored. So [[!+placeholder]] would basically prevent it from being processed in the local scope of the chunk, even when uncached. Using the non-cacheable token (i.e. ! ) always delays processing until all cacheable processing is completed by either the Template attached to a Resource, or the Content of a Resource itself if no Template is specified.

                      I like that, but now I have this question: Why would I ever want to use the properties array in getChunk() if I can get any combination of cacheing I want using just setPlaceholder() and [[!$placeholder]], especially since using the properties array might conflict with a placeholder marked with the ! tag (perhaps set by a user of the snippet modifying the tpl).?

                      BTW, I wanted to ask about the philosophy of using the properties array to *set* incoming properties in getChunk(). My understanding of the general use of arrays like that in the getObject family is that we use an array like that as a set of search criteria for finding the object (and the argument is called $criteria in getObject()). I understand that getChunk() is not just a wrapper for getObject(), but based on what I knew of MODx objects, I would have guessed that that array in getChunk() would just add extra search criteria. I would never have guessed that its function was to set properties of the returned object and it would be really tough to understand what the scope of those changes would be (even after having it explained). And it’s not that common, IMO, to *set* specific object properties in a *get* method.

                      I don’t have much in the way of an alternative to suggest, but thought I’d at least raise the issue. The only other way I could think of is to do away with that argument altogether (or just not tell people about it) and just use setPlaceolder() and the ! token in the placeholder tags, even if it’s a little less efficient. It might prevent having to have a discussion like this one with a boatload of confused developers. wink
                        Did I help you? Buy me a beer
                        Get my Book: MODX:The Official Guide
                        MODX info for everyone: http://bobsguides.com/modx.html
                        My MODX Extras
                        Bob's Guides is now hosted at A2 MODX Hosting