3.9 Views

3.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 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 action it corresponds to. For example, the view file for the Products controller's "view()" action, 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.

3.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>
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  2. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  3. <html xmlns="http://www.w3.org/1999/xhtml">
  4. <head>
  5. <title><?php echo $title_for_layout?></title>
  6. <link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
  7. <!-- Include external files and scripts here (See HTML helper for more info.) -->
  8. <?php echo $scripts_for_layout ?>
  9. </head>
  10. <body>
  11. <!-- If you'd like some sort of menu to
  12. show up on all of your views, include it here -->
  13. <div id="header">
  14. <div id="menu">...</div>
  15. </div>
  16. <!-- Here's where I want my views to be displayed -->
  17. <?php echo $content_for_layout ?>
  18.  
  19. <!-- Add a footer to each displayed page -->
  20. <div id="footer">...</div>
  21. </body>
  22. </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';
    }
}
?>
  1. <?php
  2. class UsersController extends AppController {
  3. function viewActive() {
  4. $this->pageTitle = 'View Active Users';
  5. }
  6. }
  7. ?>

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
    }
}
?>
  1. <?php
  2. class UsersController extends AppController {
  3. function viewActive() {
  4. $this->pageTitle = 'View Active Users';
  5. $this->layout = 'default_small_ad';
  6. }
  7. function viewImage() {
  8. $this->layout = 'image';
  9. //output user image
  10. }
  11. }
  12. ?>

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.

3.9.3 Elements

Hodně aplikací obsahuje malé bloky prezentačního kódu, které jsou používány na více stránkách, někdy i na více místech v layoutu. CakePHP umožňuje definovat části stránek, které lze potom znovupoužít. Tyto části se nazývají Elementy. Reklama, boxy s nápovědou, navigace, různá menu, přihlašovací formuláře a popisky k obrázkům jsou v CakePHP obvykle realizovány pomocí elementů. Element je de facto mini-view, který může být volán z jiného view, layoutu a dokonce i z jiných elementů. Element může být použít i jako zpřehlednění view, tím, že umístíme opakující se části do jejich vlastních souborů. Můžou také pomoci ke znovupoužití obsahu v aplikaci.

Elementy jsou v adresáři /app/views/elements/, mají příponu .ctp. Používají se pomocí metody element ve view

<?php echo $this->element('helpbox'); ?>
  1. <?php echo $this->element('helpbox'); ?>

3.9.3.1 Passing Variables into an Element

You can pass data to the element through the second argument

<?php echo
$this->element('helpbox', 
    array("helptext" => "Oh, this text is very helpful."));
?>
  1. <?php echo
  2. $this->element('helpbox',
  3. array("helptext" => "Oh, this text is very helpful."));
  4. ?>

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.

<?php
echo $helptext; //outputs "Oh, this text is very helpful."
?>
  1. <?php
  2. echo $helptext; //outputs "Oh, this text is very helpful."
  3. ?>

The element() function combines options for the element with the data for the element to pass. The two options are 'cache' and 'plugin'. An example:

<?php echo
$this->element('helpbox', 
    array(
        "helptext" => "This is passed to the element as $helptext"
        "foobar" => "This is passed to the element as $foobar"
        "cache" => "+2 days" //sets the caching to +2 days.
        "plugin" => "" //to render an element from a plugin
    )
);
?>
  1. <?php echo
  2. $this->element('helpbox',
  3. array(
  4. "helptext" => "This is passed to the element as $helptext"
  5. "foobar" => "This is passed to the element as $foobar"
  6. "cache" => "+2 days" //sets the caching to +2 days.
  7. "plugin" => "" //to render an element from a plugin
  8. )
  9. );
  10. ?>

"cache" can also be set to an array, with the format array('cache' => value, 'key' => value)

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'));
        }
    }
}
?>
  1. <?php
  2. class PostsController extends AppController {
  3. ...
  4. function index() {
  5. $posts = $this->paginate();
  6. if (isset($this->params['requested'])) {
  7. return $posts;
  8. } else {
  9. $this->set(compact('posts'));
  10. }
  11. }
  12. }
  13. ?>

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'); ?>
<?php foreach($posts as $post): ?>
<ol>
    <li><?php echo $post['Post']['title']; ?>;</li>
</ol>
<?php endforeach; ?>
  1. <h2>Latest Posts</h2>
  2. <?php $posts = $this->requestAction('posts/index/sort:created/order:asc/limit:5'); ?>
  3. <?php foreach($posts as $post): ?>
  4. <ol>
  5. <li><?php echo $post['Post']['title']; ?>;</li>
  6. </ol>
  7. <?php endforeach; ?>

3.9.3.2 Kešování elementů

Pomocí kešovacího parametru můžete kešovat view. Pokud je nastaven na true, keš vyexpiruje za 1 den. Můžete ale nastavit jinou expiraci. Více o nastavení expirace naleznete v kapitole Kešování.

<?php echo $this->element('helpbox', array('cache' => true)); ?>
  1. <?php echo $this->element('helpbox', array('cache' => true)); ?>

3.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')); ?>
  1. <?php echo $this->element('helpbox', array('plugin' => 'pluginname')); ?>

3.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';
}
  1. class ExampleController extends AppController {
  2. var $view = 'Theme';
  3. }

To declare which theme to use by default, specify the theme name in your controller.

var $theme = 'example';
  1. 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';
  1. $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.

3.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);
    }
}
  1. class ExampleController extends AppController {
  2. function download () {
  3. $this->view = 'Media';
  4. $params = array(
  5. 'id' => 'example.zip',
  6. 'name' => 'example',
  7. 'download' => true,
  8. 'extension' => 'zip',
  9. 'path' => 'files' . DS
  10. );
  11. $this->set($params);
  12. }
  13. }
ParametersDescription
idThe ID is the file name as it resides on the file server including the file extension.
nameThe name allows you to specify an alternate file name to be sent to the user. Specify the name without the file extension.
downloadA boolean value indicating whether headers should be set to force download.
extensionThe 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.
pathThe folder name, including the final directory separator. The path is relative to the APP folder.