Composite layouts

Contents...

Quite often the task of generating a set of complex web pages arises, particluraly when application pages share common design and contain several dynamic content blocks, some of which may be the same for all such pages or only for some of them. For example, pages, regardless of their main content, which must contain the dynamically generated menu of the currently active section and the latest news list.

To facilitate implementation of such tasks, the framework offers the layout mechanism.

General concept

Layout is the main structural template which contains areas where HTML code generated by different actions is dynamically included. One of these areas is considered as default and is filled with the content generated by the action or controller, which was called to process the user request. In other words, the main areas where the page content is displayed. Actions used to fill the remaining content areas are called directly from within the layout.

Layouts get connected to actions and controllers in addition to templates. The action/controller to which a layout has been connected transfers control over the final web page rendering to the layout. The layout receives the HTML code generated using the action's template and inserts it into the main content area of the resulting page. To fill the remaining dynamic blocks, the layout calls other actions specified in the code of the layout class.

Each layout consists of two files:

Simple example

A classic scheme with a common page layout with two dynamic blocks:

Layout template files must reside inside application directory templates/layouts/. The name of a template file must be the same as that of the corresponding template name.

Let us name a layout Default and create template file templates/layouts/Default.html for it:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>{$wa->appName()} &mdash; {$wa->accountName()}</title>
  {$wa->css()}
  <script type="text/javascript"
  src="{$wa_url}wa-content/js/jquery/jquery-1.5.2.min.js"></script>
</head>
<body>
  <div id="wa">
  {$wa->header()}
    <div id="wa-app">
      <div class="sidebar left200px">
        {$sidebar}
      </div>
      <div class="content left200px">
        {$content}
      </div>
    </div>
  </div>
</body>
</html>

Variable $content used in the template is a system one; it is automatically replaced with the execution result of the main action, when a web page is generated by this layout.

The name of a layout class name must comply with the "lowerCamelCase" notation rules: {APP_ID}{Layout Name}Layout. The layout PHP class file must reside inside application directory lib/ (we recommend using a separate subdirectory for layout classes: lib/layouts/) and must be named in accordance with the rule {class name without Layout suffix}.layout.php.

Let us create layout class file dummyDefault.layout.php. The layout class must extend system class waLayout:

<?php

class dummyDefaultLayout extends waLayout
{

    // Defining template blocks
    public function execute()
    {
        // Execution result of action dummySidebarAction will be
        // accessible via variable $sidebar in the layout template
        $this->executeAction('sidebar', new dummySidebarAction());
    }

}

Now the layout can be attached to actions and controllers. Layouts are available for classes waViewAction, waViewActions, waViewController. Here is how a layout is attached:

  $this->setLayout(new dummyDefaultLayout());

With this line of code, the execution result of an action is inserted into the layout template instead of variable $content and other variables in the layout template are replaced with the code generated by the actions specified in the dummyDefaultLayout layout class.

Layout use options

Below are described several practical tips on organizing and using layouts in an application.

Common layout for the entire application

All application pages have the same design layout; only the contents of the main page area are different.

Suppose all pages are implemented in separate classes extending waViewAction. In order to avoid attaching the layout to each action, we can override the default controller.

Some information about the default controller. Even if no controller has been explicitly defined in an application, there is still a default controller in the system when an action class is called, because an action never returns data directly to a browser — it saves its execution result to a variable. The rest is taken care of by the controller. When no controller is specified, default controller waDefaultViewController is used, which is informed by the system which action must be executed.

The default controller can be overridden in an application by creating configuration file wa-apps/{APP_ID}/lib/config/factories.php with the following contents:

<?php

return array(
    'default_controller' => 'dummyViewController'
);

Here dummyViewController is the name of the default controller class.

If file factories.php already exists in an application, then simply add this line to it.

Controller class in this case extends waDefaultViewController and must have the following structure:

<?php

class dummyViewController extends waDefaultViewController
{

    public function execute()
    {
        $this->setLayout(new dummyDefaultLayout());
        parent::execute();
    }

}

Layout for a set of pages with simple logic

Suppose we have several sets of simple middle-sized pages where each set requires its own layout. Pages have simple design; therefore, actions are based on class waViewActions, where individual actions are implemented as methods of a single class.

  1. Create the desired number of layouts.
  2. Create a separate action class extending waViewActions for each set of pages and specify the desired layout for the corresponding page set in method preExecute:
<?php

class dummyTestActions extends waViewActions
{

    // This method is called before the execution of any action
    public function preExecute()
    {
        $this->setLayout(new dummyDefaultLayout());
    }
  
    public function defaultAction()
    {
        ...
    }
  
    // template file templates/actions/test/TestPage1.html
    public function page1Action()
    {
        ...
    }
  
    // template file templates/actions/test/TestPage2.html
    public function page2Action()
    {
        ...
    }

}

An individual layout for a single page

If individual layouts are required for several single application pages, you can create separate controllers extending class waViewController for each page:

<?php


class dummyTestPageController extends waViewController
{

    public function execute()
    {
        $this->setLayout(new dummyDefaultLayout());
        $this->executeAction(new dummyTestPageAction());
    }

}