5.9 Views
5.9.1 View Templates
The view layer of CakePHP is how you speak to your users. Most of the time your views will be showing (X)HTML documents to browsers, but you might also need to serve AMF data to a Flash object, reply to a remote application via SOAP, or output a CSV file for a user.
CakePHP view files are written in plain ‘ol PHP and have a default extension of .ctp (CakePHP Template). These files contain all the presentational logic needed to get the data it received from the controller in a format that is ready for the audience you’re serving to.
View files are stored in /app/views/, in a folder named after the controller that uses the files, and named after the view it corresponds to. For example, The view() action of the Products controller would normally be found in /app/views/products/view.ctp.
The view layer in CakePHP can be made up of a number of different parts. Each part has different uses, and will be covered in this chapter:
- layouts: view files that contain presentational code that is found wrapping many interfaces in your application. Most views are rendered inside of a layout.
- elements: smaller, reusable bits of view code. Elements are usually rendered inside of views.
- helpers: these classes encapsulate view logic that is needed in many places in the view layer. Among other things, helpers in CakePHP can help you build forms, build AJAX functionality, paginate model data, or serve RSS feeds.
5.9.2 Layouts
A layout contains presentation code that wraps around a view. Anything you want to see in all of your views should be placed in a layout.
Layout files should be placed in /app/views/layouts. CakePHP's default layout can be overridden by creating a new default layout at /app/views/layouts/default.ctp. Once a new default layout has been created, controller-rendered view code is placed inside of the default layout when the page is rendered.
When you create a layout, you need to tell CakePHP where to place the code for your views. To do so, make sure your layout includes a place for $content_for_layout (and optionally, $title_for_layout). Here's an example of what a default layout might look like:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title><?php echo $title_for_layout?></title>
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<!-- Include external files and scripts here (See HTML helper for more info.) -->
<?php echo $scripts_for_layout ?>
</head>
<body>
<!-- If you'd like some sort of menu to
show up on all of your views, include it here -->
<div id="header">
<div id="menu">...</div>
</div>
<!-- Here's where I want my views to be displayed -->
<?php echo $content_for_layout ?>
<!-- Add a footer to each displayed page -->
<div id="footer">...</div>
</body>
</html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title><?php echo $title_for_layout?></title><link rel="shortcut icon" href="favicon.ico" type="image/x-icon"><!-- Include external files and scripts here (See HTML helper for more info.) --><?php echo $scripts_for_layout ?></head><body><!-- If you'd like some sort of menu toshow up on all of your views, include it here --><div id="header"><div id="menu">...</div></div><!-- Here's where I want my views to be displayed --><?php echo $content_for_layout ?><!-- Add a footer to each displayed page --><div id="footer">...</div></body></html>
$scripts_for_layout contains any external files and scripts included with the built-in HTML helper. Useful for including javascript and CSS files from views.
When using $html->css() or $javascript->link() in view files, specify 'false' for the 'in-line' argument to place the html source in $scripts_for_layout. (See API for more details on usage).
$content_for_layout contains the view. This is where the view code will be placed.
$title_for_layout contains the page title.
To set the title for the layout, it's easiest to do so in the controller, using the $pageTitle controller variable.
<?php
class UsersController extends AppController {
function viewActive() {
$this->pageTitle = 'View Active Users';
}
}
?>
<?phpclass UsersController extends AppController {function viewActive() {$this->pageTitle = 'View Active Users';}}?>
You can create as many layouts as you wish: just place them in the app/views/layouts directory, and switch between them inside of your controller actions using the controller's $layout variable, or setLayout() function.
For example, if a section of my site included a smaller ad banner space, I might create a new layout with the smaller advertising space and specify it as the layout for all controller's actions using something like:
var $layout = 'default_small_ad';
<?php
class UsersController extends AppController {
function viewActive() {
$this->pageTitle = 'View Active Users';
$this->layout = 'default_small_ad';
}
function viewImage() {
$this->layout = 'image';
//output user image
}
}
?>
<?phpclass UsersController extends AppController {function viewActive() {$this->pageTitle = 'View Active Users';$this->layout = 'default_small_ad';}function viewImage() {$this->layout = 'image';//output user image}}?>
CakePHP features two core layouts (besides CakePHP’s default layout) you can use in your own application: ‘ajax’ and ‘flash’. The Ajax layout is handy for crafting Ajax responses - it’s an empty layout (most ajax calls only require a bit of markup in return, rather than a fully-rendered interface). The flash layout is used for messages shown by the controllers flash() method.
Three other layouts–xml, js, and rss–exist in the core for a quick and easy way to serve up content that isn’t text/html.
5.9.3 Elements
Many applications have small blocks of presentation code that needs to be repeated from page to page, sometimes in different places in the layout. CakePHP can help you repeat parts of your website that need to be reused. These reusable parts are called Elements. Ads, help boxes, navigational controls, extra menus, login forms, and callouts are often implemented in CakePHP as elements. An element is basically a mini-view that can be included in other views, in layouts, and even within other elements. Elements can be used to make a view more readable, placing the rendering of repeating elements in its own file. They can also help you re-use content fragments in your application.
Elements live in the /app/views/elements/ folder, and have the .ctp filename extension. They are output using the element method of the view.
<?php echo $this->element('helpbox'); ?> <?php echo $this->element('helpbox'); ?>
5.9.3.1 Passing Variables into an Element
You can set variables for your elements by passing them as parameters to the element.
<?php echo
$this->element('helpbox',
array("helptext" => "Oh, this text is very helpful."));
?>
<?php echo$this->element('helpbox',array("helptext" => "Oh, this text is very helpful."));?>
Inside the Element file, all the passed variables are available as the names of the keys of the passed array (much like how set() in the controller works with view files). In the above example, the /app/views/elements/helpbox.ctp file can use the $helptext variable.
One way to take full advantage of elements is by using requestAction(). The requestAction() function fetches view variables from a controller action and returns them as an array. This allows your elements to perform in true MVC style. Create a controller action that prepares the view variables for your elements, and call requestAction() inside the second parameter of element() to feed the element the view variables from your controller.
To do this, in your controller add something like the following for the Post example.
<?php
class PostsController extends AppController {
...
function index() {
$posts = $this->paginate();
if (isset($this->params['requested'])) {
return $posts;
} else {
$this->set(compact('posts'));
}
}
}
?>
<?phpclass PostsController extends AppController {...function index() {$posts = $this->paginate();if (isset($this->params['requested'])) {return $posts;} else {$this->set(compact('posts'));}}}?>
And then in the element we can access the paginated posts model. To get the latest five posts in an ordered list we would do something like the following:
<h2>Latest Posts</h2>
<?php $posts = $this->requestAction('posts/index/sort:created/order:asc/limit:5'); ?>
<ol>
<li><?php echo $posts['Post']['title']; ?>;</li>
</ol>
<h2>Latest Posts</h2><?php $posts = $this->requestAction('posts/index/sort:created/order:asc/limit:5'); ?><ol><li><?php echo $posts['Post']['title']; ?>;</li></ol>
5.9.3.2 Caching Elements
You can take advantage of CakePHP view caching if you supply a cache parameter. If set to true, it will cache for 1 day. Otherwise, you can set alternative expiration times. See Caching for more information on setting expiration.
<?php echo $this->element('helpbox', array('cache' => true)); ?>
<?php echo $this->element('helpbox', array('cache' => true)); ?>
5.9.3.3 Requesting Elements from a Plugin
If you are using a plugin and wish to use elements from within the plugin, just specify the plugin parameter. If the view is being rendered for a plugin controller/action, it will automatically point to the element for the plugin. If the element doesn't exist in the plugin, it will look in the main APP folder.
<?php echo $this->element('helpbox', array('plugin' => 'pluginname')); ?> <?php echo $this->element('helpbox', array('plugin' => 'pluginname')); ?>
5.9.4 Themes
You can take advantage of themes, making it easy to switch the look and feel of your page quickly and easily.
To use themes, you need to tell your controller to use the ThemeView class instead of the default View class.
class ExampleController extends AppController {
var $view = 'Theme';
}
class ExampleController extends AppController {var $view = 'Theme';}
To declare which theme to use by default, specify the theme name in your controller.
var $theme = 'example';
var $theme = 'example';
You can also set or change the theme name within an action or within the beforeFilter or beforeRender callback functions.
$this->theme = 'another_example';
$this->theme = 'another_example';
Theme view files need to be within the /app/views/themed/ folder. Within the themed folder, create a folder using the same name as your theme name. Beyond that, the folder structure within the /app/views/themed/example/ folder is exactly the same as /app/views/.
For example, the view file for an edit action of a Posts controller would reside at /app/views/themed/example/posts/edit.ctp. Layout files would reside in /app/views/themed/example/layouts/.
If a view file can't be found in the theme, CakePHP will try to locate the view file in the /app/views/ folder. This way, you can create master view files and simply override them on a case-by-case basis within your theme folder.
If you have CSS or JavaScript files that are specific to your theme, you can store them in a themed folder within webroot. For example, your stylesheets would be stored in /app/webroot/themed/example/css/ and your JavaScript files would be stored in /app/webroot/themed/example/js/.
All of CakePHP's built-in helpers are aware of themes and will create the correct paths automatically. Like view files, if a file isn't in the theme folder, it'll default to the main webroot folder.
5.9.5 Media Views
Media views allow you to send binary files to the user. For example, you may wish to have a directory of files outside of the webroot to prevent users from direct linking them. You can use the Media view to pull the file from a special folder within /app/, allowing you to perform authentication before delivering the file to the user.
To use the Media view, you need to tell your controller to use the MediaView class instead of the default View class. After that, just pass in additional parameters to specify where your file is located.
class ExampleController extends AppController {
function download () {
$this->view = 'Media';
$params = array(
'id' => 'example.zip',
'name' => 'example',
'download' => true,
'extension' => 'zip',
'path' => 'files' . DS
);
$this->set($params);
}
}
class ExampleController extends AppController {function download () {$this->view = 'Media';$params = array('id' => 'example.zip','name' => 'example','download' => true,'extension' => 'zip','path' => 'files' . DS);$this->set($params);}}
| Parameters | Description |
|---|---|
| id | The ID is the file name as it resides on the file server including the file extension. |
| name | The name allows you to specify an alternate file name to be sent to the user. Specify the name without the file extension. |
| download | A boolean value indicating whether headers should be set to force download. |
| extension | The file extension. This is matched against an internal list of acceptable mime types. If the mime type specified is not in the list, the file will not be downloaded. |
| path | The folder name, including the final directory separator. The path is relative to the APP folder. |
