Custom View Helper in Zend Framework

Zend Framework which is built on MVC design pattern has also provided lots of it’s accessories. The view helper is one of them.

 

The view helper, as it named, is to help the view to complete it’s work. It’s major role is to package the html code and sometimes with model data.

 

Here I will use a simple but useful helper – Image Helper to show you how to build your own one.

 

First the application structure :

 

 

Now is the code :

 

[codesyntax lang=”php”]

// Bootstrap.php

// Get viewRenderer
$viewRenderer = Zend_Controller_Action_HelperBroker::getExistingHelper('viewRenderer');

// initialize the view
$viewRenderer->initView($myViewBasePath);
$view = $viewRenderer->view;

// Path and prefix of custom view helper
$view->addHelperPath('Kbs/View/Helper/', Kbs_View_Helper_);

[/codesyntax]

 

[codesyntax lang=”php”]

// Image Helper : Kbs/View/Helper/Img.php

require_once('Zend/View/Helper/Abstract.php');

class Kbs_View_Helper_Img extends Zend_View_Helper_Abstract
{
    public function img($src, $width, $height, $alt = '', $options = array())
    {
        if (empty($alt)) {
            // make sure alt is not empty for SEO
            throw new Zend_View_Exception('Alt attribute should be filled.');
        }

        $basepath = $this->view->serverUrl() . '/public/img/';
        $img = '<img src="' . $basepath . $src . '" width="' . $width . '" '
             . 'height="' . $height . '" alt="' . $alt . '" />';

        return $img;
    }
}

[/codesyntax]

 

[codesyntax lang=”php”]

// index.phtml
echo $this->img('example.jpg', 100, 100, 'This is the example');

[/codesyntax]

 

Isn’t it easy enough?

Posted in Zend Framework | Tagged | Leave a comment

Builder Pattern in Zend Framework

When we want to implement one thing in different ways, we think of builder design pattern. It’s like a building, when, design has been done, though handled by different engineers directing different construction teams, eventually the building will be the same.

 

Here I have to say something about the different between the builder pattern and the factory pattern. In fact as the name implies factory, It provides products, such as rice cooker, microwave ovens and so on. But the builder is more responsible, it provides the different finished in different ways. For example cooking, we can use rice cooker, but microwave ovens can also be used.

 

Zend_Feed module in Zend Framework has already implemented the builder design pattern to allow users to achieve their own customized content feed :

 

 

The source code below is simplified :

 

[codesyntax lang=”php”]

// builder interface
interface Zend_Feed_Builder_Interface
{
    public function getHeader();
    public function getEntries();
}

[/codesyntax]

 

Default builder provided by Zend_Feed :

 

/**
* @see Zend_Feed_Builder_Interface
*/

require_once 'Zend/Feed/Builder/Interface.php';
/**
* @see Zend_Feed_Builder_Header
*/

require_once 'Zend/Feed/Builder/Header.php';
/**
* @see Zend_Feed_Builder_Entry
*/

require_once 'Zend/Feed/Builder/Entry.php';
/**
* Zend_Feed_Builder implements the Zend_Feed_Builder_Interface interface
* Users can create their own customized builder through Zend_Feed_Builder_Interface interface
*/

class Zend_Feed_Builder implements Zend_Feed_Builder_Interface
{
private $_header;
private $_entries = array();
// ......
public function __construct(array $data)
{
// ......
$this->_header = new Zend_Feed_Builder_Header($data['title'], $data['link'], $data['charset']);
foreach ($data as $row) {
// ......
$entry = new Zend_Feed_Builder_Entry($row['title'], $row['link'], $row['description']);
$this->_entries[] = $entry;
}
}
// Zend_Feed_Builder_Interface interface function
public function getHeader()
{
return $this->_header;
}
// Zend_Feed_Builder_Interface interface function
public function getEntries()
{
return $this->_entries;
}
// ......
}

 

Notice that we can easily implement our own builder through Zend_Feed_Builder_Interface interface, for example :

 

[codesyntax lang=”php”]

class My_Feed_Builder implements Zend_Feed_Builder_Interface
{
public function getHeader()
{
return 'My Header!';
}
public function getEntries()
{
return 'My Entries!';
}
}

