A layout is basically a view (or collection of views) that wrap around controller specific content. They typically include the repeating parts of a website, such as the header, footer and navigation elements. I’ve written about them briefly in a previous post, but in this post, I will elaborate slightly.
This is the general approach I take when using views and layouts in Solar. This isn’t a CSS framework. This is just an approach to laying out files in such a way that they can be easily shared between various Solar applications.
Let’s start with a basic 2 colum site design where I have my site-wide navigation on the left, a header up on top, and the footer below. In the main column is the controller-specific content. Based on that information, I am going to create 6 individual layout files. That seems like a lot, but it will make more sense shortly.
The Files
The layout files are as follows:
- 2col-navleft.php
- _head.php
- _body.php
- _header.php
- _footer.php
- _nav.php
The main layout file is called 2col-navleft.php. It’s good to choose a descriptive name like this so you know what to expect from the layout. It has 2 columns and the navigation is on the left. This is also the name of the layout you specify in your Solar controllers. For example, your controller would have the following property:
protected $_layout_default = '2col-navleft';
Better yet, you might be using a “Base” controller that all your other controllers extend. In this way, all your child controllers will use the same layout by default. And, of course, you could change this at anytime. More about that later. For now, here is the contents of the main layout.
/**
* File: 2col-navleft.php
*/
<!DOCTYPE html PUBLIC "-W3CDTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<?php
// generate the <head>
include $this->template('_head.php');
// generate the <body>
include $this->template('_body.php')
?>
</html>
Nice and simple. You’ve got the doctype and the html block. Within the html block, you can see how to include other layout pieces, such as _head.php and _body.php.
Here is what _head.php looks like. As you can see, its purpose is to create the <head> tags and all the stuff in between.
/**
* File: _head.php
*/
<head>
<?php
// add meta tags
foreach ((array) $this->layout_head['meta'] as $val) {
$this->head()->addMeta($val);
}
// set the title
$this->head()->setTitle($this->layout_head['title']);
// set the uri base
$this->head()->setBase($this->layout_head['base']);
// add links
foreach ((array) $this->layout_head['link'] as $val) {
$this->head()->addLink($val);
}
// add baseline styles
$this->head()->addStyleBase("Vendor/styles/2col-navleft.css");
// additional baseline styles
foreach ((array) $this->layout_head['style'] as $val) {
$this->head()->addStyleBase($val);
}
// additional baseline scripts
foreach ((array) $this->layout_head['script'] as $val) {
$this->head()->addScriptBase($val);
}
// done!
echo $this->head()->fetch();
?>
</head>
This layout uses a nice view helper called Solar_View_Helper_Head ($this->head()…). This helper sets all the head elements and displays them in the correct order. A public property (layout_head) need to be set in order for this to work properly. The layout_head public property is an array.
The next file is _body.php. This file, as you can imagine, sets the content between the <body> tags. Here is what _body.php looks like:
/**
* File:_body.php
*/
<body>
<div id="wrap">
<div id="header">
<?php include $this->template('_header.php'); ?>
</div>
<div id="nav">
<?php include $this->template('_nav.php'); ?>
</div>
<div id="content">
<div id="main">
<?php echo $this->layout_content; ?>
</div>
</div>
<div id="footer">
<?php include $this->template('_footer.php'); ?>
</div>
</div>
</body>
Here, you can see several other includes that point to more “sub layouts”.
- The _header.php file simply displays the header piece of the page.
- The _nav.php displays the site-wide navigation.
- At the bottom is the _footer.php file which displays the footer.
- Finally, is the php statement which echos $this->layout_content. This is where the controller-specific content is displayed.
Of course, these are just the basic layouts you can use. You could add more layouts as you see fit. Things like an _auth.php layout, a _topnav.php layout, etc.
Vendor- and Application-specific Layouts
So, why break them into such small pieces? Well, for one, you could easily alter the overall structure of your site by using a different main layout (2col-navright.php or 2col-navtop.php). Or, you could implement a CSS framework such as the Stenhouse CSS Framework. Also, Solar enables a nice heirachy of includes that you can easily have a different _header.php and _nav.php layout for each vendor or even each application. Have a look at the following directory structure to help understand how that works. Let’s start the “include” folder.
include/
Vendor/
App/
Base/
Helper/
Layout/
2col-navleft.php
_body.php
_footer.php
_head.php
_header.php
_nav.php
Locale/
View/
Index/
Helper/
Layout/
_nav.php
Locale/
View/
Solar/
In this example, let’s assume that our Vendor_App_Base class extends Solar_Controller_Page. That class specifies the default layout as 2col-navleft.
<?php
class Vendo_App_Base extends Solar_Controller_Page {
protected $_layout_default = 'main';
// The array needed in the _head.php layout
public $layout_head = array(
'title' => null,
'base' => null,
'meta' => array(),
'link' => array(),
'style' => array(),
'script' => array(),
'object' => array(),
);
.
.
.
}
?>
Vendor_App_Index extends Vendor_App_Base.
<?php
class Vendor_App_Index extends Vendor_App_Base {
protected $_action_default = 'browse';
public function actionBrowse()
{
// layout_head defined in parent class
$this->layout_head['title'] = "Here is my happy site";
}
.
.
.
}
?>
By default, any class that extends Vendor_App_Base will use the specified default layout (2col-navleft.php) and all sub layouts. However, In Vendor_App_Index_Helper, we have another _nav.php layout. Whenever you request the index application, this application-specific navigation layout will be used instead of that in the base application. Solar doesn’t need any explicit instructions to do this. It just knows.
Interacting with the Layouts (and Views)
As I have mentioned before, both Solar views and layouts have access to public properties in your controller (and those it extends). In the above example, $this->layout_head is a public property, therefore, the layouts and views have access to it via $this->layout_head. Knowing this should help the _head.php layout make even more sense.
Wrapping Up
Views and layouts aren’t too complex. The best way to learn them is to try it all out. The other really important thing you would be wise to learn about are view helpers.