6.0.0-git
2024-04-25
Last Modified 2018-10-10 by Ralf Lang

Horde_Controller

Documentation on using Horde_Controller

General Info

Horde uses a lot of behind-the-scenes magic to glue together controller based request processing. In normal cases, the application developer only needs to create a routes configuration file entry and a controller class, horde will handle the rest.
To add custom pre and post filters to a controller, just add the corresponding $app_$controller_SettingsExporter class to the app/settings dir.
On this page, developers of specialised endpoints (RPC, REST, etc) can read up on how the pieces work together.

General flow of processing

A request object (Interface Horde_Request) is generated from server variables.
Some helper generates a Horde_Controller_RequestConfiguration instance (a config). The config defines which controller to execute and which SettingsExporter to use. The SettingsExporter affects which pre and post filters are run by the FilterRunner, among other things.
The request and the config are fed into a runner. The runner will return a response object. The runner may first execute prefilters on the request. Depending on the prefilter outcome, the originally defined controller may not be executed at all.
After the controller is run, post filters may change the response (for example, tidying output, applying compression)

Horde App specific flow of processing

Web Server configuration redirects any unmatched URLs to horde/rampage.php

rampage.php sets up a horde environment with auth and the horde base app

Get a Horde_Controller_Request_Http request object from running Horde_Core_Factory_Request
Get a Horde_Controller_Runner instance
Get a Horde_Core_Controller_RequestConfiguration from Horde_Core_Controller_RequestMapper::getRequestConfiguration
The first path component after the horde base app's webroot will be interpreted as the app name.
The remaining parts of the request uri are interpreted relative to the identified app's web root.
The requestMapper in turn will get a list of routes to match from app fileroot/config/routes.php
If no defined route matches, a default Horde_Core_Controller_NotFound is returned

Otherwise, a controller class name is found and the identified app's context is loaded ($registry->pushApp())
The controller class found is added to the RequestConfiguration.
The SettingsFinder looks for an $app_$controller_SettingsExporter class, otherwise it adds the Horde_Controller_SettingsExporter_Default to the config - which exports no filters or bindings to the runner

Let the runner create a $response = $runner->execute($injector, $request, $config);

Finally, get a responseWriter (_Web is the default) and render the response object to the output

How to use Horde_Controllers in Horde Core Apps

Horde Controllers are independent from the Horde Ajax Framework. Controllers need Horde_Routes and need rewrite rules.

Ajax application controllers do not live in lib/ but in $app/app/controllers/

Example:

Class Nag_CompleteTask_Controller in nag/app/controllers/CompleteTask.php

<?php
class Nag_CompleteTask_Controller extends Horde_Controller_Base
{
    public function processRequest(Horde_Controller_Request $request, Horde_Controller_Response $response)
    {
        /* Toggle the task's completion status if we're provided with a
         * valid task ID. */
        $requestVars = $request->getRequestVars();
        if (isset($requestVars['task']) && isset($requestVars['tasklist'])) {
            $nag_task = new Nag_CompleteTask();
            $result = $nag_task->result($requestVars['task'], $requestVars['tasklist']);
        } else {
            $result = array('error' => 'missing parameters');
        }

        $requestVars = $request->getGetVars();
        if (!empty($requestVars['format']) &&
            $requestVars['format'] == 'json') {
            $response->setContentType('application/json');
            $response->setBody(json_encode($result));
        } elseif ($requestVars['url']) {
            $response->setRedirectUrl($requestVars['url']);
        }
    }
}
?>

A Horde Controller based app needs a config/routes.php file.

For example

<?php
/**
 * Setup default routes
 */
$mapper->connect('/t/complete',
    array(
        'controller' => 'CompleteTask',
    ));
?>

defines a route for a call like www.example.com/nag/t/complete to be handled by the CompleteTask controller seen above.

The endpoint script is horde/rampage.php - rampage.php currently seems to handle only authenticated calls.

The controller is passed the request (in this case, a json request) and handles it (with a json answer in this case)