[/codesyntax]

 

Then let’s take a look at Zend_Feed_Abstract abstract class. It acts like a director in the builder pattern within Zend_Feed module. Its responsibility is to choose and aggregate the builder that user provide, and then cure the semi-manufactured into perfect goods.

 

[codesyntax lang=”php”]

/**
* Zend_Feed_Abstract abstract class
*/

abstract class Zend_Feed_Abstract extends Zend_Feed_Element implements Iterator
{
// Header and Entries are provided by $builder
public function __construct($uri = null, $string = null, Zend_Feed_Builder_Interface $builder = null)
{
// ......
$this->_mapFeedHeaders($builder->getHeader());
$this->_mapFeedEntries($builder->getEntries());
}
}

[/codesyntax]

 

The example feed data sets is from a simple array :

 

[codesyntax lang=”php”]

$data = array('author' => 'kim'
              'description' => 'my data');

// Use default builder
require_once 'Zend/Feed/Builder.php';
$atom = new Zend_Feed_Atom(null, null, new Zend_Feed_Builder($data));

// Use my own builder
require_once 'My/Feed/Builder.php';
$myAtom = new Zend_Feed_Atom(null, null, new My_Feed_Builder($data));

[/codesyntax]

 

The builder design pattern has provide a flexible mechanism to create the object and data collections, which is really the assuring for the extensiblity of application.

 

Posted in Design Patterns | Tagged , | Leave a comment

PHP Coding Standards (1) – File Formatting

1. For PHP files the closing tag ("?>") is to be omitted. It is not required by PHP, and omitting it prevents trailing whitespace from being accidentally injected into the output.

 

In fact the problem comes when you don’t use gzip or output buffering in php : 

 

// php.ini – Turn off compress output and output buffering

zlib.output_compression = off

output_buffering = off

 

// foo.php – There are some white spaces after "?>"

[codesyntax lang=”php”]

<?php
$foo = 'foo';
?>

[/codesyntax]

 

// index.php – In fact we have already output some white spaces when include foo.php

[codesyntax lang=”php”]

<?php
include 'foo.php';
session_start();
?>

[/codesyntax]

 

We will see the warning saying that "… Cannot send session cache limiter – headers already sent …" because of the output of some white spaces before session_start() is called.

 

 

2. Inclusion of arbitrary binary data as permitted by __halt_compiler() is prohibited from PHP files in the Zend Framework project or files derived from them.

 

In fact it’s to prevent some cases unpredictable. Take the example above :

 

// foo.php – we have already permitted "?>"

 

[codesyntax lang=”php”]

<?php
// Perhaps we want to output something by using __halt_compiler()
if (defined('__COMPILER_HALT_OFFSET__')) {
    $fp = fopen(__FILE__, 'r');
    fseek($fp, __COMPILER_HALT_OFFSET__);
    var_dump(stream_get_contents($fp));
}

// At the end of script
__halt_compiler();

[/codesyntax]

 

We still see the warning until __halt_compiler() is commentted. In other hand please pay attention that __halt_compiler() is language structure but not function or method.

 

 

3. Use an indent of 4 spaces with no tab characters. Editors should be configured to treat tabs as spaces in order to prevent injection of tab characters into the source code.

 

Its mainly goal is to keep the source code looks clean and neat Especially in different IDE or editors. In fact it had already became an default standard for software development.

 

For example :

[codesyntax lang=”php”]

if ($x == 1) {
$indented_code = 1;
if ($new_line == 1) {
$more_indented_code = 1;
}
}

[/codesyntax]

 

 

4. Multiple assignments must have the same indentation.

 

For example :

[codesyntax lang=”php”]

$variable1 = "demo"; 
$var2 = "demo2";

[/codesyntax]

 

 

5. The target line length is 80 characters. The maximum length of any line of PHP code is 120 characters.

 

Since linux read the file by 80 charactors per time which means it needs additional operations if one line with more than 80 charactors. It seems a little problem, but it’s worth to compliance especially for those strive for perfection.

 

For example some lines in Zend/Navigation.php :

 

 

