Page_Controller and <% control %>

Enable Page_Controller fuctions from a <% control %> loop

Quite often we run into the problem that within a <% control %> loop all Page_Controller methods are unavailable. At first this might seem like some defect - but it isn't really. The current Page_Controller controls the page's output, so it's methods can be used, but once we enter a control we're loopingh DataObjectSets, and DataObjectSets contain DataObjects - and not controllers!

And thats just the same in looping pages: controls like <% control Children %> or <% control Menu(1) %> are fed with Page DataObjects, not Page_Controllers. And the Page class knows nothing of the Page_Controller class!

One way to overcome this, is moving the necessary Page_Controller methods to the Page class. Fortunately the Page_Controller can always access functions within the Page class, so no duplicate code necessary. However - once your methods depend on other functions/prperties/data that are specific to the page controller, this is not an option..

Case study

This came up when encountering this post on the SilverStripe Forums. A way to re-use pagetype-specific layout within a pageholder overview: an overview consisting of different pages, each with their specific layout. This could easily be done using something like this:

<% control Children %>
    <% if ClassName = PageType1 %>
        <% include Layout1 %>
    <% elseif ClassName = PageType2 %>
        <% include Layout2 %>
    <% end_if %>
<% end_control %>

...and then use the same included templates for rendering the individual pages themselves. Unfortunately this will only work if the templates don't need to access Page_Controller functions. The following solution offers a way outinĀ  allowing the use of Page_Controller functions from within a control.

Solution

1. A couple of templates...

create an include template for each different pagetype that is used for rendering its content within the holder page.

2. Page and Page_Controller

Create the functions: one in the Page class, that you can call from within a control loop, and one in the Page_Controller that actually renders the templates.

class Page extends Page_Controller {
    ...

    function RenderAsChild() {
        $class = $this->ClassName . "_Controller";
        $controller = new $class($this);
        return $controller->renderForHolderPage();
    }
}

class Page_Controller extends ContentController {
    ...
    public static $layout_template = 'PageLayout';

    function renderForHolderPage() {
        $template = $this->stat('LayoutTemplate');
        if ($template) return $this->renderWith(array($template));
        else return '';
    }
}
  • renderForHolderPage() - this is the bit you normally cannot reach: the function that actually renders the childpage content for display on the holderpage.
  • $layout_template - the template that this controller will use to render its content for the HolderPage. Can be different for every pagetype...
  • renderAsChild() - this one can be called from within the control loop. It instantiates a Page_Controller for the childpage and then calls its renderForHolderPage() method.

The renderForHolderPage in turn has access to all controller functions, so that covers about everything!

3. The actual control loop in the HolderPage template

Now in your HolderPage.ss template, it's really simple:

<% control Children %>
    $RenderAsChild
<% end_control %>

So there it is. I might never use it, and it might be high on resources, but it was a nice puzzle anyway :-)

Comments

Het versturen van reacties is uitgeschakeld.

RSS feed voor reacties op deze pagina