7.3. Subclassing
Prev | Chapter 7. Zend_Controller | Next

## 7.3. Subclassing

### 7.3.1. Introduction

The `Zend_Controller` system was built with extensibility in mind, either by subclassing the existing classes or writing new classes that implement the interfaces `Zend_Controller_Router_Interface` and `Zend_Controller_Dispatcher_Interface`.

Possible reasons for implementing a new router or dispatcher might be:

- The existing URI routing system is not suitable in some way, such as integrating into an existing website that uses its own conventions for routing that do not mesh with the routing mechanism provided with the Zend Framework.

- You need to implement routing for something completely different. The `Zend_Controller_Router` class only deals with URIs. It's possible and likely that you might want to use the MVC pattern for developing another type of program, such as a console application. In the case of a console application, a custom router could process command line arguments to determine the route.

- The mechanism provided by `Zend_Controller_Dispatcher` is not suitable. The default configuration assumes a convention that controllers are classes and actions are methods of those classes. However, there are many other strategies for doing this. One example would be where controllers are directories and actions are files within those directories.

- You wish to provide additional capabilities that will be inherited by all of your controllers. For example, `Zend_Controller_Action` does not integrate with `Zend_View` by default. However, you could extend your own controller to do this, and using it would not require modifying the supplied `Zend_Controller_Router` or `Zend_Controller_Dispatcher`.

Please be careful when overriding significant parts of the system, particularly the dispatcher. One of the advantages of `Zend_Controller` is that it establishes common conventions for building applications. If too much of this default behavior is changed, some of these advantages are lost. However, there are many different needs and one solution can't fit them all, so the freedom is provided if needed.

### 7.3.2. Conventions

When subclassing any of the Zend_Controller classes, you are strongly encouraged to follow these conventions for naming or storing files. Doing so will ensure that another programmer who is familiar with the Zend Framework will be able to understand your project easily.

#### 7.3.2.1. Prefix

Classes included with the Zend Framework follow a convention where every class is prefixed by "Zend_". This is the prefix. We recommend that you name all of your classes in the same way, e.g. if your company name is Widget, Inc., the prefix might be "Widget_".

#### 7.3.2.2. Directory Layout

The `Zend_Controller` classes are stored in the library directory as follows:

    /library
      /Zend
        /Controller
          Action.php
          Dispatcher.php
          Router.php

When subclassing `Zend_Controller` classes, it is recommended that the new classes be stored in an identical structure under your prefix. This will make them easy to find for someone during that learning process of reviewing the code for your project.

For example, a project from Widget, Inc. which implements only a custom router might look like this:

    /library
      /Zend
      /Widget
        /Controller
          Router.php
          README.txt

Notice in this example that the `Widget/Controller/` directory mirrors the `Zend/Controller/` directory wherever possible. In this case, it provides the class `Widget_Controller_Router`, which would be either a subclass or replacement for `Zend_Controller_Router` implementing `Zend_Controller_Router_Interface`.

Also, notice in the example above that a `README.txt` file has been placed in `Widget/Controller/`. Zend strongly encourages you to document your projects through supplying separate tests and documentation for customers. However, we encourage you to also place a simple `README.txt` file right in the directory to briefly explain your changes and how they work.

### 7.3.3. Router Interface

The interface `Zend_Controller_Router_Interface` provides a definition for only one method:

    <?php

      /**
       * @param  Zend_Controller_Dispatcher_Interface
       * @throws Zend_Controller_Router_Exception
       * @return Zend_Controller_Dispatcher_Token|boolean
       */
      public function route(Zend_Controller_Dispatcher_Interface $dispatcher);

    ?>

Routing only occurs once: when the request is first received into the system. The purpose of the router is to generate a `Zend_Controller_Dispatch_Token` that specifies a controller and action of that controller. This is then passed to the dispatcher. If it is not possible to map a route to a dispatch token (nonsenical route) then a boolean, `FALSE`, should be returned.

Some routers may process dynamic elements and need a way to determine if the dispatch token generated is actually dispatchable before returning it. For this reason, the router receives the object handle of the dispatcher as the sole argument to its `route()` method. The dispatcher provides a method, `isDispatchable()`, for this testing.

### 7.3.4. Dispatcher Interface

`Zend_Controller_Front` will first call the router to receive the first dispatch token, which it will pass to the dispatcher. The dispatcher will dispatch the action (instantiate the controller, call its action) and then return with either a boolean, FALSE, or another dispatch token.

`Zend_Controller_Front` repeatedly calls the dispatcher until a dispatch token is not returned from it. This is known as the dispatch loop. It allows for actions to be processed sequentially until all work has been done.

The interface `Zend_Controller_Dispatcher_Interface` provides definitions for two methods:

    <?php

    /**
     * @param  Zend_Controller_Dispatcher_Token $route
     * @return boolean
     */
    public function isDispatchable(Zend_Controller_Dispatcher_Token $route);

    ?>

`isDispatchable()` checks if a dispatch token is dispatchable. If it is, it returns `TRUE`. Otherwise, it returns `FALSE`. The definition of what is dispatchable is left to the class implementing the interface. In the case of the default implementation, `Zend_Controller_Dispatcher`, it means that the controller file exists, the class exists within the file, and the action method exists within the class.

    <?php

    /**
     * @param  Zend_Controller_Dispatcher_Token $route
     * @return Zend_Controller_Dispatcher_Token|boolean
     */
    public function dispatch(Zend_Controller_Dispatcher_Token $route);

    ?>

`dispatch()` is where the work gets done. This method must execute the action of the controller. It must return either a dispatch token or a boolean, FALSE, to indicate that there is no more work to do.

Prev | Up | Next
7.2. Getting Started | Home | 7.4. Provided Subclasses