An Alternative to Zend_Controller

Zend Framework is very flexible and one of its strengths is that it allows developers to implement their own components. The Zend_Controller component, for example, is very powerful. Of course, it’s not my intention to replace it, but to offer an alternative that decreases the number of decisions a developer needs to make when developing an application.

Meet Zf_Controller. The Zf_Controller component has the following goals:

  • Abstract complexity: Try to reduce the level of details so the developer can focus on a few concepts at a time.
  • Emphasize Convention over Configuration: Emphasize CoC, meaning that the user only needs to specify unconventional aspects of the application.
  • Maintain backwards compatibility: Allow the developer to replace Zf_Controller with Zend_Controller in case the application grows in size or complexity.
  • Improve performance: Load less classes, execute less code.
  • Remove circular references: Avoid circular references.
  • Remove Singleton classes: Avoid implementing the Singleton pattern.
  • Research: Learn more about the framework, what it does, how it works.

Project Structure

Zend_Controller allows you to use the project structure that best suits your needs. On the other hand, Zf_Controller is more rigid, it only allows you to use the standard project structure:

project/
  app/
    config/
    controllers/
      ErrorController.php
      IndexController.php
    views/
      layouts/
      scripts/
        error/
        index/
          index.phtml
  domain/
    Model/
      Example.php
  lib/
    Zend/
    Zf/

Zf_Controller classes:

Zf/
  Controller/
    Action/
      Helper/
        Layout.php
    Action.php
    Front.php

Bootstrap File

Zend_Controller:

define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../app'));
set_include_path(APPLICATION_PATH . '/../lib'
    . PATH_SEPARATOR . get_include_path());

require_once "Zend/Loader.php";
Zend_Loader::registerAutoload();

$frontController = Zend_Controller_Front::getInstance();
$router = $frontController->getRouter();
$routes = include_once APPLICATION_PATH . '/config/routes.php';
$router->addRoutes($routes);

$layout = Zend_Layout::startMvc();
$layout->setLayoutPath(APPLICATION_PATH . '/views/layouts');

$frontController->dispatch();

Zf_Controller (no Router):

define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../app'));
set_include_path(APPLICATION_PATH . '/../lib'
    . PATH_SEPARATOR . APPLICATION_PATH . '/../domain);

require_once "Zend/Loader.php";
Zend_Loader::registerAutoload();

$frontController = new Zf_Controller_Front();
$frontController->setLayoutPath(APPLICATION_PATH . '/views/layouts');
$frontController->dispatch();

Action Controller

The default action controller and the default action are named “index”:

class IndexController extends Zf_Controller_Action
{
  public function indexAction()
  {}
}

Error Controller

Zend_Controller:

class ErrorController extends Zend_Controller_Action
{
  // Action used by Zend_Controller
  public function errorAction()
  {
    $error = $this->_getParam('error_handler');
    echo $error->exception->getMessage();
  }
}

Zf_Controller:

class ErrorController extends Zf_Controller_Action
{
  // Action used by Zf_Controller
  public function indexAction($e)
  {
    echo $e->getMessage();
  }
}

Rendering a View Script

Zf_Controller does not use the ViewRenderer helper class. To make the code more readable and testable, you need to call the render() method and return a value:

class IndexController extends Zf_Controller_Action
{
  public function indexAction()
  {
    $view = $this->initView();
    $view->message = 'Hello';

    // Renders views/scripts/index/index.phtml
    return $this->render();
  }

  public function testAction()
  {
    $view = $this->initView();
    $view->message = 'Goodbye';

    // Renders views/scripts/index/index.phtml
    return $this->render('index');
  }}

index.phtml file:

<p><?php echo $this->message ?></p>

Using a Layout

By setting the path to your layouts in the Bootstrap file, you automatically enable the default layout “layout.phtml”:

$frontController = new Zf_Controller_Front();
$frontController->setLayoutPath(APPLICATION_PATH . '/views/layouts');

To disable the layout:

class IndexController extends Zf_Controller_Action
{
    protected $_isLayoutEnabled = false;
}

To use a different layout:

class IndexController extends Zf_Controller_Action
{
    protected $_layoutScript = 'main.phtml';
}

main.phtml file:

<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<?php echo $this->headTitle() ?>
<?php echo $this->headScript() ?>
<?php echo $this->headStyle() ?>
</head>
<body>
<div id="content"><?php echo $this->layout()->content ?></div>
</body>
</html>

Source Code:
http://svn.fedecarg.com/repo/Zf/Controller/

About these ads

9 thoughts on “An Alternative to Zend_Controller

  1. Hi solomongaby,

    I haven’t benchmark any “Hello World” app yet. Only ZF components and my own app.

    Zf_Controller is lighter than Zend_Controller, it loads less classes. Anyway, that doesn’t mean your app will perform better, since all applications are different. It can help you squeeze more requests per second perhaps, or make your life easier :)

    I’ll release version 0.1 after documenting everything.

  2. Latest benchmark:

    – Hello World app: 25% faster (framework benchmark)
    – Custom app: 35% faster (app benchmark)

  3. Pingback: An Alternative to Zend_Controller: The Router

  4. Pingback: Making a custom front controller in Zend Framework | CodeUtopia

  5. @solomongaby, the Singleton pattern has lately become an antipattern in that it favors use of global symbols. Using a Singleton in other classes means hard coding components. There’s no way to replace that piece of the puzzle.

    Well, Matthew Weier O’Phinney has written a blog post in which he shows how to extend Zend_Controller_Front so that every place that makes a call to Zend_Controller_Front::getInstance() will actually get an instance of My_Controller_Front. IMO though, this is bad. It’s a deceiving API. One would expect an instance of ZCF whereas he actually gets an instance of My_Controller_Front.

    These being said… Federico, how did you solve the problem of hard coded calls to Zend_Controller_Front? Did you rewrite all the Zend_Controller package? Does it pass all ZF tests when plugged in the place of the shipped ZC package?

  6. Hi Ionut,

    > Did you rewrite all the Zend_Controller package?

    I think the biggest issue is:
    Zend_Controller_Action_Helper_Abstract

    At the moment I’m not using any of the action helper classes. However, if you want to avoid singletons, you can pass an instance of Zend_Controller_Front to Zend_Controller_Action, and Zend_Controller_Action to Zend_Controller_Action_Helper_Abstract.

  7. Pingback: An Alternative to Zend_Controller: The Model « fede.carg ( blog )

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s