SSbits - Home page
Site by Carbon Crayon
Submit a Post >

Tutorials - Big bits of code to help you do more

Making a hierarchy aware templating system

Something that has been bothering me when building larger sites with SilverStripe is that I often find myself creating new classes not to add functionality, but to just get a new template.

You can set separate templates for different actions manually but that's not what I want in this case, I want different templates for the same action on the same class.

After thinking about this for awhile I came up with a two part solution and the first part is to make the template choosing aware of the Sitetree hierarchy.

In order to get this to work I have sub classed ContentController with a class I call HierarchyController. This class only contains two methods, namely a __construct() method to kick start the parent and a method called getViewer which overrides the getViewer method of the Controller class.

The code in getViewer consists of the code from the parent method with my own code added at the end. The reason I copy the code from the parent is that I want to do the same processing it does first and then do my own. Since the parent method returns an SSViewer object with the templates already set it's too late for me to step in and make the needed changes (I think).

The Snippet

So the added code is as follows:

...
if ($this->dataRecord) {
	$hierarchyTemplate = $templates[0];
	$current = $this->dataRecord;
	while ($current->ParentID > 0) {
		$hierarchyTemplate = $current->ClassName.'_'.$hierarchyTemplate;
		array_unshift($templates, $hierarchyTemplate);
		$current = $current->Parent();
	}
}

The code above gets added just after

 

$templates = array_unique($templates); 

in the original getViewer method.

The Results

So what does this code do? Essentially it grabs the parent classes (hierarchy wise) of the current page and adds them to the template list with the current class last in the chain.

As an example, if you have a Page that is a sub page to another Page then the first template choice becomes Page_Page.ss. If you have page that's a sub page of a sub page it becomes Page_Page_Page.ss if all the pages are of the Page class. It then falls back to Page_Page.ss and after that Page.ss.

I want to hear from everyone here if you think this is a useful idea (I of course do :P). If anyone knows of a better way to implement this I would also really like to know. Also, what do you think about the fallback routine? Should it fall back to the base choice directly or walk it's way up the hierarchy like it's doing now?

The next part (which I haven't tackled yet) will be adding the ability to choose a custom template for a page in the CMS. If someone has already done this then please post it as a snippet!

Below is all the code for the HierarchyController. In order to use it, copy the code and put it in a file called HierarchyController.php in mysite/code. After that make sure that your Page_Controller extends HierarchyController and you should be good to go!

All the Code

class HierarchyController extends ContentController {
	
	public function __construct($dataRecord = null) {
		parent::__construct($dataRecord);
	}
		
	function getViewer($action) {
		// Hard-coded templates
		if($this->templates[$action]) {
			$templates = $this->templates[$action];
		}	else if($this->templates['index']) {
			$templates = $this->templates['index'];
		}	else if($this->template) {
			$templates = $this->template;
		} else {
			// Add action-specific templates for inheritance chain
			$parentClass = $this->class;
			if($action && $action != 'index') {
				$parentClass = $this->class;
				while($parentClass != "Controller") {
					$templates[] = strtok($parentClass,'_') . '_' . $action;
					$parentClass = get_parent_class($parentClass);
				}
			}
			// Add controller templates for inheritance chain
			$parentClass = $this->class;
			while($parentClass != "Controller") {
				$templates[] = strtok($parentClass,'_');
				$parentClass = get_parent_class($parentClass);
			}
			// remove duplicates
			$templates = array_unique($templates);
			if ($this->dataRecord) {
				$hierarchyTemplate = $templates[0];
				$current = $this->dataRecord;
				while ($current->ParentID > 0) {
					$hierarchyTemplate = $current->ClassName.'_'.$hierarchyTemplate;
					array_unshift($templates, $hierarchyTemplate);
					$current = $current->Parent();
				}
			}
		}
		return new SSViewer($templates);			
	}	
}
Marcus Dalgren avatar

Marcus Dalgren

Marcus is a web developer currently working at a small startup company called Overlay in Gothenburg, Sweden. He also does freelance work for small to medium sized businesses in the Gothenburg area.

No one has commented on this page yet.

Post a comment ...

You cannot post comments until you have logged in. Login Here.

Advertisement

Site of the Month

Find SSbits on

Top Contributers

Rank Avatar Name
1 article image Aram Balakjian
2 article image Daniel Hensby
3 article image Marcus Dalgren
4 article image Hamish Campbell
5 article image Ty Barho
6 article image njorndare
7 article image Martijn van Nieuwenhoven
8 article image Darren-Lee
9 article image Roman Schmid
10 article image Matt Clegg

View full leaderboard


Advertisement