================= Views and Layouts ================= ---------- The Basics ---------- Directory Structure =================== By way of introduction, here is the directory structure for an example application. We'll call the top-level namespace "Vendor", and the application itself "Example". (These would live in the PEAR directory next to the Solar installation.) Vendor/ App/ Example.php Example/ View/ hello.php Layout/ default.php Page Controller, View, and Layout ================================= The example application is a simple "Hello World" [[Class::Solar_Page_Controller | page controller]]: /* Vendor/App/Example.php */ class Vendor_App_Example extends Solar_Controller_Page { protected $_layout = 'default'; public $foo; public $zim; public method actionHello() { // let's set some properties $this->foo = 'bar'; $this->zim = 'gir'; // Solar_Controller_Page automatically finds and renders the // 'hello.php' view, then takes that output and automatically // injects it into the 'default.php' layout. } } **Note**: As of revision 3374 Solar_App_Base now uses new $_layout_default property, instead of redefining $_layout. The view script in this case is dirt-simple, but you can use [[Package::Solar_View | ]] helpers to jazz it up.

Hello, world!

Foo is escape($this->foo) ?>.

As with most 2-step view implementations, the view output is "injected" into the layout script. In this case, let's use a bare-bones HTML layout. Example layout_content ?> (The `$layout_content` property is automatically populated by the page-controller with the output of the rendered view.) When you browse to `http://example.com/example/hello`, you should see this output from the application: Example

Hello, world!

Foo is bar.

Variable Assignment =================== Wait, how did `$foo` get into the view? The page-controller automatically assigns all of its own public properties to the view object, so you don't have to think about what gets set and what doesn't. If a controller property is public, the view can use it. 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 `$zim` as the title ... <?php echo $this->escape($this->zim) layout_content ?> ... and the output would become: Gir

Hello, world!

Foo is bar.

--------------- Advanced Topics --------------- Other Layouts, or No Layout =========================== If you want to use a layout other than the default one, just change `$this->_layout` to the one you want to use. First, add the layout script: Vendor/ App/ Example.php Example/ View/ hello.php Layout/ default.php other.php Then ask for it in your action: /* Vendor/App/Example.php */ class Vendor_App_Example extends Solar_Controller_Page { protected $_layout = 'default'; protected $_action_default = 'hello'; public $foo; public $zim; public method actionHello() { // let's set some properties $this->foo = 'bar'; $this->zim = 'gir'; // let's use some other layout $this->_layout = 'other'; } } If you don't want to use a layout at all, set `$this->_layout = null`. 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 `$this->_view` to the name of any view you like. Shared Layouts ============== 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 "base" controller from which other controllers will extend, then put the shared layouts there. Vendor/ App/ Base.php Base/ Layout/ default.php other.php The base controller might look like this: /* Vendor/App/Base.php */ class Vendor_App_Base extends Solar_Controller_Page { // nothing really needed here, unless you want // shared methods and properties too } Now the "example" controller extends the base controller: /* Vendor/App/Example.php */ class Vendor_App_Example extends Vendor_App_Base { // ... } 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. Vendor/ App/ Base.php Base/ Layout/ default.php other.php Example.php Example/ View/ hello.php You can override the shared layouts with local ones if you want to. If you have `Example/Layout/default.php` the page-controller will use it instead of the shared one. This works with views too. Put any views you want to share in `Base/View`, and the page-controller will find them if they don't exist in the `Example/View` directory. ---------------- Multiple Formats ---------------- Now let's 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 -- you do not have to change your controller logic at all. First, we need to tell the controller that we will allow an XML response to an action (in this case, the "hello" action). Modify the [[Solar_Controller_Page::$_action_format]] property to do so. {{code: php class Vendor_App_Example extends Vendor_App_Base { // ... protected $_action_format = array( 'hello' => array('xml'); ); } }} (We add as an array because the "hello" action might also respond to 'atom', 'rss', and so on -- just add the extra formats to the array.) Now let's add the XML view for our "hello" action ("hello.xml.php" below). Vendor/ App/ Example.php Example/ View/ hello.php hello.xml.php Layout/ default.php other.php The hello.xml.php view script looks like this: escape($this->foo) ?> escape($this->zim) ?> Now when you browse to `http://example.com/example/hello.xml` (notice the added ".xml" at the end), you will get this output: bar gir You can do this for any output format you like: .atom, .rss, and so on -- and not have to change your controller logic at all. 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.