6. Lines should not contain trailing spaces.

 

In order to facilitate this convention, most IDEs and editors can be configured to strip trailing spaces, such as upon a save operation.

 

 

7. Line termination is the standard way for Unix text files. Lines must end only with a linefeed "\n" (LF). Linefeeds are represented as ordinal 10, or hexadecimal 0x0A. Do not use carriage returns "\r" (CR) like Macintosh computers (0x0D). Do not use the carriage return/linefeed combination "\r\n" (CRLF) as Windows computers (0x0D, 0x0A).

 

It doesn’t means to belittle apple or windows. The fact is that LAMP is still mainstream and we need to follow its file formatting standard for better performance.

 

 

Posted in Coding Standards | Tagged , | Leave a comment

Practise dojox.grid.DataGrid with Zend_Dojo

Zend_Dojo was released together with Zend Framework 1.6 as well as Dojo toolkit package. We can make a good experience of the client-side with powerful Dojo components through a simple API provided by Zend_Dojo.

 

I had tried one very simple example of dojox.grid.DataGrid using Zend_Dojo and Zend_Dojo_Data few days ago.

 

You can place the example below within any view because GoogleAPI CDN for dojo is used.

 

[codesyntax lang=”php”]

<?php
// index.phtml or any other view

// Testing data (should be from database)
$this->posts = array(
    '1' => array(
        'postId' => 'id_1',
        'postTitle' => 'title_1',
        'postDetail' => 'detail_1',
    ),
    '2' => array(
        'postId' => 'id_2',
        'postTitle' => 'title_2',
        'postDetail' => 'detail_2',
    ),
    '3' => array(
        'postId' => 'id_3',
        'postTitle' => 'title_3',
        'postDetail' => 'detail_3',
    ),
    '4' => array(
        'postId' => 'id_4',
        'postTitle' => 'title_4',
        'postDetail' => 'detail_4',
    ),
    '5' => array(
        'postId' => 'id_5',
        'postTitle' => 'title_5',
        'postDetail' => 'detail_5',
    ),
    '6' => array(
        'postId' => 'id_6',
        'postTitle' => 'title_6',
        'postDetail' => 'detail_6',
    ),
);

// Zend_Dojo_View_Helper_Dojo
if (isset($this->posts)) {

    // Google Api CDN path
    $cdnPath = 'http://ajax.googleapis.com/ajax/libs/dojo/1.3.1/';

    $this->dojo()
         ->enable()

         // We use CDN version 1.3.1
         ->setCdnVersion('1.3.1')

         // Basic configs
         ->setDjConfigOption('parseOnLoad', true)
         ->setDjConfigOption('isDebug', false)
         ->setDjConfigOption('locale', 'zh')

         // Import some css
         ->registerDojoStylesheet(true)
         ->addStylesheet($cdnPath . 'dojox/grid/resources/Grid.css')
         ->addStylesheet($cdnPath . 'dojox/grid/resources/tundraGrid.css')
         ->addStylesheet($cdnPath . 'dijit/themes/tundra/tundra.css')

         // Include some dojo modules
         ->requireModule('dijit.dijit')
         ->requireModule('dojox.grid.DataGrid')
         ->requireModule('dojo.data.ItemFileWriteStore')
         ->requireModule('dojo.parser')
         ;

    // Echo Dojo (in layout as you like)
    echo $this->dojo();

    // Use Zend_Dojo_Data to build dojo data (in fact it's a json data)
    $data = new Zend_Dojo_Data();
    $data->setIdentifier('postId')
         ->setLabel('My post list')
         ->addItems($this->posts);

    //var_dump($data);
?>

    <script type="text/javascript">
        // Dojo addOnLoad loaded on demand
        dojo.addOnLoad(function() {
            // Grid layout
            var gridLayout = [[
                {name: 'Post',      field: 'postId',        width: "50px"},
                {name: 'Title',     field: 'postTitle',     width: "200px"},
                {name: 'Detail',    field: 'postDetail',    width: "400px"}
            ]];

            // Debug - setDjConfigOption('isDebug', true)
            //console.log('<?php echo $data; ?>');

            // Use ItemFileWriteStore to store data
            var test_store = new dojo.data.ItemFileWriteStore({data: <?php echo $data; ?>});

            // Set layout and set store
            gridNode.setStructure(gridLayout);
            gridNode.setStore(test_store);
        });
    </script>

    <div jsId="gridNode" dojoType="dojox.grid.DataGrid" rowsPerPage="10"
        style="width:675px; height:400px;"></div>

<?php
}
?>

