We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 18654
    • 191 Posts
    I have a script that loops through multiple contexts and selects resources based on criteria. For example, a "ShowOnHomePage" Template Variable attached to an Event Resource in the NC State Context determines whether a link to this resource is shown on the home page.

    The problem I’m having is that when I change the Template Variable from "Yes" to "No" or vice-versa whatever cache files it’s clearing, it’s missing something because I have to manually clear the cache via site->clear cache for the results to show up correctly. I didn’t have this issue when I was keeping all my events in the web context - it’s only when using multiple contexts.

    Is this expected behavior? Is the only way to deal with this to manually clear the cache every time I change a field in a context other than web or to make the snippet call uncached?

    I do have a cron job that clears the cache daily just before it updates the events, so I could probably get away with leaving it as-is, but some users might get confused when they don’t see immediate results. And trying to explain to non-technical people about how they need to manually clear the cache in certain circumstances could be challenging.

    -matt
      God does not save those who are only imaginary sinners. Be a sinner, and let your sins be strong, but let your trust in Christ be stronger, and rejoice in Christ who is the victor over sin, death, and the world.
      • 22303 MODX Staff
      • 10,725 Posts
      Quote from: mattcdavis1 at Apr 03, 2010, 06:38 AM

      I have a script that loops through multiple contexts and selects resources based on criteria. For example, a "ShowOnHomePage" Template Variable attached to an Event Resource in the NC State Context determines whether a link to this resource is shown on the home page.
      Why does it loop through Contexts? Can’t you just get the Resources based on the criteria in one query? Here’s an example, simplified and adapted from getResources (you’d probably also need to add special sorting to build the menu properly, or to get nested children, etc):
      <?php
      $output = array();
      if (!empty($parents) && !empty($contexts)) {
          /* explode a comma delimited list of parent Resources */
          $parents = explode(',', $parents);
          /* explode a comma delimited list of Contexts to look at */
          $contexts = explode(',', $contexts);
          /* define specific columns to return helps reduce memory usage of the result set */
          $columns = array(
              'id'
              ,'pagetitle'
              ,'menutitle'
          );
      
          /* create a new xPDOQuery object and define the initial criteria */
          $criteria = $modx->newQuery('modResource', array(
              'deleted' => 0
              ,'published' => 1
              ,'hide_menu' => 0
              ,"`modResource`.`parent` IN (" . implode(',', $parents) . ")"
              ,"`modResource`.`context_key` IN ('" . implode("','", $contexts) . "')"
          ));
      
          /* this additional criterion is a very efficient way to check for a specific Resource TV value */
          $tmplVarTbl = $modx->getTableName('modTemplateVar');
          $tmplVarResourceTbl = $modx->getTableName('modTemplateVarResource');
          $criteria->where("EXISTS (SELECT 1 FROM {$tmplVarResourceTbl} `tvr`
                  JOIN {$tmplVarTbl} `tv` ON `tvr`.`value` = 'Yes'
                  AND `tv`.`name` = 'ShowOnHomePage'
                  AND `tv`.`id` = `tvr`.`tmplvarid`
                  WHERE `tvr`.`contentid` = `modResource`.`id`)"
          );
          /* specify the columns to return from the modResource */
          $criteria->select($modx->getSelectColumns('modResource', '', '', $columns));
      
          /* get the collection of Resources */
          $collection = $modx->getCollection('modResource', $criteria);
          
          /* loop through the collection */
          foreach ($collection as $object) {
              /* load an array with just the values of the columns you selected */
              $data = $object->get($columns);
              /* add the url to the data */
              $data['url'] = $modx->makeUrl($object->get('id'));
              if (!empty($tpl)) {
                  /* if you defined a chunk tpl, pass the data to the chunk to get the processed output */
                  $output[] = $modx->getChunk($tpl, $data);
              } else {
                  /* otherwise just dump the data to output in pre tags */
                  $output[] = '<pre>' . print_r($data, true) . '</pre>';
              }
          }
      }
      return implode("\n", $output);
      ?>


      Quote from: mattcdavis1 at Apr 03, 2010, 06:38 AM

      The problem I’m having is that when I change the Template Variable from "Yes" to "No" or vice-versa whatever cache files it’s clearing, it’s missing something because I have to manually clear the cache via site->clear cache for the results to show up correctly. I didn’t have this issue when I was keeping all my events in the web context - it’s only when using multiple contexts.

      Is this expected behavior? Is the only way to deal with this to manually clear the cache every time I change a field in a context other than web or to make the snippet call uncached?
      I think this is unexpected and should be reported in JIRA. Am I understanding correctly, when editing a Resource in a Context other than web, and editing the value of a Template Variable, the cached Resource is not cleared?
        • 18654
        • 191 Posts
        I need to loop through contexts because each context has information that I need in it’s settings. Each context represents a chapter in our organization. On the home page, for example, the script needs to accomplish the following:

        1. Get resources only from contexts whose key "site_type" == "chapter_subdomain’
        2. Each domain has a resource container that contains events. The id of this events container is specified in the context settings - so I need to get the id of the events resource container from each context.
        3. [And this is where I’m having the problems] check the "ShowOnHomePage" TV of each returned resource to determine whether to put in the the upcoming events section of the home page. I have to manually clear the cache to do this.

        #1 could be accomplished via your script by specifying a list of contexts in the snippet call, but I kind of like idea of not having to worry about that. The way it’s currently setup, when I add new chapter-contexts I don’t need to touch any other code. Now, I suppose I could run a query that gets the appropriate contexts (key:’site_type’ == value:’chapter_subdomain’) and then write the context-keys to an array and then pass that array as a variable to the snippet you provided. That would solve the problem of not having to update the snippet when I add a new chapter/context.

        #2 could be handled by manually listing event resource containers in the snippet call, but then I run into the same issue as #1 where I have to update multiple snippets (or at the very least a property set) every time I add a new chapter-context.

        #3 obviously wouldn’t be an issue.

        I guess my question is why not loop through contexts? My script is comparable in size (lines of code) and the logic is pretty straight-forward so its easy to maintain. However, I don’t know the inner workings of ModX like you do. Perhaps looping through contexts is much more expensive as far as processing time? If this is the case, perhaps I will look into using property sets with my snippets to provide the needed information and use something similar to the code you provided. I just really liked the idea of being able to put a bunch of settings in one place (context key-value settings) and then utilizing those values in my scripts.

        Actually, now that I think about it I can definitely see where it would be much more time consuming using my approach, especially if our organization grows to 20,30, or more chapters. That’s 30+ queries as opposed to one. Perhaps the best approach then would be to transfer the information that I’m currently storing in context settings to a property set instead and then use some version of the script you provided. Does that sound like a good approach? The only potential downside here is in that in some cases a key-value pair may needed to be associated with a specific context. I haven’t experimented much with property sets (actually, I’ve never used them), so I’m not sure if I can do this or not. I’ll have to experiment and find out.

        As far as the cache-clearing question. The non-web-context resource variables may be clearing some cache files on-TV-save, but I know for certain that when looping through contexts it does not recognize a TV Value change unless I manually clear the cache.

        UPDATE:

        After giving it some more thought, I think I’m simply going to create a TV called "ResourceType" with a dropdown list of values that will initially include "event_resource" and "event_resource_container". The events and their corresponding TV’s are updated and created via a script that pulls from Google Calendar, so the user won’t ever have to worry about adjusting this field. This approach allows for only one query and keeps things pretty simple.

        But then again, this wouldn’t work for situations where I need to list all chapters, since there isn’t an actual "chapter" resource. Each context is a chapter. So, I guess I will still need to implement something along the lines of what was mentioned above.

        -matt




          God does not save those who are only imaginary sinners. Be a sinner, and let your sins be strong, but let your trust in Christ be stronger, and rejoice in Christ who is the victor over sin, death, and the world.
          • 18654
          • 191 Posts
          OpenGeek - thanks for your help with this issue. I’ve rewritten the script so that I don’t need to loop through contexts. I decided to utilize TV’s instead of context key/values. However, the cache issue does indeed seem to be a bug. I’ll post it in JIRA.

          Here’s what I ended up with:
          <?php
          
          	$outputArray = array();
          	$homePageArray = array();
          	
          	//Get an array of Event Resources
          	$c = $modx->newQuery('modResource');
          	$c->innerJoin('modTemplateVarResource', 'TemplateVarResources');
          	$c->where(array(
          		'TemplateVarResources.tmplvarid' => 26 //Resource Type TV
          		,'TemplateVarResources.value' => 'event_page'
          	));
          	$c->sortby('unpub_date');
          	$eventObjects = $modx->getCollection('modResource',$c);  
          	
          	//Refine initial array to resources that have "ShowOnHomePage" == Yes
          	foreach ($eventObjects as $eventObject) {
          		if($eventObject->getTVValue(9) == 'Yes') {
          			$homePageArray[] = $eventObject;	
          		}
          	}
          
          	if (count($homePageArray) > 0) {
          	
          		foreach ($homePageArray as $key => $event) {
          			$event_date = strtotime($event->get('unpub_date'));
          			$outputArray['event_date'] = date('l, F jS, Y', $event_date);
          			$outputArray['event_link'] = '[[~' .  $event->get('id') . ']]';
          			$outputArray['event_campus'] = 'Campus: ' . $event->getTVValue(17);
          			$outputArray['event_content'] = $event->get('introtext');			
          
          			if ($key == key(reset($event))) {
          				echo $modx->parseChunk('EventFirst', $outputArray);
          					if ($key == end(array_keys($homePageArray))) echo '</ul>';
          			}
          					   
          			else if ($key != end(array_keys($homePageArray))) {
          				echo $modx->parseChunk('EventRepeat', $outputArray);
          			}
          			
          			else {
          				echo $modx->parseChunk('EventLast', $outputArray);
          			}	
          
          		}//End foreach ($homePageArray as $key => $event) {}
          	} //End if (count($homePageArray) > 0) {}
          					   
          	else {
          		echo $modx->parseChunk('EventFirst', $outputArray) . '</ul>';
          	}
          ?>
          

            God does not save those who are only imaginary sinners. Be a sinner, and let your sins be strong, but let your trust in Christ be stronger, and rejoice in Christ who is the victor over sin, death, and the world.