Zend Controllers

The Zend Framework dispatches the provided URL to a controller action which reacts to that URL. The standard dispatch rules can be summarized as follows:

  1. The dispatcher examines the first segment of the URL and matches it against the names of the registered modules. Note that a default module may be used if no other module matches.
  2. The dispatcher then examines the next segment of the URL and matches it against the names of the controllers available in the directory bound to the module. So, if the segment is auth, it will look for a file named AuthController.php. By default, if there is no match, the IndexController.php file may be used (if it exists).
  3. The dispatcher then examines yet another segment of the URL and matches it against the names of the actions available in the controller class. So, if the segment is logout, it will look for a method named logoutAction. By default, if there is no matching, the indexAction may be used (if it exists).
  4. Any remaining parts of the URL are provided to the selected action.

So, basically, the initial configuration of the Zend Dispatcher will generate a set of URL prefixes which are bound to member functions of fresh instances of classes in the file system. This leads to the obvious question: what is that set of prefixes for my website?

In my case, the list would be:

-- module 'admin'
  -- controller 'auth'
    /admin/auth
    /admin/auth/logout
  -- controller 'help'
    /admin/help/page
  -- controller 'index'
    /admin/
  -- controller 'pages'
    /admin/pages
    /admin/pages/page
    /admin/pages/save
    /admin/pages/ajaxmove
    /admin/pages/ajaxrename
    /admin/pages/ajaxdelete
    /admin/pages/ajaxnew
  -- controller 'users'
    /admin/users
    /admin/users/ajaxnew
    /admin/users/ajaxdelete
    /admin/users/ajaxupdate
-- module 'public'
  -- controller 'index'
    /

So, for instance, /admin/pages/page/id/1 would forward /id/1 to the page action of the pages controller of the admin module, whereas /home/about-us would forward /home/about-us to the index action of the index controller of the public module (which is the default module).

The Tool

The above list was automatically generated by a tool. The core of that tool is this:

class _privateControllerExplorer {
  function __construct($modules, $default_module) {
    $this -> _modules = $modules;
    $this -> _default_module = $default_module;
  } 

  function explore($root_path) {
    $modules = array();
    foreach ($this -> _modules as $name => $path)
      $modules[$name] =
        array( "path" => $root_path . $path,
               "controllers" => $this -> explore_module($root_path . $path, $name));
    return $modules;
  } 

  private function explore_module($path, $module) {
    $uri = $module == $this -> _default_module ? '/' : "/$module/";
    $controllers = array();
    foreach (glob("$path/*Controller.php") as $controller) {
        $name = basename($controller);
        $name = str_replace('Controller.php', '', $name);
        $name{0} = strtolower($name{0});
        $controller_uri = $name === 'index' ? $uri : "$uri$name";
        $controllers[$name] =
          array( "path" => $controller,
                 "actions" => $this -> explore_controller($controller, $controller_uri));
      }
    return $controllers;
  } 

  private function explore_controller($path, $uri) {
    preg_match_all('%function[^a-zA-Z0-9_{]*([a-zA-Z0-9_]*)Action%',
                   @file_get_contents($path), $matches);
    $actions = array();
    foreach($matches[1] as $action)
      $actions[$action] = $uri . ($action == 'index' ? '' : '/' . $action);
    return $actions;
  }
} 

function explore_controllers($modules, $default_module, $root) {
  $explorer = new _privateControllerExplorer($modules, $default_module);
  return $explorer -> explore($root);
}

One should call the function defined at the bottom using the arguments:

  • The modules are a hash binding every module name to a directory where the controllers for that module are to be found. This is usually extracted quite easily from the configuration of your FrontController (where controller directories are bound to module names).
  • The default_module is the name of the default module (or null if there is no default module). This can also be found in the configuration of the FrontController.
  • The root is the absolute path to the position from where the controller directories are defined. That is, controller directories are assumed to be relative paths, and must be completed with the root path.

It should be fairly trivial to write a function which extracts that information from the FrontController.

The tool obviously makes a few assumptions. The first assumption is that the standard Zend dispatcher is used (otherwise, the rules for dispatching may not match what the tool is attempting to extract). The second assumption is that every controller file has a fairly simple layout : instead of intrusively interpreting the file in PHP (which may require the inclusion of other files and have side-effects) the tool merely processes it with a regular expression that could definitely use some improvement.

0 Responses to “Zend Controllers”


  1. No Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>



680 feed subscribers
(readers who polled a feed this week)