[/codesyntax]

 

 

Simple and powerful, isn’t it? It can be easily extended to be a powerful data grid. Please see Dojo Api and Dojo 1.3 manual for more details.

Posted in Zend Framework | Tagged , | Leave a comment

Multi-modules and multi-templates application for Zend_Application

At the very beginning I need to introduced everybody of Zend_Application before doing anything. As one of the most important big changes in Zend Framework 1.8, the Zend_Application has introduce two new concepts (new to Zend Framework) – Bootstrap and Resource, which greatly simplifies the construction of applications. It can be said that the Zend_Appication marks the emergence of the genuine maturing of Zend Framework.

 

 

Two new concepts in Zend_Application :

 

1. Bootstrap

 

The bootstrap, familiar to many developers who had tried to used Zend Framework, is aim at packaging the initialization process. I am sure most of you have wrote this (or similar to this) bootstrap class :

 

[codesyntax lang=”php”]

// Bootstrap.php
class Bootstrap
{
    // ...

    public function initLoader(){...}
    public function initController(){...}
    public function initDb(){...}
    public function initView(){...}
    public function initLayout(){...}
    public function initSession(){...}
    public function initAuth(){...}
    public function initAcl(){...}

    // ...
}

[/codesyntax]

 

In this way your bootstrap has became an monster and hard to handle. But don’t worry, now Zend_Application has been your good friend which makes the construction of application really easy. What you need to do is just create the object of appliation and then make some configurations (usually one .ini).

 

2. Resource

 

Zend_Application_Resource is a new concept from 1.8 in view of the characteristic of php. The spirit it describes is :  Loaded On Demand. Since the every time of php’s running and parsing is a complete process of resource recycling, the question how to minimize the code of each cycle has became one of the most important thing for either php optimization or framework development.

 

In fact we can see resource as a component of Zend Framework, for example Zend_Controller, Zend_Db, Zend_View and so on. And at the same time you can also create your own resource in order to use your own component. For instance the Zend_Application_Resource_Db is one of the default resources which initializes the Zend_Db object and set default adapter :

 

[codesyntax lang=”php”]

class Zend_Application_Resource_Db extends Zend_Application_Resource_ResourceAbstract
{
    // ...

    // Defined by Zend_Application_Resource_Resource
    public function init()
    {
        // ...

        $this->_db = Zend_Db::factory($adapter, $this->getParams());
        Zend_Db_Table::setDefaultAdapter($db);
        return $db;

        // ...
    }
}

[/codesyntax]

 

Zend Framework 1.8 has provided 10 default resources for the moment :

 

1. Zend_Application_Resource_Db

2. Zend_Application_Resource_Frontcontroller

3. Zend_Application_Resource_Layout

4. Zend_Application_Resource_Locale

5. Zend_Application_Resource_Modules

6. Zend_Application_Resource_Navigation

7. Zend_Application_Resource_Router

8. Zend_Application_Resource_Session

9. Zend_Application_Resource_Translate

10. Zend_Application_Resource_View

 

Hope it will increase in the furture.

 

Here is one simple example to initialize the FrontController resource :

 

[codesyntax lang=”php”]

// Project root
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH',
              MY_PROJECT_ROOT . '/application');

// Application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV',
              (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV')
                                         : 'production'));

// Zend_Application and setting of FrontController resource
require_once 'Zend/Application.php';
$application = new Zend_Application(
    APPLICATION_ENV,
    array(
        'resources' => array(
            'FrontController' => array(
                'controllerDirectory' => APPLICATION_PATH . '/controllers',
            ),
        ),
    )
);

// Bootstrap resources and run
$application->bootstrap();
$application->run();

[/codesyntax]

 

