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.

General Questions /

General questions about getting started with SilverStripe that don't fit in any of the categories above.

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

Clarification of inheritance, please


Reply


7 Posts   1140 Views

Avatar
Romeo

Community Member, 67 Posts

4 December 2009 at 5:07am

Something didn't work just now which I thought would, which suggests my understanding of the way inheritance works in Silverstripe is slightly flawed. I'm hoping someone can clarify things for me.

I have, as usual, a Page.php. I also have a ChildPage.php which extends that. In my themes directory, I have templates called Page.ss and ChildPage.ss, which behave exactly as they should. I also have a PHP class called StudentsPage, which extends ChildPage. My expectation was that unless I created a matching template file called StudentsPage.ss, it would default to using the parent template file, namely ChildPage.ss. But it doesn't, it uses Page.ss, skipping a generation. This is puzzling to me. It's not hugely problematic, because if I do create a file called StudentsPage.ss, it does use it. It doesn't go well with the Don't Repeat Yourself philosophy, though, as it is fundamentally the same as ChildPage.ss.

What have I misunderstood here? This is Silverstripe 2.3.4.

Avatar
Willr

Forum Moderator, 5513 Posts

4 December 2009 at 9:35am

I believe this is just a limitation with the SSViewer. AFAIK How it works is it looks for a template with the same classname, if it can't find one then it defaults to page. It doesn't take any inheritance / class structure into account. You could customize the rendering of StudentPage by supplying a custom renderWith('ChildPage').

Avatar
Sean

Forum Moderator, 922 Posts

4 December 2009 at 9:48am

Edited: 04/12/2009 9:53am

SilverStripe should have gone through the template stack, going up until it finds a template to render with. Perhaps this is a bug, as I'd expect it to work the way you want it.

Avatar
Romeo

Community Member, 67 Posts

4 December 2009 at 10:00am

Thanks, Willr and Sean. At least if it is a bug, I can presumably get around the consequences of it Willr's way.

Avatar
Romeo

Community Member, 67 Posts

5 December 2009 at 2:57am

I just created a little SS website purely to test this out, and I can confirm that in the case of a class hierarchy more than 2 levels deep, SilverStripe doesn't go up the template stack until it finds a template to render with, it goes straight to the Page template. At least, as structured in my little site it does. Just to make this clearer:

I have 3 classes - the standard Page.php; ChildPage.php which extends Page.php; and GrandChildPage.php which extends ChildPage.php.

In my templates, I have the standard Page.ss at the top level, and within the Layout directory, the standard Page.ss and also ChildPage.ss.

When I display a ChildPage record, it is automatically rendered with the Layout/ChildPage.ss template. When I display a GrandChildPage record, though, it is not rendered with Layout/ChildPage.ss, despite it being a subclass of ChildPage, but is rendered instead with Layout/Page.ss. This definitely doesn't strike me as what it should do.

I said I could get round the consequences of this by using renderWith, but I'm evidently not using it right. In my GrandChildPage_Controller class, I tried adding this:

   function Index(){
      return $this->renderWith("ChildPage");
   }

It does indeed render it with ChildPage.ss, but ONLY with ChildPage.ss. That is, it just renders the page fragment ChildPage.ss, not the whole page as rendered by Page.ss with $Layout being rendered by ChildPage.ss, which is of course what I want. How do I force this to happen?

Avatar
dalesaurus

Community Member, 283 Posts

5 December 2009 at 4:33am

renderWith() only invokes the specific template you sent to it, and doesn't traverse up the regular Layout paths. Currently in 2.3 you are limited to the Page/Layout method of 2 levels. Templates don't inherit along side subclasses as they are selected by where you are generating content for, not by a hierarchical "Who's your daddy".

You can probably force it to render with your templates manually by mimicking the way SSViewer processes templates in your controller.

public function index() {
   foreach(array('GrandChildPage','ChildPage') as $template) {
      $subtemplateViewer = new SSViewer($template);
      $this->customise(array(
         $template => $subtemplateViewer->process($this)
      ));
   }
   return $this->renderWith('Page');

Check out SSViewer.php, Line 303 for more meat. I'm not 100% sure this will work but if you need a custom rendering solution beyond the Layout method you're going to have to do something like this.

Perhaps you could rethink your layout to use the 2 level system or create a new template with everything from your Page and ChildPage (html to /html) and use renderWith() on that. Its dirty but it works.

Avatar
Romeo

Community Member, 67 Posts

5 December 2009 at 7:20am

Thanks, that's very helpful and it does clarify things. It's not a huge problem and I can certainly work around it. I was just wanting to be clear about how it should work.