{
    "href": "/post/2007/07/12/solar-views-and-layouts/",
    "relId": "2007/07/12/solar-views-and-layouts",
    "title": "Solar Views and Layouts",
    "author": "pmjones",
    "markup": "html",
    "tags": [
        {
            "href": "/tag/php/",
            "relId": "php",
            "title": "PHP",
            "author": null,
            "created": null,
            "updated": [],
            "markup": "markdown"
        },
        {
            "href": "/tag/solar/",
            "relId": "solar",
            "title": "Solar",
            "author": null,
            "created": null,
            "updated": [],
            "markup": "markdown"
        }
    ],
    "created": "2007-07-12 13:24:37 UTC",
    "updated": [
        "2007-07-12 13:24:37 UTC"
    ],
    "html": "<p>Looks like the Zend Framework project doesn\u2019t have \u201ccomplex views\u201d settled just yet.  I\u2019m sure they\u2019ll hit on a solution soon.  In the mean time, let me show you how easy it is to work with views and layouts in <a href=\"http://solarphp.com\">Solar</a>, including automatic format discovery and inherited layouts.</p>\n<h3>Basic Directory Structure</h3>\n<p>By way of introduction, here is the directory structure for an example application.  We\u2019ll call the top-level namespace \u201cVendor\u201d, and the application itself \u201cExample\u201d.  (These would live in the PEAR directory next to the Solar installation.)</p>\n<pre><code> Vendor/\n     App/\n         Example.php\n         Example/\n            View/\n                hello.php\n            Layout/\n                default.php\n</code></pre>\n<h3>Page Controller, View, and Layout</h3>\n<p>The example application is a simple \u201cHello World\u201d <a href=\"http://solarphp.com/class/Solar_Controller_Page\">page controller</a>:</p>\n<pre><code>/* Vendor/App/Example.php */\n\nclass Vendor_App_Example extends Solar_Controller_Page {\n\n    protected $_layout = 'default';\n\n    public $foo;\n\n    public $zim;\n\n    public function actionHello()\n    {\n        // let's set some properties\n        $this-&gt;foo = 'bar';\n        $this-&gt;zim = 'gir';\n\n        // Solar_Controller_Page automatically finds and renders the\n        // 'hello.php' view, then takes that output and automatically\n        // injects it into the 'default.php' layout.\n    }\n}\n</code></pre>\n<p>The view script in this case is dirt-simple, but you can use <a href=\"http://solarphp.com/package/Solar_View\">Solar_View</a> helpers to jazz it up.</p>\n<pre><code>        &lt;!-- Vendor/App/Example/View/hello.php --&gt;\n        &lt;p&gt;Hello, world!&lt;/p&gt;\n        &lt;p&gt;Foo is &lt;?php echo $this-&gt;escape($this-&gt;foo) ?&gt;.&lt;/p&gt;\n</code></pre>\n<p>As with most 2-step view implementations, the view output is \u201cinjected\u201d into the layout script.  In this case, let\u2019s use a bare-bones HTML layout.</p>\n<pre><code>&lt;!-- Vendor/App/Example/View/default.php --&gt;\n&lt;html&gt;\n    &lt;head&gt;\n        &lt;title&gt;Example&lt;/title&gt;\n    &lt;/head&gt;\n    &lt;body&gt;\n        &lt;?php echo $this-&gt;layout_content ?&gt;\n    &lt;/body&gt;\n&lt;/html&gt;\n</code></pre>\n<p>(The <code>$layout_content</code> property is automatically populated by the page-controller with the output of the rendered view.)</p>\n<p>When you browse to <code>http://example.com/example/hello</code>, you should see this output from the application:</p>\n<pre><code>&lt;!-- Vendor/App/Example/Layout/default.php --&gt;\n&lt;html&gt;\n    &lt;head&gt;\n        &lt;title&gt;Example&lt;/title&gt;\n    &lt;/head&gt;\n    &lt;body&gt;\n        &lt;!-- Vendor/App/Example/View/hello.php --&gt;\n        &lt;p&gt;Hello, world!&lt;/p&gt;\n        &lt;p&gt;Foo is bar.&lt;/p&gt;\n    &lt;/body&gt;\n&lt;/html&gt;\n</code></pre>\n<h3>Variable Assignment</h3>\n<p>Wait, how did <code>$foo</code> get into the view?  The page-controller automatically assigns all public properties of the controller to the view object, so you don\u2019t have to think about what gets set and what doesn\u2019t.  If a controller property is public, the view can use it.</p>\n<p>Likewise, the page-controller assigns the same variables to the layout, so you have full access to them in your layouts as well.  For example, we could change the layout script to use <code>$zim</code> as the title \u2026</p>\n<pre><code>&lt;!-- Vendor/App/Example/View/default.php --&gt;\n&lt;html&gt;\n    &lt;head&gt;\n        &lt;title&gt;&lt;?php echo $this-&gt;escape($this-&gt;zim)&lt;/title&gt;\n    &lt;/head&gt;\n    &lt;body&gt;\n        &lt;?php echo $this-&gt;layout_content ?&gt;\n    &lt;/body&gt;\n&lt;/html&gt;\n</code></pre>\n<p>\u2026 and the output would become:</p>\n<pre><code>&lt;!-- Vendor/App/Example/View/default.php --&gt;\n&lt;html&gt;\n    &lt;head&gt;\n        &lt;title&gt;Gir&lt;/title&gt;\n    &lt;/head&gt;\n    &lt;body&gt;\n        &lt;!-- Vendor/App/Example/View/hello.php --&gt;\n        &lt;p&gt;Hello, world!&lt;/p&gt;\n        &lt;p&gt;Foo is bar.&lt;/p&gt;\n    &lt;/body&gt;\n&lt;/html&gt;\n</code></pre>\n<h3>Other Layouts, or No Layout</h3>\n<p>If you want to use a layout other than the default one, just change <code>$this-&gt;_layout</code> to the one you want to use.  First, add the layout script:</p>\n<pre><code> Vendor/\n     App/\n         Example.php\n         Example/\n            View/\n                hello.php\n            Layout/\n                default.php\n                other.php\n</code></pre>\n<p>Then ask for it in your action:</p>\n<pre><code>/* Vendor/App/Example.php */\n\nclass Vendor_App_Example extends Solar_Controller_Page {\n\n    protected $_layout = 'default';\n\n    protected $_action_default = 'hello';\n\n    public $foo;\n\n    public $zim;\n\n    public function actionHello()\n    {\n        // let's set some properties\n        $this-&gt;foo = 'bar';\n        $this-&gt;zim = 'gir';\n\n        // let's use some other layout\n        $this-&gt;_layout = 'other';\n    }\n}\n</code></pre>\n<p>If you don\u2019t want to use a layout at all, set <code>$this-&gt;_layout = null</code>.</p>\n<p>You can do the same thing for views; by default, the page controller looks for a view that matches the action name, but you can set <code>$this-&gt;_view</code> to the name of any view you like.</p>\n<h3>Multiple Formats</h3>\n<p>Now let\u2019s say that we want to expose an XML version of our view.  The Solar page-controller can look at the format-extension on a request and render the right view for you automatically.  All you need to do it provide the view script for it \u2013 you do not have to change your controller logic at all.</p>\n<p>Let\u2019s add the XML view for our \u201chello\u201d action (\u201chello.xml.php\u201d below).</p>\n<pre><code> Vendor/\n     App/\n         Example.php\n         Example/\n            View/\n                hello.php\n                hello.xml.php\n            Layout/\n                default.php\n                other.php\n</code></pre>\n<p>The hello.xml.php view script looks like this:</p>\n<pre><code>&lt;hello&gt;\n    &lt;foo&gt;&lt;?php echo $this-&gt;escape($this-&gt;foo) ?&gt;&lt;/foo&gt;\n    &lt;zim&gt;&lt;?php echo $this-&gt;escape($this-&gt;zim) ?&gt;&lt;/zim&gt;\n&lt;/hello&gt;\n</code></pre>\n<p>Now when you browse to <code>http://example.com/example/hello.xml</code> (notice the added \u201c.xml\u201d at the end), you will get this output:</p>\n<pre><code>&lt;hello&gt;\n    &lt;foo&gt;bar&lt;/foo&gt;\n    &lt;zim&gt;gir&lt;/zim&gt;\n&lt;/hello&gt;\n</code></pre>\n<p>You can do this for any output format you like: .atom, .rss, and so on \u2013 and not have to change your controller logic at all.</p>\n<p>Wait a minute, what happened to the layout?  The Solar page-controller knows that if it receives a non-default format request, it should turn off the layout and use only the view.</p>\n<h3>Shared Layouts</h3>\n<p>Now, what if you have a layout or view that you want to share among multiple page controllers?  This is pretty easy, too.  First, define a \u201cbase\u201d controller from which other controllers will extend, then put the shared layouts there.</p>\n<pre><code> Vendor/\n     App/\n         Base.php\n         Base/\n            Layout/\n                default.php\n                other.php\n</code></pre>\n<p>The base controller might look like this:</p>\n<pre><code>/* Vendor/App/Base.php */\nclass Vendor_App_Base extends Solar_Controller_Page {\n    // nothing really needed here, unless you want\n    // shared methods and properties too\n}\n</code></pre>\n<p>Now the \u201cexample\u201d controller extends the base controller:</p>\n<pre><code>/* Vendor/App/Example.php */\nclass Vendor_App_Example extends Vendor_App_Base {\n    // ...\n}\n</code></pre>\n<p>And you can remove the layouts from the example controller; it will automatically look up through the class-inheritance hierarchy to find the requested layout.</p>\n<pre><code> Vendor/\n     App/\n         Base.php\n         Base/\n            Layout/\n                default.php\n                other.php\n         Example.php\n         Example/\n            View/\n                hello.php\n</code></pre>\n<p>You can override the shared layouts with local ones if you want to. If you have <code>Example/Layout/default.php</code> the page-controller will use it instead of the shared one.</p>\n<p>This works with views too.  Put any views you want to share in <code>Base/View</code>, and the page-controller will find them if they don\u2019t exist in the <code>Example/View</code> directory.</p>\n<h3>That\u2019s All For Now</h3>\n<p>Questions?  Comments?  Leave a message below, or join the <a href=\"http://solarphp.com/project/mailing-list\">Solar mailing list</a> and chime in there \u2013 we\u2019d be happy to have you around.</p>\n"
}
