Jump to:

3460 Posts in 1064 Topics by 739 members

Data Model Questions

SilverStripe Forums » Data Model Questions » Creating a list of pages with $belongs_many_many grouped by their Parent

Moderators: martimiz, Sean, biapar, Willr, Ingo, swaiba, simon_w

Page: 1
Go to End
Author Topic: 742 Views
  • Juanitou
    Community Member
    323 Posts

    Creating a list of pages with $belongs_many_many grouped by their Parent Link to this post


    The following code is working, it's based on the SiteMap tutorial, but I'm sure the same thing can be done more easily by using functions of ComponentSet and respecting the MVC paradigm.

    I have this Page_Themes many_many relationship between some pages (Articles, Links, BlogEntries) of a site and one kind of page that groups them by Theme :

    class Page extends SiteTree {
       // Pages can have many themes (see ThemePage for the other side of the relation)
       public static $many_many = array(
          'Themes' => 'ThemePage'


    // With class Theme it didn't worked, you had to add …Page
    class ThemePage extends Page {
       static $belongs_many_many = array(
          'Pages' => 'Page'

    My problem is that I wanted to give some context to the pages being classed by Themes, displaying also its parents. In ThemePages.ss I can display all pages belonging to the theme with a <% control Pages %>, where I can access the Parent of every page with $Parent.Title, for example. That's neat, but list look like:
    Pages belonging to the Theme XXX:
    Articles » Article1
    Blog entries » BlogEntry1
    Blog entries » BlogEntry2
    Links » Link

    I'd like to group all pages belonging to a theme by it's parent ID. I've looked to the DataObjectSet API doc and seen that there's some methods as GroupedBy, removeDuplicates… but I've not been able to work my way with the ComponentSet 'Pages'. So, I had to do this ugly thing in ThemePage.php:

    /* PagesList() creates an array of unique parents for the pages of this theme,
    ** then it passes it to makeList()
    function PagesList() {
       foreach ($this->Pages() as $page) {
          $parentIDs[$page->Parent->Title] = $page->ParentID;
       $parentIDs = array_unique($parentIDs);
       $output = $this->makeList($parentIDs);
       return $output;
       private function makeList($parentIDs) {
       $output = "";
       if(count($parentIDs)) {
          foreach($parentIDs as $parentID) {
             // Get the unique parents
             $parent = DataObject::get_by_id('Page', $parentID);
             // First level of the ul
             $output .= '<li class="newsTitle parent">' . '<a href="'.$parent->URLSegment.'" title="'. _t('SECTIONTITLE1', '') . convert::raw2xml($parent->Title). _t('SECTIONTITLE2', '') . '">' . Convert::raw2xml($parent->Title) . '</a>';
             // Then iterate through pages of this theme and class it by parent
             //Second level of the ul
             $output .= '<ul class="children">';
             foreach($this->Pages() as $page) {
                if($page->ParentID == $parentID){
                   $output .= '
                   <li class="newsTitle"><a href="'.$page->URLSegment.'" title="'. _t('PAGETITLE1', '') . convert::raw2xml($page->Title). _t('PAGETITLE2', '') . '">' . Convert::raw2xml($page->MenuTitle).'</a>';
                   $output .= '
             $output .= '</ul></li>';
       return $output;

    Getting the unique parent's ID, then using get_by_id with them to filter the pages of the ComponentSet by ParentID seems like an unnecessary long travel, isn't it? Also, I don't like the idea of mixing view and controller.

    If somebody brave enough to read till here could help me cleaning this mess I'd be deeply grateful.

    Best regards,

Page: 1
Go to Top

Want to know more about the company that brought you SilverStripe? Then check out SilverStripe.com

Comments on this website? Please give feedback.