And we can create our own resource by extending Zend_Application_Resource_ResourceAbstract . Then what we need to do is make some configurations within Application.ini to register our resource to the Bootstrap. After that the function Zend_Application_Bootstrap_Bootstrap::bootstrap($resource) is the one to bootstrap resource whenever needed.

 

Register custom view resource :

 

[codesyntax lang=”php”]

// Custom view resource
class Kbs_Application_Resource_View extends Zend_Application_Resource_ResourceAbstract
{
    protected $_view;

    // init view
    // @return Zend_View $view
    public function init()
    {
        if (null === $this->_view) {
            $options = $this->getOptions();
            $view = new Zend_View($options);
            ......
            $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper(
                'ViewRenderer'
            );
            $viewRenderer->setView($view);
            $this->_view = $view;
        }        
        return $this->_view;
    }
}

[/codesyntax]

 

And parameters of Zend_Application  :

 

[codesyntax lang=”php”]

$application = new Zend_Application(APPLICATION_ENV, array(
    // Path and prefix of plugin resources
    'pluginPaths' => array(
        'Kbs_Application_Resource' => 'Kbs/Application/Resource/',
    ),
    'resources' => array(
        'FrontController' => array(...),
        ......
        // View resource
        'View' => array('title' => 'my application'),
    ),
));

[/codesyntax]

 

Of course we can also put them in Application.ini instead :

 

// Application.ini

pluginPaths.Kbs_Application_Resource                    = APPLICATION_PATH "/../library/Kbs/Application/Resource/"
resources.view.title                                    = "my application"
resources.view.encoding                                 = "UTF-8"
 

Then pass it to Zend_Application :

 

[codesyntax lang=”php”]

$application = new Zend_Application(
    APPLICATION_ENV, 
    PROJECT_ROOT . '/Config/Application.ini'
));

[/codesyntax]

 

 


 

As we have already made a preview of Zend_Application and Zend_Application_Resource, let’s start our main subject : how to build multi-modules and multi-templates application with Zend_Application .

 

Zend Framework, which based on MVC design pattern, has provided a complete set of modular design. That’s to say every module in Zend Framework has it’s own MVC structure.

 

But it’s not easy for you to do such things like assigning different templates to different modules or assigning different templates to the same module. We need some configurations and skills when building our structure and application.

 

First, our application’s structure is just as below :

 

 

 

We have two folders – modules and templates under application. And we got two modules – admin and front in each of them. The folder controllers within each module is where we store controllers (e.g. IndexController, UserController). The folders of modules in templates is where we store all different templates. For example we got two templates called default and oceanStyle under front.

 

We then put all our resources under  library/Kbs/Application/Resource/  folder :

 

 

Ok let’s finish our configuration file (Application.ini) :

  

; Application.ini

[production]
;=========== Library path
;includePaths.library                                           = APPLICATION_PATH "/../library/"

;=========== Autoload namespace prefix
autoloadernamespaces.0                                          = "Zend_"
autoloadernamespaces.1                                          = "ZendX_"
autoloadernamespaces.2                                          = "Kbs_"

;=========== php ini setting
phpsettings.date.timezone                                       = "Asia/Shanghai"
phpSettings.display_startup_errors                              = 0
phpSettings.display_errors                                      = 0
phpsettings.error_reporting                                     = 8191

;=========== Bootstrap class and it’s path
bootstrap.path                                                  = APPLICATION_PATH "/Bootstrap.php"
bootstrap.class                                                 = "Bootstrap"

;=========== Plugin resources and their path
pluginPaths.Kbs_Application_Resource                            = APPLICATION_PATH "/../library/Kbs/Application/Resource/"

;=========== Resource frontController
resources.frontController.moduleDirectory                       = APPLICATION_PATH "/modules/"
resources.frontController.moduleControllerDirectoryName         = "controllers"
resources.frontController.defaultModule                         = "front"
resources.frontController.plugins.common                        = "Kbs_Controller_Plugin_Common"
resources.frontController.noErrorHandler                        = 0
resources.frontController.throwExceptions                       = 1
 

;=========== Resource layout
resources.layout.layout                                         = "we use resources.view.params.module.layout instead"
resources.layout.layoutPath                                     = "we use resources.view.params.module.layoutPath instead"

