How to render a view based on a layout?You will have noticed in the previous example using render() we had to define our entire page markup in a single view file for that page. This is fine when we only have a few pages but what do you do when you have hundreds of views in your application and need to change the markup of the header? You would need to go through and update potentially ALL of the view files in your application.
This was improved upon by DooView which had a renderLayout method added. This allowed you to specify a single layout file and within this layout you could define place holders. An example of this might be:
- Code: Select all
<html>
<head>
<title>Test Site</title>
</head>
<body>
<div id="header">
<!-- placeholder:header -->
<h1>Default Header</h1>
<!-- endplaceholder -->
</div>
<div id="content">
<!-- placeholder:content -->
<p>No content defined</p>
<!-- endplaceholder -->
</div>
<div id="footer">
<!-- placeholder:footer -->
<span>Copyright 2010</span>
<!-- endplaceholder -->
</div>
</body>
</html>
With the setup in DooView you could define several of these layout's each containing the provided placeholders you needed. If you then wanted to override any part of the place holder you could define blocks within your view file. For each placeholder in the layout a check would be made for that block within your view file and if found the placeholder would be replace with the compiled version of this view file. However you could not have templates being inherited. That means that if you had a sub section of the site with its own view file /support/x/y/z then any views in x, x/y and x/y/z would all need to have this change made in there views.
Therefore I have updated how layouts work in DooViewBasic with the main change here being inheritance support for placeholders.
To get started we must first define a layout.html file which outlines all the components which can be extended. To do this we will create the following file: /protected/view/layout.html and copy the following html into it:
- Code: Select all
<html>
<head>
<title>Test Site</title>
</head>
<body>
<div id="header">
<!-- placeholder:header -->
<h1>Default Header</h1>
<!-- endplaceholder -->
</div>
<div id="content">
<!-- placeholder:content -->
<p>No content defined</p>
<!-- endplaceholder -->
</div>
<div id="footer">
<!-- placeholder:footer -->
<span>Copyright 2010</span>
<!-- endplaceholder -->
</div>
</body>
</html>
Its important to note that the layout file must always be in the root of the active view root folder (in this case protected/view/) or it will not be found / work.
Now we have defined our layout file it important to understand how DooViewBasic decides what to put into each placeholder.
In order to use DooViewBasics renderLayout you must parse it a view to be rendered in much the same way as you do for render. This might be "example" for example but unlike with render where we would have a file protected/view/example.html it should be a folder instead. So we might have the folder protected/view/example/
Within the views folder we can define a series of files. These files should be named in accordance with the placeholder names defined in our layout. In the example we are using the place holders are header, footer and content. Therefore the files should be header.html, footer.html and content.html.
However we do not have to place all of these in the folder /example/ as renderLayout will automatically attempt to find these files in the parent folders of the view so it would try in this case protected/view/example/header.html and then try protected/view/header.html. If it finds a file it will stop looking further up. It will then try the same for content and then footer trying protected/view/example/ and then protected/view/.
If it does find a suitable match it will swap out the placeholder for the contents of the .html file corresponding to the placeholder. If no match is found though it will replace the placeholder with the content within the placeholders definition within the layout.
The recursive searching means that child views can inherit not only the layouts view but further more each of its parents views with it always using the closest parent version. So if we had a view of "blog/post/view" we might want a different header for people looking at blog/post and blog/post/view so we could define the new header file in protected/view/blog/post/header.html and this would be used by both blog/post and blog/post/view.
To try this all out create some new view files as defined below
view/header.html
- Code: Select all
<h1>I am the main site title</ha>
view/index/content.html
- Code: Select all
<p>Welcome to the home page. No content has been written yet!</p>
view/blog/content.html
- Code: Select all
<p>This would be a blog listing</p>
<ul>
<li>Post 1</li>
<li>Post 2</li>
<li>Post 3</li>
</ul>
view/blog/post/header.html
- Code: Select all
<h1>Some Site Header : Viewing Blog Post</h1>
view/blog/post/content.html
- Code: Select all
<p>This is a blog post</p>
view/blog/post/comment/content.html
- Code: Select all
<p>Post a comment on this post</p>
view/blog/post/comment/footer.html
- Code: Select all
<span>Notice your data will be the property of example.com</span>
Now you have some views it times to call them. Rather than showing how to define a whole lot of routes and actions of a controller (example exist on doing this) I will just give you some examples of the render command you could try out.
- Code: Select all
class MainController extends DooController {
public function index() {
$data = array();
// uncomment 1 of these at a time
$this->view()->renderLayout('index', $data);
//$this->view()->renderLayout('blog', $data);
//$this->view()->renderLayout('blog/post', $data);
//$this->view()->renderLayout('blog/post/comment', $data);
}
}
Each of the views being loaded have full access to the $data array and additionally the layouts and views can all contain the template tags within them.
Hopefully all of this renderLayout stuff makes some sense. I will hopefully incorporate some of this into the To Doo List Manager tutorial when I have a chance to finish it off.
One finally note while I remember. Unlike with the render() method renderLayout does not check if ALL the various view files have changed since the view was last compiled. Therefore if you are busy coding you are better to use the force compile setting. You might also want to write a function you can call to clear your compiled view folder therefore forcing views to be recompiled again.
Note: code samples my not be 100% accurate.