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.

General Questions /

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

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

Clarification of inheritance, please


Go to End


7 Posts   1587 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, 5523 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.