Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

We've moved the forum!

Please use forum.silverstripe.org for any new questions (announcement).
The forum archive will stick around, but will be read only.

You can also use our Slack channel or StackOverflow to ask for help.
Check out our community overview for more options to contribute.

Template Questions /

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

Traverse All Parents of a Page and Exiting A Control Loop


Go to End


6 Posts   5218 Views

Avatar
craigcordell

Community Member, 6 Posts

5 May 2010 at 12:21pm

My apologies if this has already been covered. Spent several hours searching but not finding a solution so...

Two part question...

One - Is it possible to upwardly traverse all parents of page in a control block? For example to add all sidebar widgets from each parent...

<% control Parents %>
$Sidebar
<% end_control %>

Two - Can you exit a control if a condition is met? Example - traverse parents until we find a sidebar then display...

<% control Parents %>
$Sidebar
<% if Sidebar %>
[[[ exit the control loop ]]]
<% end_if %>
<% end_control %>

Thanks in advance for any help you may have. First project using SS but thoroughly impressed so far.

Avatar
Willr

Forum Moderator, 5523 Posts

6 May 2010 at 11:14pm

Hi,

No this is not possible, Only ways to go back up the tree is to use Parent which is 1, Nested Parents like Parent.Parent or use Top (which is the topmost parent). If you want to traverse back up the tree then you'll need to do that in PHP and while a while loop kinda like

// mysite/code/Page.php

function ParentSidebar() {
$parent = $this->Parent();

while($parent && $parent->exists()) {

// do your check


$parent = $this->Parent(); 
}
}

Then you can use $ParentSidebar() in the template

Avatar
Willr

Forum Moderator, 5523 Posts

6 May 2010 at 11:14pm

Hi,

No this is not possible, Only ways to go back up the tree is to use Parent which is 1, Nested Parents like Parent.Parent or use Top (which is the topmost parent). If you want to traverse back up the tree then you'll need to do that in PHP and while a while loop kinda like

// mysite/code/Page.php

function ParentSidebar() {
$parent = $this->Parent();

while($parent && $parent->exists()) {

// do your check


$parent = $this->Parent(); 
}
}

Then you can use $ParentSidebar() in the template

Avatar
craigcordell

Community Member, 6 Posts

8 May 2010 at 11:50am

Thanks for the quick reply. Based on the number of posts that you have, I see you are a busy guy. I appreciate you taking the time to respond.

The code above does have a typo - $this->Parent() should be $parent->Parent() right? Original will just loop.

So based on your code I created a new method in my page model like so...

function Parents( )
{
$parent = $this->Parent();

$output = new DataObjectSet();

while( $parent && $parent->exists() )
{
$output->push( $parent );
$parent = $parent->Parent();
}

return $output;
}

Then in my template file...

<% if Sidebar.Items %>
$Sidebar
<% else %>
<% control Parents %>
<% if Sidebar.Items %>
$Sidebar
<% end_if %>
<% end_control %>
<% end_if %>

It works great. Now I just need a way to break out of a control block if a condition is met. Any way to do that?

If not is there a way to extend the template parser without modifying the source? Could see this being useful for lots of other situations.

Also, is there a way to extend whatever class handles Parents()? Would like to create some generic methods for traversing hierarchical data like Siblings, ParentsUntil, Closest, etc. Use a lot of jQuery so its nice to have a way to move around a selection.

Thanks again. Look forward to your reply.

Avatar
craigcordell

Community Member, 6 Posts

18 May 2010 at 3:35pm

Still have not found a way to break out of a control loop based on a condition so to resolve this issue I placed the following method in Page.php ...

function FirstParentMatching( $field, $value = NULL )
{
$parent = $this->Parent();

$output = new DataObjectSet();

while( $parent && $parent->exists() && !$output->items )
{

$fieldID = $field . 'ID';

if ( $value == NULL && ( $parent->$field || $parent->$fieldID ) )
{
$output->push( $parent );
}
else if ( $value != NULL && ( $parent->$field == $value || $parent->$fieldID == $value ) )
{
$output->push( $parent );
}

$parent = $parent->Parent();
}

return $output;
}

This will step through the current page and its parents to see if a variable has any value or a specific value. Have not fully tested the specific value but should be fine. I'm using this to step through each page's parents to find the first one with a widget.

Here is my template code...

<% if Sidebar.Items %>
$Sidebar
<% else %>
<% control FirstParentMatching(Sidebar) %>
$Sidebar
<% end_control %>
<% end_if %>

Note that in this instance we are looking for a parent page with a SiderbarID value. Method will return a DataObjectSet one record.

Avatar
craigcordell

Community Member, 6 Posts

18 May 2010 at 4:02pm

Also, in my current project I have pages that are siblings of the homepage. The template code above does not accommodate. I want to use the sidebar widgets for the homepage if the current page (a sibling of home) does not have any specified. So we use ...

<% if Sidebar.Items %>
$Sidebar
<% else_if Parent %>
<% control FirstParentMatching(Sidebar) %>
$Sidebar
<% end_control %>
<% else %>
<% control Page(Home) %>
$Sidebar
<% end_control %>
<% end_if %>