Views, Templates, and Layouts

Bullet comes with full PHP template support that can be used to render basic PHP files as templates with some nice enhancements and features bundled in.

Configuring Templates

Before Bullet can know how to render your templates, you have to let Bullet know where they are. If you want to use layouts, Bullet has to know where those are too. Template support can be configured with a simple array when creating the main Bullet\App object:

$app = new Bullet\App(array(
    'template' => array(
        'path' => __DIR__ . '/templates/',
        'path_layouts' => __DIR__ . '/templates/layout/',
        'auto_layout' => 'application'
    )
));
 

The auto_layout flag, if set to a string, will automatically wrap all templates in a layout file of the same name if no other layout is specified. So in this example, a layout file would have to exist at src/templates/layout/application.html.php. If you don’t want this behavior, set the flag to boolean false or simply remove it (it is off by default).

Responding With Templates From Routes

Bullet has a built-in helper method template for rendering templates as HTTP responses from routes:

$app->path('/', function($request) use($app) {
    return $app->template('hello', array('name' => 'World'));
});
 

Note that you are using return instead of echo or print. This is an important feature of Bullet. Every route should respond with a valid response type, and the Bullet\View\Template object is actually a valid HTTP response that knows how to render itself on-demand. This means that you are returning a template object, and not a rendered chunk of content. This allows you to further manipulate the response and alter it in events and nested sub-requests, even after this route is matched and executed.

Full-Featured Example

Here is a more full-featured example of template usage, just so you can see all the options that are available to you. The header and status methods come from the Bullet\Request object that the template object extends (a template is literally a form of an HTTP response in Bullet).

$app->path('/', function($request) use($app) {
    return $app->template('hello')
        ->set(array('name' => 'World'))
        ->layout('auth')
        ->format('xml') // makes it xml.php instead of html.php
        ->header('Content-Type', 'text/xml')
        ->status(200);
});
 

Template Contents

Templates will have local variables set that match the names of the variables that are passed to them. The ->set(array('name' => 'World')) call will make the variable $name available inside the template.

src/templates/hello.html.php

<p>Hello, <?php echo $name; ?>!</p>
 

Layout Contents

Layouts have a special variable $yield that holds the template content. You can use this variable to render the template content inside your layout wherever you want it to go.

src/templates/layouts/auth.html.php

<html>
<head>
  <title>Hello World</title>
</head>
<body>
  <div>
    <?php echo $yield; ?>
  </div>
</body>
</html>
 

Template Blocks

Often you will need to include assets like CSS and JavaScript files or other content within template files that need to be made available in layouts. Blocks allow you to achieve this. Content can be added to blocks using 3 different methods, depending on your desired result: content, append, and prepend.

Template Contents

Templates can define blocks with content (without an echo statement) that will be set in the block content and then later rendered in the layout or another template that it is nested in. Note that content will clear any previously set content, so if you want to add a stack of things to a block from several different templates, use append or prepend instead.

src/templates/awesome.html.php

<p>I need a custom javascript on this page because it's awesome.</p>
<?php $view->block('js')->content(function() { ?>
<script type="text/javascript" src="http://www.cornify.com/js/cornify.js"></script>
<?php }); ?>
 

Layout Contents

This layout prints the content of two blocks - one named css and one named js. The css block uses prepend with the global site styles so that the content defined here will appear before any other content added by templates.

src/templates/layouts/application.html.php

<html>
<head>
  <title>Hello World</title>
  <?php echo $view->block('css')->prepend(function() { ?>
    <style type="text/css" href="/assets/styles/site.css" />
  <?php }); ?>
</head>
<body>
  <div>
    <?php echo $yield; ?>
  </div>
  <?php echo $view->block('js'); ?>
</body>
</html>
 
Note that the block does not have to be defined beforehand for the set content to be displayed. In this example, the css block is never used first in the template, but the content set here will be displayed normally without errors.

Fork me on GitHub