Jump to:

3447 Posts in 1032 Topics by 872 members

Template Questions

SilverStripe Forums » Template Questions » Nested control blocks

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

Page: 1
Go to End
Author Topic: 5195 Views
  • Romeo
    Avatar
    Community Member
    67 Posts

    Nested control blocks Link to this post

    I have a Links page which contains a list of Link objects each consisting of a Title, URL and Region. I want to display the links grouped by region. What I had in mind for this was to have a Control block backed by a Regions function in the LinkPage class which gives me the list of regions (in the order I want them), and within this a nested Control block listing the links for each region.

    <% control Regions %>
    <% control Links($region) %>
    #Do something here
    <% end_control %>
    <% end_control %>

    There are two problems here. Firstly, I can't work out how to grab the value I require within the Regions control block - it's just a string, from a string array, but I can't find any documentation which tells me how to get this value. Secondly, assuming I have got it, I don't believe I can pass it as a variable to the inner control block anyway - that's not allowed, is it?

    Which means, of course, that I'm doing it wrong...But how should I do this? It seems a simple enough requirement.

  • banal
    Avatar
    Community Member
    901 Posts

    Re: Nested control blocks Link to this post

    Hi

    To pass custom array-like structures to the template engine, you should usually use the DataObjectSet.
    And you're right about that variable ($region) in your template. That's not going to work.

    In cases like yours, I usually wrap all my data in a DataObjectSet. For your Regions it could look like this:

    // static definition of regions
    protected static $regionStrings = array('Region A', 'Region B', 'Region C');

    public function Regions(){
       $regions = array();
       foreach(self::$regionStrings as $str){
          $regions[] = array(
             'RegionTitle' => $str,
             'RegionLinks' => $this->Links($str)
          );
       }
       
       return new DataObjectSet($regions);
    }

    The above code simply walks through the regions (which are defined as static array) and adds the String from the Array as "RegionTitle" and the links as "RegionLinks" to an array, which is then returned as DataObjectSet.
    Of course, you'll also have to implement the Links method, so that it takes a string as argument and returns the desired collection of links.
    This could look like this:

    public function Links($region){
       // check if region is one of the defined regions,
       // otherwise return false
       if(!in_array($region, self::$regionStrings))
          return false;
          
       // be sure to replace 'LinkClass' with the actual class
       // name of your Link DataObject. "Region = has to be replaced
       // with the name of the region field you would like to check
       // for a match.
       return DataObject::get('LinkClass', "Region = '$region'");
    }

    In the template, you can then write something along these lines:

    <% control Regions %>
       <h2>$RegionTitle</h2>
       <% control RegionLinks %>
          <a href="$LinkUrl">$LinkTitle</a>
       <% end_control %>
    <% end_control %>

    The RegionTitle and RegionLinks variables are coming from the DataObjectSet that we built in the "Regions" function. If everything went fine, you should be able to access your Link-DataObject within the "RegionLinks" control block. I assumed the members of the Link class are named $LinkUrl and $LinkTitle, this could be different of course.

    Edit: spelling

  • Romeo
    Avatar
    Community Member
    67 Posts

    Re: Nested control blocks Link to this post

    Fantastic, thanks! I'll give it a go and report back.

  • Romeo
    Avatar
    Community Member
    67 Posts

    Re: Nested control blocks Link to this post

    Yes, it works a treat! Thanks ever so much. I'm hoping all of this will come much more easily to me soon. It's all slightly frustrating for me because I'm an experienced Java guy, used to knowing exactly how to do what I want to do with web applications in Java, but I'm new to PHP. Still, a lot of it is similar and I feel I'm making good progress.

  • blueskies
    Avatar
    Community Member
    42 Posts

    Re: Nested control blocks Link to this post

    Thank you! This was exactly what I was looking for

  • Xurk
    Avatar
    Community Member
    50 Posts

    Re: Nested control blocks Link to this post

    Thanks a lot for your detailed post, banal It really opened my eyes as to how to manipulate data from inside a control, without having to attempt to nest another control. Pointed me in the right direction with instant success!

  • Xurk
    Avatar
    Community Member
    50 Posts

    Re: Nested control blocks Link to this post

    Hmm, now that I'm actually trying to apply this example to a DataObject which has a nested DataObject inside it, I can't manage to get to the finish line. I'm stuck on the final lap, I think

    I've got the call to another function (QuestionAuthor) setting the value of a property in the DataObject being returned and it looks like this:

    function LatestQuestions($iNum = 10) {
       $oQuestions = DataObject::get("Question", "", "Created DESC", "", $iNum);

       foreach ($oQuestions as $oQuestion => $data) {
          $data->Author = array($this->QuestionAuthor($data->Author));
          $data->Answers = $this->NumAnswers($data->ID);
       }

       return $oQuestions;
    }


    function QuestionAuthor($iAuthorID) {
       $oAuthor = DataObject::get_by_id("Member", (int) $iAuthorID);

       $dsoAuthor = new DataObjectSet();
       $dsoAuthor->push(new DataObject(array(
          'Avatar' => $oAuthor->data()->AvatarPath,
          'Name' => $oAuthor->data()->FirstName." ".$oAuthor->data()->Surname,
          'Occupation' => $oAuthor->data()->Occupation
       )));

       return $dsoAuthor;
    }

    And then this is what I have in my template:

    <ul id="questionsList">
    <% control LatestQuestions(5) %>
       <li>
          <div class="author">
          <% control Author %>
             <img src="$Avatar" width="35" height="35" alt="" />
             <p>
                <span class="name">$Name</span><br />
                <span class="title">$Occupation</span>
             </p>
          <% end_control %>
          </div>

          <p class="question">
             <a href="questions/$ID/$Title" class="title">$Title</a><br />
             <span>posted on $Created.format(d F Y) ($Answers responses)</span>
          </p>

          <a href="questions/$ID/$Title#AnswerForm" class="button">respond &raquo;</a>
       </li>
    <% end_control %>
    </ul>


    So what my problem is, is that I can't seem to access the variables set inside the nested control ($Name, $Occupation and $Avatar). I've been var_dump'ing the complete DataObjectSet returned by the parent control and everything seems to be in place (here is an excerpt with some irrelevant stuff filtered out for readability):

    object(DataObjectSet)#70 (16) {
       array(5) {
          [0]=>
          object(Question)#71 (15) {
             array(11) {
                ["ClassName"]=> string(8) "Question"
                ["Created"]=> string(19) "2010-06-18 14:22:35"
                ["LastEdited"]=> string(19) "2010-06-18 14:22:35"
                ["Title"]=> string(12) "A test entry"
                ["Author"]=> array(1) {
                   [0]=>
                   object(DataObject)#79 (15) {
                      array(3) {
                         ["Avatar"]=> string(32) "assets/Uploads/av/testavatar.jpg"
                         ["Name"]=> string(20) "Lonneke Ceelie"
                         ["Occupation"]=> string(12) "Editor"
                      }
                   }
                }
                ["Content"]=> string(50) "Lorem ipsum test test test"
                ["QuestionHolderID"]=> string(2) "30"
                ["DocumentID"]=> string(1) "0"
                ["ID"]=> int(6)
                ["RecordClassName"]=> string(8) "Question"
                ["Answers"]=> int(5)
             }
          }
       }
    }

    Yet in my nested control, I can't seem to access the three variables I want to. I've tried a few different things, like the second function returning (instead of a DataObject as above) a plain Array, an ArrayData object and a DataObjectSet, but the results are similar to the above each time. I also tried i.e. $Author.Occupation in the nested control, but that accomplishes nothing either.

    The only time I can get anything to print onscreen is if I remove the <% control Author %> and replace it with $Author, which prints out "Array" onscreen for me.

    Am I missing something completely obvious here? Any pointers would be much appreciated

  • inCharge
    Avatar
    Community Member
    102 Posts

    Re: Nested control blocks Link to this post

    Maybe you need to use Top.RegionLinks to put it into the parent context.

    For a full explanation see http://silverstripe.org/template-questions/show/287958#post287958

    5195 Views
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.