;=========== Resource view
resources.view.title                                            = ""
resources.view.encoding                                         = "UTF-8"
resources.view.helperPathPrefix                                 = "Kbs_View_Helper_"
resources.view.helperPath                                       = "Kbs/View/Helper/"
 

;=========== Params for modules front and admin within resource view (including basepath, prefix, layout, layoutPath)
resources.view.params.front.basePath                            = APPLICATION_PATH "/templates/front/default/"
resources.view.params.front.helperPathPrefix                    = "Kbs_View_Helper_Front_"
resources.view.params.front.helperPath                          = "Kbs/View/Helper/Front/"
resources.view.params.front.layout                              = "frontlayout"
resources.view.params.front.layoutPath                          = APPLICATION_PATH "/templates/front/default/layout/"

resources.view.params.admin.basePath                            = APPLICATION_PATH "/templates/admin/default/"
resources.view.params.admin.helperPathPrefix                    = "Kbs_View_Helper_Admin_"
resources.view.params.admin.helperPath                          = "Kbs/View/Helper/Admin/"
resources.view.params.admin.layout                              = "adminlayout"
resources.view.params.admin.layoutPath                          = APPLICATION_PATH "/templates/admin/default/layout/"
 

;=========== Other params for view
resources.view.params.pathCss                                   = "/public/css/"
resources.view.params.pathImg                                   = "/public/img/"
resources.view.params.pathJs                                    = "/public/js/"
resources.view.params.doctype                                   = "HTML4_STRICT"
resources.view.params.charset                                   = "utf-8"

;=========== Database setting
resources.db.adapter                                            = "pdo_mysql"
resources.db.params.host                                        = "localhost"
resources.db.params.username                                    = "xxx"
resources.db.params.password                                    = "xxx"
resources.db.params.dbname                                      = "xxx"
resources.db.isDefaultTableAdapter                              = true
resources.db.params.driver_options.1002                         = "SET NAMES UTF8;"

;=========== Translation setting
resources.translate.registry_key                                = "Zend_Translate"
resources.translate.adapter                                     = "array"
resources.translate.options.scan                                = "directory"
resources.translate.data.directory                              = APPLICATION_PATH "/languages/"
resources.translate.data.fileExt                                = ".php"

;=========== Locale enabled
resources.locale                                                = true

[testing : production]
phpSettings.display_startup_errors                              = 1
phpSettings.display_errors                                      = 1
phpsettings.error_reporting                                     = 8191
resources.db.params.username                                    = "xxx"
resources.db.params.password                                    = "xxx"
resources.db.params.dbname                                      = "xxx"

[development : production]
phpSettings.display_startup_errors                              = 1
phpSettings.display_errors                                      = 1
phpsettings.error_reporting                                     = 8191
resources.db.params.username                                    = "xxx"
resources.db.params.password                                    = "xxx"
resources.db.params.dbname                                      = "xxx"

 

The two sections testing and development are inherited from production. We can set runtime configurations by putting phpsettings.* as well as .htaccess or php.ini. The bootstrap class and it’s path can be set by bootstrap.* while resources.* is so called resources.

 

These are configurations of my own and may not fit any situation. Make some changes to fit yourself whenever needed.

 

The entry index.php :

 

[codesyntax lang=”php”]

// Project root
defined('PROJECT_ROOT')
    || define('PROJECT_ROOT',
              realpath(dirname(dirname(__FILE__))));

// Application path
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH',
              PROJECT_ROOT . '/application');

// Application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV',
              (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV')
                                         : 'production'));

// Include paths
set_include_path(implode(PATH_SEPARATOR, array(
    PROJECT_ROOT . '/library'
)));

// Zend_Application
require_once 'Zend/Application.php';

// Create application
$application = new Zend_Application(
    APPLICATION_ENV,
    PROJECT_ROOT . '/library/Kbs/Config/Application.ini'
);

// Throw warnings when development and testing
if ('production' !== APPLICATION_ENV) {
    $application->getAutoloader()->suppressNotFoundWarnings(false);
}

