We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 36924 ☆ A M B ☆
    • 298 Posts
    I have resources with a TV called category.

    Say I have Resources A, B, C, D with the 'category' TV bearing Management for resource A, B, C while resource D bears Staff

    How do I list the categories without repeating the Categories?

    I want it listed thus:

    Management
    A
    B
    C
    
    Staff
    D


    Rather than:

    Management
    A
    Management
    B
    Management
    C
    
    Staff
    D
      • 3749
      • 24,544 Posts
      You could do it with two getResources calls, but I would do something like this (off the top of my head and untested):

      $tvId = 12; /* change this to the ID of the category TV */
      
      /* Get Management docs */
      $tvrs = $modx->getCollection('modTemplateVarResource', array('tmplvarid' => $tvId, 'value' => 'Management'));
      
      foreach ($tvrs as $tvr) {
          $docs[] = $tvr->get('contentid');
      }
      
      $c = $modx->newQuery('modResource');
      $c->where(
         array('id:in' => $docs)
      );
      $c->sortby('pagetitle', 'ASC');
      
      $managementDocs = $modx->getCollection('modResource', $c);
      
      $output = '<h3>Management</h3><ul>';
      foreach ($managementDocs as $doc) {
         $output .= '<li>' . $doc->get('pagetitle'). '</li>';
      }
      $output .= '</ul>';
      
      /*** Get Staff docs */
      
      $tvrs = $modx->getCollection('modTemplateVarResource', array('tmplvarid' => $tvId, 'value' => 'Staff'));
      
      foreach ($tvrs as $tvr) {
          $docs[] = $tvr->get('contentid');
      }
      
      $c = $modx->newQuery('modResource');
      $c->where(
         array('id:in' => $docs)
      );
      $c->sortby('pagetitle', 'ASC');
      
      $staffDocs = $modx->getCollection('modResource', $c);
      
      $output = '<h3>Staff</h3><ul>';
      foreach ($staffDocs as $doc) {
         $output .= '<li>' . $doc->get('pagetitle'). '</li>';
      }
      $output .= '</ul>';


      This should only take four queries. It's probably possible to use getCollectionGraph() or a join to do it in two queries, but I'm too tired to work it out. The code above will be *way* faster than doing it with getResources, which would make many more queries.

      You could also use a Tpl chunk to format the output, but it would slow things down slightly by adding a call to $modx->getChunk() for each resource. If you need to have a link to each resource, you can do something like this inside the document loop:

      $url = $modx->makeUrl($doc->get('id'), "", "", "full");
      $output .= '<li><a href="' . $url . '">' .  $doc->get('pagetitle'). '</a></li>';


      You could also shorten the code significantly (with little or no change in the speed) by putting a getDocs() function at the top, passing it the category, and having it return the output.

      That would look like this:



      function getDocs($category) {
          $tvId = 12; /* change this to the ID of the category TV */
          $tvrs = $modx->getCollection('modTemplateVarResource', array(
              'tmplvarid' => $tvId,
              'value'     => $category
          ));
      
          foreach ($tvrs as $tvr) {
              $docs[] = $tvr->get('contentid');
          }
      
          $c = $modx->newQuery('modResource');
          $c->where(
            array('id:in' => $docs)
      );
          $c->sortby('pagetitle', 'ASC');
      
          $staffDocs = $modx->getCollection('modResource', $c);
      
          $output = '<h3>' . $category . '</h3>
      <ul>';
          foreach ($staffDocs as $doc) {
              $output .= '<li>' . $doc->get('pagetitle') . '</li>';
          }
          $output .= '
      </ul>';
      
          return $output;
      }
      
      return getDocs('Management') . getDocs('Staff');
      
      


      Important: None of this will work if any of the TV values are inherited or hold the default value of the TV.

        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
        • 36924 ☆ A M B ☆
        • 298 Posts
        Thanks. Just saw the email notification. I'll look at the code and revert asap. God bless.
          • 36924 ☆ A M B ☆
          • 298 Posts
          Loooking at the code, I see the value of the TV 'category' needs to be hardcoded.
          My intent: end-user can enter any value into the 'category' TV; all resources bearing that TV value are displayed under that category on a summary page. So for each resource displayed underneath the respective Categories we have the PageTitle and other resource specific custom TV values.

          Kind of trying to achieve a MODx version of the DISTINCT and GROUP BY SQL statements.

          I guess I'm struggling painting my question. Hope you understand.
            • 3749
            • 24,544 Posts
            Will the "user" selecting/entering the category in a form, or editing a tag in the Manager?

            Either way, the code above could be modified to work for you.
              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
              • 36924 ☆ A M B ☆
              • 298 Posts
              Manager user will be entering the value in the 'category' TV of every new resource created.
                • 3749
                • 24,544 Posts
                OK, I hope I'm understanding what you want. This should do it (untested):

                $tvId = 12; /* change this to the ID of the category TV */
                
                function getDocs($category, $tvId) {
                    global $modx;
                    $tvrs = $modx->getCollection('modTemplateVarResource', array(
                        'tmplvarid' => $tvId,
                        'value'     => $category
                    ));
                    $docs = array();
                    foreach ($tvrs as $tvr) {
                        $docs[] = $tvr->get('contentid');
                    }
                
                    $c = $modx->newQuery('modResource');
                    $c->where(
                      array('id:in' => $docs)
                    );
                    $c->sortby('pagetitle', 'ASC');
                
                    $resources = $modx->getCollection('modResource', $c);
                
                    $output = '<h3>' . $category . '</h3>
                <ul>';
                    foreach ($resources as $resource) {
                        $output .= '<li>' . $resource->get('pagetitle') . '</li>';
                        /* Use this instead if you want links to the resources:
                        $url = $modx->makeUrl($doc->get('id'), "", "", "full");
                        $output .= '<li><a href="' . $url . '">' .  $doc->get('pagetitle'). '</a></li>';
                        */
                    }
                    $output .= '
                </ul>';
                
                    return $output;
                }
                
                /* Get all possible categories */
                $c = $modx->newQuery('modTemplateVarResource');
                $c->distinct();
                $c->where(array('tmplvarid' => $tvId));
                
                $tvrs = $modx->getCollection('modTemplateVarResource', $c);
                
                $output = '';
                /* Get the resources in each category */
                foreach ($tvrs as $tvr) {
                    $category = $tvr->get('value');
                    if (!empty($category)) {
                        $output .= getDocs($category, $tvId);
                    }
                }
                
                return $output;
                


                It ignores resources where the category is empty.



                  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
                  • 36924 ☆ A M B ☆
                  • 298 Posts
                  Wow. Though the current is what I achieved when I used a nested getResources approach, the code is very fast.

                  I have attached the files: GroupByCategoryCorrectList.gif (this is the goal) while GroupByCategoryWrongList.gif (is what the code is currently outputting) [ed. note: ojchris last edited this post 12 years, 4 months ago.]
                    • 3749
                    • 24,544 Posts
                    Are you saying that you're still getting duplicate categories in the list? The $c->distinct() is supposed to prevent that.

                    If it's still a problem, change this code near the end:

                        if (!empty($category)) {
                            $output .= getDocs($category, $tvId);
                        }


                    to this:

                        
                        if (!empty($category)) {
                            if (! in_array($category, $usedCategories)) {
                                $usedCategories[] = $category;
                                $output .= getDocs($category, $tvId);
                            }
                        }


                    Also, add this line just above the final foreach loop:

                    $usedCategories = array();
                      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
                      • 36924 ☆ A M B ☆
                      • 298 Posts
                      Finally the new additions solved it. The output is now as intended. I am even more thrilled by the fast response time (better than getResources).

                      Now in formatting the output I have a Chunk (for a getResources call) with the following:

                      <div class="classes">
                      <h2><strong>[[+pagetitle]]</strong></h2>
                      <ul>
                      <li><strong>Project:</strong> [[+tv.ProjectTitle]]</li>
                      <li><strong>Location: </strong> [[+tv.ProjectLocation]]</li>
                      <li><strong>Client:</strong> [[+tv.ProjectClient]]</li>
                      <li><strong>Terrain:</strong> [[+tv.ProjectTerrain]]</li>
                      </ul>
                      <p><strong>Overview</strong><br />
                      [[+introtext]]<p>
                      [[+tv.ProjectDetail:notempty=`<p>[[+tv.ProjectDetail]]<p>`]]
                      [[+tv.ProjectDetailTwo:notempty=`<p>[[+tv.ProjectDetailTwo]]<p>]]
                      
                      
                      <p  class="galleryIMGs">
                      
                      
                      [[!Gallery? &album=`[[+tv.ActivityAlbumTitle]]` &toPlaceholder=`gallery`  &limit=`1` &tag=`lead` &thumbTpl=`nest_galItemLink` &linkToImage=`1`]]
                      [[!Gallery? &album=`[[+tv.ActivityAlbumTitle]]` &toPlaceholder=`gallery2`  &tag=`follow` &thumbTpl=`nest_galItemFollowLink` &linkToImage=`1`]]
                      
                      [[+gallery]]
                      [[+gallery2]]
                      
                      </p>
                      </div>


                      Using this:
                      $page = $modx->getObject('modResource', $c);
                      and
                      $page->getTVValue('TvName')
                      I've been able to create this formatting within the code via appropriate concatenation.

                      How do I achive the IF check (e.g. [[+tv.ProjectDetail:notempty=`<p>[[+tv.ProjectDetail]]<p>`]].

                      And most importantly how do I make the Gallery snippet call (within the code):

                      [[!Gallery? &album=`[[+tv.ActivityAlbumTitle]]` &toPlaceholder=`gallery`  &limit=`1` &tag=`lead` &thumbTpl=`nest_galItemLink` &linkToImage=`1`]]
                      [[!Gallery? &album=`[[+tv.ActivityAlbumTitle]]` &toPlaceholder=`gallery2`  &tag=`follow` &thumbTpl=`nest_galItemFollowLink` &linkToImage=`1`]]
                      
                      [[+gallery]]
                      [[+gallery2]]
                      [ed. note: ojchris last edited this post 12 years, 4 months ago.]