We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 22448
    • 241 Posts
    I'm trying to get multiple tvs for each resource returned by getCollectionGraph but i seem to only get the last one. Here's the context:

    Schema:
    <?xml version="1.0" encoding="UTF-8"?>
    <model package="migxresourcerelations" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" version="1.1">
        <object class="rrResourceRelation" table="rr_resource_relations" extends="xPDOSimpleObject">
            
            <field key="source_id" dbtype="int" precision="10" phptype="integer" null="false" default="0" index="index" />
            <field key="target_id" dbtype="int" precision="10" phptype="integer" null="false" default="0" index="index" />	
    		<field key="active" dbtype="tinyint" precision="1" attributes="unsigned" phptype="integer" null="false" default="0" index="index" />
            <field key="published" dbtype="tinyint" precision="1" attributes="unsigned" phptype="integer" null="false" default="0" index="index" />
            <field key="pos" dbtype="int" precision="10" phptype="integer" null="false" default="0" index="index" />
            <field key="extended" dbtype="text" phptype="json" null="false" default="" />
           
            <aggregate alias="Source" class="modResource" local="source_id" foreign="id" cardinality="one" owner="foreign" />
            <aggregate alias="Target" class="modResourse" local="target_id" foreign="id" cardinality="one" owner="foreign" />          
        </object>
        
    </model> 


    Snippet:
    $criteria = array();
    $criteria['rrResourceRelation.target_id:IN'] = $cIDs;
    $criteria['TemplateVarResources.tmplvarid:IN'] = array(44,41,40,$relTV);
    $criteria = $modx->newQuery('rrResourceRelation', $criteria);
    $items = $modx->getCollectionGraph('rrResourceRelation','{"Source":{"TemplateVarResources":{}}}',$criteria);
    
    $target = array();
    foreach ($items as $item) {
            $target[] = $item->get('source_id');
            $target[] = $item->Source->get('pagetitle');
            $tvs = array();
            $tvCount = 0;
            foreach($item->Source->TemplateVarResources as $tvr) {
                $tvs[$tvr->get('id')] = $tvr->get('value');
            $tvCount++;
            }
    }
    $target[] = $tvs;


    Results:
    the output array show this:
    Array ( [0] => 4407 [1] => Emily Blake [2] => Array ( [7173] => 1 ) ) 


    Only the last tv (id = 7173) is being included. In modx_site_tmplvar_contentvalues resource 4407 has 5 tvs with values.

    I tried all sorts of ways and looked at several examples but can't see any issues with my code. Perhaps some fresh eyes can spot it.

    Any help is always appreciated. [ed. note: outre99 last edited this post 12 years, 1 month ago.]
      • 3749
      • 24,544 Posts
      Lines 2 and 3 aren't doing anything because they come before newQuery(), which creates a new $criteria object.

      The search criteria should go in a $criteria->where() statement that comes just after the newQuery().
        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
        • 4172
        • 5,888 Posts
        @Kiril:

        can you explain, what you are trying at all.
        Perhaps there a simpler ways to get what you want.
        Maybe by using pdoResources or a custom-snippet made by using pdoTools.
          -------------------------------

          you can buy me a beer, if you like MIGX

          http://webcmsolutions.de/migx.html

          Thanks!
          • 22448
          • 241 Posts
          Quote from: BobRay at Aug 25, 2014, 10:29 PM
          Lines 2 and 3 aren't doing anything because they come before newQuery(), which creates a new $criteria object.

          The search criteria should go in a $criteria->where() statement that comes just after the newQuery().

          Hi BobRay,
          i actually got that code from one of the examples in rtfm from here http://rtfm.modx.com/xpdo/2.x/class-reference/xpdo/xpdo.getcollectiongraph (in the debugging section). That part seems to work. I checked as the example recommends with
          $criteria->prepare();
          print $criteria->toSQL();
          and the generated sql looks right and returns proper results.

          The problem happens after getCollectionGraph gets called.
            • 3749
            • 24,544 Posts
            Ah, I didn't notice that you were passing $criteria as an argument to newQuery(). That's an unfamiliar way to do it for me.

            Would the fact that the criteria in lines 2 and 3 are ANDed explain your problem? Only TVRs that meet both will be retrieved.

              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
              • 22448
              • 241 Posts
              Hi Bruno,
              good to hear from you again. I actually got a few more questions about our custom MIGX configuration. Please let me know if you're available for a little bit of consulting.

              Back to this issue though.
              I got several relationships between modResources defined with your relations extra.

              I'm writing a custom snippet based on your rrgetrelations snippet. Originally i tried to include Target and Source documents into the single graph so i could generate both clinic and doctor output in the same loop and the statement looked like this:

              $items = $modx->getCollectionGraph('rrResourceRelation','{"Target":{},"Source":{"TemplateVarResources":{}}}',$criteria);
               

              But that would return nothing, i don't understand why since it looked ok based on the examples. So i removed the Target part which returned Source data but only with one tv for some reason.

              So in this case the Target is a clinic and the Source is a doctor. A doctor can be related to multiple clinics and a clinic can have multiple doctors. The clinics are organized in a hierarchy by country and city. So for each country/city i'm trying to list all clinics and the doctors for each clinic. The generated html is for Isotope filtering javascript by clinic.
              The full snippet is below. What really bewilders me is that this getCollectionGraph call actually works and returns data for the Source documents and for one tv but not all.

              I'm sure there are many ways to do this but i was trying to leverage the graph's promise of returning all related data in a single query. I did try looking at pdoTools but there was no documentation to speak of so I postponed diving into that code to figure it out but from the first glance there was nothing that would return the relationships that the graph provides.



              <?php
              $location = $modx->getOption('id', $scriptProperties, $modx->resource->get('id'));
              $levelType = $modx->getOption('leveltype', $scriptProperties, '');
              $outputSeparator = $modx->getOption('outputSeparator', $scriptProperties, ',');
              
              // load migxresourcerelations class
              $packageName = 'migxresourcerelations';
              $packagepath = $modx->getOption('core_path') . 'components/' . $packageName . '/';
              $modelpath = $packagepath . 'model/';
              
              $loaded = $modx->addPackage($packageName, $modelpath, $prefix);
              if (! $loaded) {return 'failed to add ' . $packageName;}
              $classname = 'rrResourceRelation';
              
              
              // determine current category and set featured TV
              $relName = 'clinics';
              $relTV = 67;
              
              // get ids of all sub-areas and their clinics
              $areas = $modx->getChildIds($location,5,array('context' => 'web'));
              $areas = array_unique($areas);
              
              // get clinic data
              $clinics = $clinicIDs = array();
              $criteria = $modx->newQuery('modResource');
              $criteria->distinct();
              $criteria->select('id','pagetitle','alias');
              $criteria->where(array('id:IN' => $areas, 'template' => '2'));
              $criteria->sortby('pagetitle','ASC');
              $collection = $modx->getCollection('modResource', $criteria);
              foreach ($collection as $clinic) {
                  $clinics[$clinic->get('id')]['alias'] =  $clinic->get('alias');
                  $clinics[$clinic->get('id')]['title'] =  $clinic->get('pagetitle');
                  $clinicIDs[] = $clinic->get('id');
              }
              $clinicIDs = array_unique($clinicIDs);
              
              
              //get doctor data
              $criteria = array();
              $criteria['rrResourceRelation.target_id:IN'] = $clinicIDs;
              $criteria['TemplateVarResources.tmplvarid:IN'] = array(44,41,40,$relTV);
              $criteria = $modx->newQuery('rrResourceRelation', $criteria);
              $items = $modx->getCollectionGraph('rrResourceRelation','{"Source":{"TemplateVarResources":{}}}',$criteria);
              
              
              //this is debug code to figure out why not all tvs are being returned
              // the actual code is commented below under 'prepare doctor output'
              $target = array();
              foreach ($items as $item) {
                      $target[] = $item->get('source_id');
                      $target[] = $item->Source->get('pagetitle');
                      $tvs = array();
                  $tvCount = 0;
                  foreach($item->Source->TemplateVarResources as $tvr) {
                          $tvs[$tvr->get('id')] = $tvr->get('value');
                      $tvCount++;
                      }
              }
              $target[] = $tvs;
              
              $doctorCount = $tvCount;
              $clinicOutput = $target;
              
              /*
              // prepare doctor output
              $featuredCount= 0;
              $doctorCount = 0;
              $doctorOutput = '';
              if (!empty($items)) {
                  foreach ($items as $item) {
                      if (is_object($item)) {
                          $doctorCount++;
                          $clinicTitle = $item->Target->get('pagetitle');
                          $clinicAlias = $item->Target->get('alias');
                          $doctorName = $item->Source->get('pagetitle');
                          $doctorID = $item->Source->get('id');
                          $featured = '';
                          $photo = '';
                          // get template var values
                          foreach ($item->Source->getMany('TemplateVarResources') as $tvr) {
                              switch ($tvr->get('tmplvarid')) {
                                  case 40:
                                      // 
                                      $photo = $tvr->get('value');
                                      $photo = (! empty($photo) ? $photo : '[[++theme_base_dir]]images/gallery-img3.jpg');
                                      break;
                                  case $relTV:
                                      // featured_in_...
                                      if ($tvr->get('value') == 1) {
                                          ++$featuredCount;
                                          $featured = 'featured';
                                      }
                              }
                          }
                          // generate output
                          $doctorOutput .= '<article class="entry '.$clinicAlias.' '.$featured.'"><div class="gallery-thumb"><img src="'.$photo.'"></div><p><a href="[[~' .$doctorID. ']]">' . $doctorName . '</a></p></article>';
                      }
                  }
              }
              
              
              // prepare clinic filters
              $url = $modx->makeUrl($modx->resource->get('id'));
              $url = substr($url, 0, -1).'#';
              
              $clinicOutput = '<li><a href="'. $url .'featured" class="selected" data-filter=".featured">Featured</a></li>';
              foreach ($clinics as $clinic) {
                  $clinicOutput .= '<li><a href="'.$url.$clinic['alias'].'" data-filter=".'.$clinic['alias'].'">'.$clinic['title'].'</a></li>';
              }
              */
              
              $modx->setPlaceholder('doctorcount', $doctorCount);
              $modx->setPlaceholder('filter', $clinicOutput);
              $modx->setPlaceholder('doctors', $doctorOutput);
              
              return '';

                • 22448
                • 241 Posts
                Quote from: BobRay at Aug 26, 2014, 01:29 PM
                Ah, I didn't notice that you were passing $criteria as an argument to newQuery(). That's an unfamiliar way to do it for me.

                Would the fact that the criteria in lines 2 and 3 are ANDed explain your problem? Only TVRs that meet both will be retrieved.


                But the criteria are specified with their class names/aliases. Wouldn't that prevent the confusion?
                Also removing line 3 produces the same result: 1 tv returned. [ed. note: outre99 last edited this post 12 years, 1 month ago.]
                  • 3749
                  • 24,544 Posts
                  Are any of the TVs set to their default value? If so, those TVs won't be in the modTemplateVarResource table (a good reason why it's a bad idea to use TV values for searching -- even if you can get it to work, it's very slow).
                    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
                    • 22448
                    • 241 Posts
                    Quote from: BobRay at Aug 26, 2014, 06:48 PM
                    Are any of the TVs set to their default value? If so, those TVs won't be in the modTemplateVarResource table (a good reason why it's a bad idea to use TV values for searching -- even if you can get it to work, it's very slow).

                    Thanks BobRay. Please keep your suggestions coming. I hope i'll get to the bottom of this.

                    Here are the rows from modx_site_tmplvar_contentvalues table for this doctor:

                    id;tmplvarid;contentid;value
                    2236;53;4407;[email protected]
                    4039;41;4407;258
                    5807;44;4407;275
                    7171;42;4407;258
                    7173;67;4407;1


                    Tvs and the values exist in the table.

                    I looked through your resource extender article and it makes perfect sense. Unfortunately i don't have the time to do complete refactoring before the deadline. I'll have to come back to that later. I can see how extending modResource can simplify a lot of things.
                      • 22448
                      • 241 Posts
                      So i tried to make the call generic by replacing compound criteria with simple one like so:

                      //get doctor data
                      $criteria = array();
                      //$criteria['rrResourceRelation.target_id:IN'] = $clinicIDs;
                      //$criteria['TemplateVarResources.tmplvarid:IN'] = array(44,41,40,$relTV);
                      $criteria['rrResourceRelation.source_id'] = '4178';
                      $criteria = $modx->newQuery('rrResourceRelation', $criteria);
                      $items = $modx->getCollectionGraph('rrResourceRelation','{"Source":{"TemplateVarResources":{}}}',$criteria);
                      
                      
                      //this is debug code to figure out why not all tvs are being returned
                      // the actual code is commented below under 'prepare doctor output'
                      $results = array();
                      foreach ($items as $item) {
                          $results['id'] = $item->get('source_id');
                          $results['title'] = $item->Source->get('pagetitle');
                          $tvs = array();
                          $tvCount = 0;
                          foreach($item->Source->TemplateVarResources as $tvr) {
                              $tvs[$tvr->get('id')] = $tvr->get('value');
                              $tvCount++;
                              }
                          $results['tvs'] = $tvs;
                      }


                      and it returns this:
                       Array ( [id] => 4178 [title] => Bxxxx Exxxx [tvs] => Array ( [7177] => 1 ) ) 


                      while modx_templvar_contentvalue for this resource looks like this:
                      id;tmplvarid;contentid;value
                      2007;53;4178;[email protected]
                      4299;41;4178;261
                      6067;44;4178;294
                      7174;36;4178;Male
                      7175;42;4178;261
                      7176;43;4178;1990
                      7177;67;4178;1


                      so it's the same problem. getCollectionGraph is not returning all of the tvs, just the last one.
                      I'm on Modx 2.3.1, could this be a bug?