// Bootstrap (only) frontController and run
$application->getBootstrap()->bootstrap('FrontController');
$application->run();

[/codesyntax]

 

Here APPLICATION_ENV is a predefined system environment variable which contain one of these three values – development, testig, production. It means which environment the application is running on.

 

What you need to pay attention is that we only bootstrap frontController resource in order to minimize the resources we boot at the first time. We will leave all others handled by one custom action plugin called Kbs_Controller_Plugin_Common and then loaded on demand by using Zend_Application_Bootstrap_Bootstrap::bootstrap($resource) method.

 

We use plugin resource but not override resource initailization (e.g. Bootstrap::_initView) to keep our bootstrap class clean and neat :

 

[codesyntax lang=”php”]

// Kbs/Application/Bootstrap.php
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
    // Do nothing
}

[/codesyntax]

 

Now we need to use a custom action plugin which had already defined in Application.ini to tell FrontController where the template localed :

 

// Custom action plugin named ‘common’

resources.FrontController.plugins.common        = "Zend_Controller_Plugin_Common"

 

[codesyntax lang=”php”]

// Custom action plugin Kbs_Controller_Plugin_Common
require_once('Zend/Controller/Plugin/Abstract.php');

class Kbs_Controller_Plugin_Common extends Zend_Controller_Plugin_Abstract
{
    // Route shut down action
    public function routeShutdown(Zend_Controller_Request_Abstract $request)
    {
        // Get module name for example admin, front etc.
        $module = $request->getModuleName();

        // Bootstrap object stored in front controller
        $bootstrap = Zend_Controller_Front::getInstance()->getParam('bootstrap');

        // Bootstrap resource view
        $bootstrap->bootstrap('View');
        $view = $bootstrap->getResource('View');
        $moduleParams = $view->$module;

        // Configurations of view
        $view->addBasePath($moduleParams['basePath'])
             ->addHelperPath($moduleParams['helperPath'],
                             $moduleParams['helperPathPrefix']);

        // Configurations of layout
        $bootstrap->bootstrap('Layout');
        $layout = $bootstrap->getResource('Layout');
        $layout->setLayoutPath($moduleParams['layoutPath'])
               ->setLayout($moduleParams['layout']);
    }
}

[/codesyntax]

 

Action plugin is the best method that I can think of since we can easily fetch module name when route shut down. Then we just need to fetch the infos of template (layout and scripts) from Application.ini depending on different modules.

 

Plugin resource Kbs_Application_Resource_View :

 

[codesyntax lang=”php”]

// Plugin resource view
class Kbs_Application_Resource_View extends Zend_Application_Resource_ResourceAbstract
{
    protected $_view;

    // init view
    public function init()
    {
        if (null === $this->_view) {
            // Options from Application.ini
            $options = $this->getOptions();
            $view = new Zend_View($options);
            if (!empty($options['params'])) {
                foreach ($options['params'] as $key => $value) {
                    $view->$key = $value;
                }
            }

            // ViewRenderer action helper
            $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper(
                'ViewRenderer'
            );

            // Save view object
            $viewRenderer->setView($view);
            $this->_view = $view;
        }        
        return $this->_view;
    }
}

[/codesyntax]

 

Everything is ok now except the contents of layout and scripts. Of course we can leave ttem to our design integration team.

 

In the example above we can easily change our template by replace :

 

resources.view.params.front.basePath            = APPLICATION_PATH "/templates/front/default/"
resources.view.params.front.layoutPath          = APPLICATION_PATH "/templates/front/default/layout"

 

by

 

resources.view.params.front.basePath            = APPLICATION_PATH "/templates/front/oceanStyle/"
resources.view.params.front.layoutPath          = APPLICATION_PATH "/templates/front/oceanStyle/layout"

 

Easy isn’t it? Ok, that’s all for how to build your multi-modules and multi-templates application with Zend_Application. 

 

What I didn’t mention here is Zend/Application/Module which is the third part of Zend_Application to deal with module bootstrap issues. Because it’s said that they will still be improved now and the furture before version 2.0. So let’s leave it now and wait for something better from Zend Framework 1.9.

 

Posted in Zend Framework | Tagged , | 2 Comments