--- /dev/null
+<?php
+/**
+ * Interface for all controller objects
+ *
+ * @category Horde
+ * @package Horde_Controller
+ * @author James Pepin <james@bluestatedigital.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ */
+interface Horde_Controller
+{
+ public function processRequest(Horde_Controller_Request $request, Horde_Controller_Response $response);
+}
<?php
/**
- * Copyright 2007 Maintainable Software, LLC
- * Copyright 2008-2010 The Horde Project (http://www.horde.org/)
+ * Base class for controllers that implements the Logged, Injected, and Viewed
+ * interfaces.
*
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- */
-
-/**
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
+ * This class is for convenience, if you decide you wish to use only logging or
+ * the injector or views, or neither, you do not have to use it. As long as
+ * your controllers implement Horde_Controller, they are runnable.
+ *
+ * @category Horde
+ * @package Horde_Controller
+ * @author James Pepin <james@bluestatedigital.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
*/
-abstract class Horde_Controller_Base
+abstract class Horde_Controller_Base implements Horde_Controller
{
/**
- * Params is the list of variables set through routes.
- * @var Horde_Support_Array
- */
- protected $params;
-
- /**
- * Have we performed a render on this controller
- * @var boolean
- */
- protected $_performedRender = false;
-
- /**
- * Have we performed a redirect on this controller
- * @var boolean
- */
- protected $_performedRedirect = false;
-
- /**
- * The request object we are processing
- * @var Horde_Controller_Request_Base
- * @todo Assign default value.
- */
- protected $_request;
-
- /**
- * The response object we are returning
- * @var Horde_Controller_Response
- * @todo Assign default value.
- */
- protected $_response;
-
- /**
- * The current action being performed
- * @var string
- * @todo Assign default value.
- */
- protected $_action;
-
- /**
- * Normal methods available as action requests.
- * @var array
- */
- protected $_actionMethods = array();
-
- /**
- * @var string
- */
- protected $_viewsDir = '';
-
- /**
- * @var
- */
- protected $_urlWriter;
-
- /**
- * New controller instance
- */
- public function __construct($options = array())
- {
- foreach ($options as $key => $val) {
- $this->{'_' . $key} = $val;
- }
- }
-
- /**
- * Access to resources (request) and lazy loading of some (view).
+ * This is marked private on purpose, so that you have to use the
+ * getInjector() method to access it in derived classes. This is done so
+ * that you don't assume its always set, since its set via setter-injection
+ * to save on having to define a constructor param for it
*
- * @param string $name Property to access
+ * @var Horde_Injector
*/
- public function __get($name)
- {
- switch ($name) {
- case 'request':
- return $this->_request;
-
- case '_view':
- $this->_view = new Horde_View;
- return $this->_view;
- }
- }
+ private $_injector;
/**
- * Process the {@link Horde_Controller_Request_Base} and return
- * the {@link Horde_Controller_Response}. This is the method that is called
- * for every request to be processed. It then determines which action to call
- * based on the parameters set within the {@link Horde_Controller_Request_Base}
- * object.
- *
- * <code>
- * <?php
- * ...
- * $request = new Horde_Controller_Request_Base();
- * $response = new Horde_Controller_Response_Base();
- *
- * $response = $controller->process($request, $response);
- * ...
- * ?>
- * </code>
+ * Private on purpose so you have to use getLogger().
*
- * @param Horde_Controller_Request_Base $request
- * @param Horde_Controller_Response_Base $response
- * @return Horde_Controller_Response_Base
- */
- public function process(Horde_Controller_Request_Base $request, Horde_Controller_Response_Base $response)
- {
- $this->_request = $request;
- $this->_response = $response;
-
- $this->_initParams();
-
- $this->_shortName = str_replace('Controller', '', $this->params[':controller']);
-
- try {
- // templates
- $this->_initActionMethods();
- $this->_initViewPaths();
- $this->_initViewHelpers();
-
- // Initialize application logic used through all actions
- $this->_initializeApplication();
- if ($this->_performed()) {
- return $this->_response;
- }
-
- // Initialize sub-controller logic used through all actions
- if (is_callable(array($this, '_initialize'))) {
- $this->_initialize();
- }
-
- // pre filters
-
- // execute action & save any changes to sessionData
- $this->{$this->_action}();
-
- // post filters
-
- // render default if we haven't performed an action yet
- if (!$this->_performed()) {
- $this->render();
- }
- } catch (Exception $e) {
- // error handling
- throw $e;
- }
-
- return $this->_response;
- }
-
- /**
+ * @var Horde_Log_Logger
*/
- protected function interpretStatus($status)
- {
- return Horde_Controller_StatusCodes::interpret($status);
- }
+ private $_logger;
/**
- * Generate a URL
- * @see Horde_Controller_UrlWriter
+ * Private on purpose so you have to use getView().
*
- * @param string|array $first named route, string, or options array
- * @param array $second options array (if not in $first)
- * @return string generated url
+ * @var Horde_View
*/
- protected function urlFor($first = array(), $second = array())
- {
- return $this->getUrlWriter()->urlFor($first, $second);
- }
+ private $_view;
/**
- * Get an instance of UrlWriter for this controller.
+ * Set the injector for this controller
*
- * @return Horde_Controller_UrlWriter
- */
- public function getUrlWriter()
- {
- // instantiate UrlWriter that will generate URLs for this controller
- if (!$this->_urlWriter) {
- $defaults = array('controller' => $this->getControllerName());
- $this->_urlWriter = new Horde_Controller_UrlWriter($defaults);
- }
- return $this->_urlWriter;
- }
-
- /**
- * Get the current controller's name.
+ * @inject
*
- * @return string
+ * @param Horde_Injector The injector that this controller should use to create objects
*/
- protected function getControllerName()
+ public function setInjector(Horde_Injector $injector)
{
- if (empty($this->params)) {
- $this->_initParams();
- }
-
- return $this->params[':controller'];
+ $this->_injector = $injector;
}
/**
- * Render the response to the user. Actions are automatically rendered if no other
- * action is specified.
- *
- * <code>
- * <?php
- * ...
- * $this->render(array('text' => 'some text to render'));
- * $this->render(array('action' => 'actionName'));
- * $this->render(array('nothing' => 1));
- * ...
- * ?>
- * </code>
- *
- * @see renderText()
- * @see renderAction()
- * @see renderNothing()
+ * Get the injector for this controller
*
- * @param array $options
- *
- * @throws Horde_Controller_Exception
+ * @return Horde_Injector The injector previously set for this controller,
+ * or a new Horde_Injector_TopLevel
*/
- protected function render($options = array())
+ public function getInjector()
{
- // should not render/redirect more than once.
- if ($this->_performed()) {
- throw new Horde_Controller_Exception("Double render error: \"$this->_action\"");
- }
-
- // validate options
-
- // set response status
- if (!empty($options['status'])) {
- $header = $this->interpretStatus($options['status']);
- $this->_response->setStatus($header);
- }
-
- // set response location
- if (!empty($options['location'])) {
- $url = $this->urlFor($options['location']);
- $this->_response->setHeader("Location: $url", $replace = true);
- }
-
- // render text
- if (!empty($options['text'])) {
- $this->renderText($options['text']);
-
- // render xml
- } elseif (!empty($options['xml'])) {
- $this->_response->setContentType('application/xml');
-
- $xml = $options['xml'];
- if (is_object($xml) && method_exists($xml, 'toXml')) {
- $xml = $xml->toXml();
- }
-
- $this->renderText($xml);
-
- // render template file
- } elseif (!empty($options['action'])) {
- $this->renderAction($options['action']);
-
- // render empty body
- } elseif (!empty($options['nothing'])) {
- $this->renderText('');
-
- // render default template
- } else {
- $this->renderAction($this->_action);
+ if ($this->_injector) {
+ return $this->_injector;
}
+ return new Horde_Injector_TopLevel();
}
/**
- * Render text directly to the screen without using a template
+ * Set the Logger for this controller
*
- * <code>
- * <?php
- * ...
- * $this->renderText('some text to render to the screen');
- * ...
- * ?>
- * </code>
+ * @inject
*
- * @param string $text
+ * @param Horde_Log_Logger The logger to use for this controller
*/
- protected function renderText($text)
+ public function setLogger(Horde_Log_Logger $logger)
{
- $this->_response->setBody($text);
- $this->_performedRender = true;
+ $this->_logger = $logger;
}
/**
- * The name of the action method will render by default.
- *
- * render 'listDocuments' template file
- * <code>
- * <?php
- * ...
- * $this->renderAction('listDocuments');
- * ...
- * ?>
- * </code>
+ * Get the logger assigned to this controller
*
- * @param string $name
+ * @return Horde_Log_Logger The logger for this controller
*/
- protected function renderAction($name)
+ public function getLogger()
{
- // current url
- $this->_view->currentUrl = '/' . $this->_request->getUri();
-
- // copy instance variables
- foreach (get_object_vars($this) as $key => $value) {
- $this->_view->$key = $value;
- }
-
- // add suffix
- if ($this->_actionConflict) {
- $name = str_replace('Action', '', $name);
- }
- if (strpos($name, '.') === false) {
- $name .= '.html.php';
- }
-
- // prepend this controller's "short name" only if the action was
- // specified without a controller "short name".
- // e.g. index -> Shortname/index
- // Shortname/index -> Shortname/index
- if (strpos($name, '/') === false) {
- // $name = $this->_shortName . '/' . $name;
+ if ($this->_logger) {
+ return $this->_logger;
}
-
- if ($this->_useLayout) {
- $this->_view->contentForLayout = $this->_view->render($name);
- $text = $this->_view->render($this->_layoutName);
- } else {
- $text = $this->_view->render($name);
- }
- $this->renderText($text);
- }
-
- /**
- * Render blank content. This can be used anytime you want to send a 200 OK
- * response back to the user, but don't need to actually render any content.
- * This is mostly useful for ajax requests.
- *
- * <code>
- * <?php
- * ...
- * $this->renderNothing();
- * ...
- * ?>
- * </code>
- */
- protected function renderNothing()
- {
- $this->renderText('');
+ return new Horde_Log_Logger(new Horde_Log_Handler_Null());
}
/**
- * Set the layout template for the controller. Specify the name of the file in
- * the /app/views/layouts directory without the .html extension
+ * Set the Horde_View object to be used for this controller
*
- * <code>
- * <?php
- * ...
- * public function _initialize()
- * {
- * $this->setLayout('application');
- * }
- * ...
- * ?>
- * </code>
+ * @inject
*
- * @param string $layoutName
+ * @param Horde_View_Base The view object
*/
- protected function setLayout($layoutName)
+ public function setView(Horde_View_Base $view)
{
- $this->_useLayout = true;
- $this->_layoutName = $layoutName;
+ $this->_view = $view;
}
/**
- * Check if a render or redirect has been performed
- * @return boolean
- */
- protected function _performed()
- {
- return $this->_performedRender || $this->_performedRedirect;
- }
-
- /**
- * Each variable set through routing {@link Horde_Routes_Mapper} is
- * available in controllers using the $params array.
+ * Gets the current view for this controller
*
- * The controller also has access to GET/POST arrays using $params
- *
- * The action method to be performed is stored in $this->params[':action'] key
- */
- protected function _initParams()
- {
- $this->params = new Horde_Support_Array($this->_request->getParameters());
- $this->_action = $this->params->get(':action');
- }
-
- /**
- * Set the list of public actions that are available for this Controller.
- * Subclasses can remove methods from being publicly called by calling
- * {@link hideAction()}.
- *
- * @throws Horde_Controller_Exception
- */
- protected function _initActionMethods()
- {
- // Perform reflection to get the list of public methods
- $reflect = new ReflectionClass($this);
- $methods = $reflect->getMethods();
- foreach ($methods as $m) {
- if ($m->isPublic() && !$m->isConstructor() && !$m->isDestructor() &&
- $m->getName() != 'process' && substr($m->getName(), 0, 1) != '_') {
- $this->_actionMethods[$m->getName()] = 1;
- }
- }
-
- // try action suffix.
- if (!isset($this->_actionMethods[$this->_action]) &&
- isset($this->_actionMethods[$this->_action.'Action'])) {
- $this->_actionConflict = true;
- $this->_action = $this->_action.'Action';
- }
- // action isn't set, but there is a methodMissing() catchall method
- if (!isset($this->_actionMethods[$this->_action]) &&
- isset($this->_actionMethods['methodMissing'])) {
- $this->_action = 'methodMissing';
-
- // make sure we have an action set, and that there is no methodMissing() method
- } elseif (!isset($this->_actionMethods[$this->_action]) &&
- !isset($this->_actionMethods['methodMissing'])) {
- $msg = 'Missing action: '.get_class($this)."::".$this->_action;
- throw new Horde_Controller_Exception($msg);
- }
- }
-
- /**
- * Initialize the view paths where the templates reside for this controller.
- * These are added in FIFO order, so if we do $this->renderAction('foo'),
- * in the BarController, the order it will search these directories will be:
- * 1. /views/Bar/foo.html
- * 2. /views/shared/foo.html
- * 3. /views/layouts/foo.html
- * 4. /views/foo.html (the default)
+ * @note This method will create an empty Horde_View if none has been set.
*
- * We can specify a directory to look in instead of relying on the default order
- * by doing $this->renderAction('shared/foo').
+ * @return Horde_View_Base The view for this controller, or a new empty
+ * Horde_View if none is set
*/
- protected function _initViewPaths()
+ public function getView()
{
- $this->_view->addTemplatePath($this->_viewsDir . 'layouts');
- $this->_view->addTemplatePath($this->_viewsDir . 'shared');
- $this->_view->addTemplatePath($this->_viewsDir . $this->_shortName);
- }
-
- /**
- * Initialize the default helpers for use in the views
- */
- protected function _initViewHelpers()
- {
- $controllerHelper = $this->_shortName . 'Helper';
- if (class_exists($controllerHelper)) {
- new $controllerHelper($this->_view);
+ if ($this->_view) {
+ return $this->_view;
}
+ return new Horde_View();
}
-
- /**
- * This gets called before action is performed in a controller.
- * Override method in subclass to setup filters/helpers
- */
- protected function _initializeApplication()
- {
- }
-
}
+++ /dev/null
-<?php
-/**
- * Copyright 2007 Maintainable Software, LLC
- * Copyright 2008-2010 The Horde Project (http://www.horde.org/)
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- */
-
-/**
- * Dispatch a request to the appropriate controller and execute the response.
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- */
-class Horde_Controller_Dispatcher
-{
- /** @var Horde_Controller_Dispatcher */
- private static $_instance;
-
- /** @var Horde_Routes_Mapper */
- protected $_mapper;
-
- /** @var Horde_Log_Logger */
- protected $_logger;
-
- /** @var Horde_Support_Inflector */
- protected $_inflector;
-
- /** @var string */
- protected $_controllerDir = '';
-
- /** @var string */
- protected $_viewsDir = '';
-
- /**
- * Singleton method. This should be the only way of instantiating a
- * Horde_Controller_Dispatcher object.
- *
- * @return Horde_Controller_Dispatcher
- */
- public static function singleton($context = array())
- {
- if (self::$_instance === null) {
- self::$_instance = new self($context);
- }
- return self::$_instance;
- }
-
- /**
- * Class constructor. Client code should use the singleton method to
- * instantiate objects.
- */
- protected function __construct($context)
- {
- if (!isset($context['mapper']) || ! $context['mapper'] instanceof Horde_Routes_Mapper) {
- $context['mapper'] = new Horde_Routes_Mapper();
- $context['mapper']->connect('/:controller/:action/:id');
- }
-
- foreach ($context as $key => $val) {
- $this->{'_' . $key} = $val;
- }
-
- // Make sure controller directory, if set, ends in a /.
- if ($this->_controllerDir && substr($this->_controllerDir, -1) != '/') {
- $this->_controllerDir .= '/';
- }
-
- // Set the mapper's controller directory and controllerScan
- if ($this->_controllerDir && !$this->_mapper->directory) {
- $this->_mapper->directory = $this->_controllerDir;
- }
- $scanner = new Horde_Controller_Scanner($this->_mapper);
- $this->_mapper->controllerScan = $scanner->getCallback();
-
- // Make sure views directory, if set, ends in a /.
- if ($this->_viewsDir && substr($this->_viewsDir, -1) != '/') {
- $this->_viewsDir .= '/';
- }
-
- // Make sure we have an inflector
- if (!$this->_inflector) {
- $this->_inflector = new Horde_Support_Inflector();
- }
- }
-
- /**
- * Get the route utilities for this dispatcher and its mapper.
- *
- * @return Horde_Routes_Utils
- */
- public function getRouteUtils()
- {
- return $this->_mapper->utils;
- }
-
- /**
- * Dispatch the request to the correct controller.
- *
- * @param Horde_Controller_Request_Base $request
- */
- public function dispatch(Horde_Controller_Request_Base $request, $response = null)
- {
- $t = new Horde_Support_Timer();
- $t->push();
-
- if (! $response instanceof Horde_Controller_Response_Base) {
- $response = new Horde_Controller_Response_Http();
- // $response = new Horde_Controller_Response_Base();
- }
-
- // Recognize routes and process request
- $controller = $this->recognize($request);
- $response = $controller->process($request, $response);
-
- // Send response and log request
- $time = $t->pop();
- $this->_logRequest($request, $time);
- $response->send();
- }
-
- /**
- * Check if request path matches any Routes to get the controller
- *
- * @return Horde_Controller_Base
- * @throws Horde_Controller_Exception
- */
- public function recognize($request)
- {
- $path = $request->getPath();
- if (substr($path, 0, 1) != '/') {
- $path = '/' . $path;
- }
-
- $matchdata = $this->_mapper->match($path);
- if ($matchdata) {
- $hash = $this->formatMatchdata($matchdata);
- }
-
- if (empty($hash) || !isset($hash[':controller'])) {
- $msg = 'No routes match the path: "' . $request->getPath() . '"';
- throw new Horde_Controller_Exception($msg);
- }
-
- $request->setPathParams($hash);
-
- // try to load the class
- $controllerName = $hash[':controller'];
- if (!class_exists($controllerName, false)) {
- $path = $this->_controllerDir . str_replace('_', '/', $controllerName) . '.php';
- if (file_exists($path)) {
- require $path;
- } else {
- $msg = "The Controller \"$controllerName\" does not exist at " . $path;
- throw new Horde_Controller_Exception($msg);
- }
- }
-
- $options = array(
- 'viewsDir' => $this->_viewsDir,
- );
- return new $controllerName($options);
- }
-
- /**
- * Take the $matchdata returned by a Horde_Routes_Mapper match and add
- * in :controller and :action that are used by the rest of the framework.
- *
- * Format controller names: my_stuff => MyStuffController
- * Format action names: action_name => actionName
- *
- * @param array $matchdata
- * @return mixed false | array
- */
- public function formatMatchdata($matchdata)
- {
- $ret = array();
- foreach ($matchdata as $key => $val) {
- if ($key == 'controller') {
- $ret[':controller'] = $this->_inflector->camelize($val) . 'Controller';
- } elseif ($key == 'action') {
- $ret[':action'] = $this->_inflector->camelize($val, 'lower');
- } elseif ($key == 'module') {
- $ret[':module'] = $this->_inflector->camelize($val);
- }
-
- $ret[$key] = $val;
- }
-
- if (!empty($ret[':module'])) {
- $ret[':controller'] = $ret[':module'] . '_' . $ret[':controller'];
- }
-
- return !empty($ret) && isset($ret['controller']) ? $ret : false;
- }
-
- /**
- * Log the http request
- *
- * @todo - get total query times
- *
- * @param Horde_Controller_Request_Base $request
- * @param int $totalTime
- */
- protected function _logRequest(Horde_Controller_Request_Base $request, $totalTime)
- {
- if (!is_callable(array($this->_logger, 'info'))) {
- return;
- }
-
- $queryTime = 0; // total time to execute queries
- $queryCount = 0; // total queries performed
- $phpTime = $totalTime - $queryTime;
-
- // embed user info in log
- $uri = $request->getUri();
- $method = $request->getMethod();
-
- $paramStr = 'PARAMS=' . $this->_formatLogParams($request->getParameters());
-
- $msg = "$method $uri $totalTime ms (DB=$queryTime [$queryCount] PHP=$phpTime) $paramStr";
- $msg = wordwrap($msg, 80, "\n\t ", 1);
-
- $this->_logger->info($msg);
- }
-
- /**
- * Formats the request parameters as a "key => value, key => value, ..." string
- * for the log file.
- *
- * @param array $params
- * @return string
- */
- protected function _formatLogParams($params)
- {
- $paramStr = '{';
- $count = 0;
- foreach ($params as $key => $value) {
- if ($key != 'controller' && $key != 'action' &&
- $key != ':controller' && $key != ':action') {
- if ($count++ > 0) { $paramStr .= ', '; }
-
- $paramStr .= $key.' => ';
-
- if (is_array($value)) {
- $paramStr .= $this->_formatLogParams($value);
- } elseif (is_object($value)) {
- $paramStr .= get_class($value);
- } else {
- $paramStr .= $value;
- }
- }
- }
- return $paramStr . '}';
- }
-
-}
+++ /dev/null
-<?php
-/**
- * Copyright 2007 Maintainable Software, LLC
- * Copyright 2008-2010 The Horde Project (http://www.horde.org/)
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- */
-
-/**
- * A file upload from multipart form
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- */
-class Horde_Controller_FileUpload
-{
- public $originalFilename = null;
- public $length = null;
- public $contentType = null;
- public $path = null;
-
- public function __construct($options)
- {
- $this->originalFilename = isset($options['name']) ? $options['name'] : null;
- $this->length = isset($options['size']) ? $options['size'] : null;
- $this->contentType = isset($options['type']) ? $options['type'] : null;
- $this->path = isset($options['tmp_name']) ? $options['tmp_name'] : null;
- }
-
-}
--- /dev/null
+<?php
+/**
+ * Filter to gzip content before being served
+ *
+ * @category Horde
+ * @package Horde_Controller
+ * @author James Pepin <james@bluestatedigital.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Controller_Filter_Gzip implements Horde_Controller_PostFilter
+{
+ public function processResponse(Horde_Controller_Request $request, Horde_Controller_Response $response, Horde_Controller $controller)
+ {
+ $body = $response->getBody();
+ $body = gzencode($body);
+
+ $response->setHeader('Content-Encoding', 'gzip');
+ $response->setHeader('Content-Length', $this->_byteCount($body));
+ $response->setBody($body);
+
+ return $response;
+ }
+
+ /**
+ * If mbstring is set to overload str* function then we could be counting
+ * multi-byte chars as single bytes so we need to treat the string like its
+ * 8-bit encoded to get an accurate byte count.
+ */
+ protected function _byteCount($string)
+ {
+ if (ini_get('mbstring.func_overload') > 0) {
+ return mb_strlen($string, '8bit');
+ }
+
+ return strlen($string);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Interface for an object that houses a collection of pre/post filters.
+ *
+ * @category Horde
+ * @package Horde_Controller
+ * @author James Pepin <james@bluestatedigital.com>
+ * @author Bob McKee <bob@bluestatedigital.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ */
+interface Horde_Controller_FilterCollection
+{
+ /**
+ */
+ public function addPreFilter(Horde_Controller_PreFilter $filter);
+
+ /**
+ */
+ public function addPostFilter(Horde_Controller_PostFilter $filter);
+}
--- /dev/null
+<?php
+/**
+ * Collects filters and executes them around a controller
+ *
+ * @category Horde
+ * @package Horde_Controller
+ * @author Bob McKee <bob@bluestatedigital.com>
+ * @author James Pepin <james@bluestatedigital.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Controller_FilterRunner implements Horde_Controller_FilterCollection
+{
+ /**
+ * @var Horde_Controller
+ */
+ protected $_controller;
+
+ /**
+ * @var array
+ */
+ protected $_preFilters = array();
+
+ /**
+ * @var array
+ */
+ protected $_postFilters = array();
+
+ /**
+ */
+ public function __construct(Horde_Controller $controller)
+ {
+ $this->_controller = $controller;
+ }
+
+ /**
+ * Append filter to prefilters array
+ *
+ * @param Horde_Controller_PreFilter $filter
+ */
+ public function addPreFilter(Horde_Controller_PreFilter $filter)
+ {
+ array_push($this->_preFilters, $filter);
+ }
+
+ /**
+ * Prepend fitler to postfilters array
+ *
+ * @param Horde_Controller_PostFilter $filter
+ */
+ public function addPostFilter(Horde_Controller_PostFilter $filter)
+ {
+ array_unshift($this->_postFilters, $filter);
+ }
+
+ /**
+ * Executes filters and controller method. Execution happens in the following order:
+ *
+ * - Run processRequest() on prefilters in first-in-first-out order
+ * - Run processRequest() on controller
+ * - Run processResponse() on postfilters in first-in-last-out order
+ *
+ * @param Horde_Controller_Request $request
+ * @param Horde_Controller_Response $response
+ *
+ * @return Horde_Controller_Response
+ */
+ public function processRequest(Horde_Controller_Request $request, Horde_Controller_Response $response)
+ {
+ if ($this->_applyPreFilters($request, $response) !== Horde_Controller_PreFilter::REQUEST_HANDLED) {
+ $this->_controller->processRequest($request, $response);
+ $this->_applyPostFilters($request, $response);
+ }
+ return $response;
+ }
+
+ /**
+ */
+ protected function _applyPreFilters(Horde_Controller_Request $request, Horde_Controller_Response $response)
+ {
+ foreach ($this->_preFilters as $filter) {
+ if ($filter->processRequest($request, $response, $this->_controller) === Horde_Controller_PreFilter::REQUEST_HANDLED) {
+ return Horde_Controller_PreFilter::REQUEST_HANDLED;
+ }
+ }
+
+ return Horde_Controller_PreFilter::REQUEST_CONTINUE;
+ }
+
+ /**
+ */
+ protected function _applyPostFilters(Horde_Controller_Request $request, Horde_Controller_Response $response)
+ {
+ foreach ($this->_postFilters as $filter) {
+ $filter->processResponse($request, $response, $this->_controller);
+ }
+ }
+}
+++ /dev/null
-<?php
-/**
- * Copyright 2007 Maintainable Software, LLC
- * Copyright 2008-2010 The Horde Project (http://www.horde.org/)
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- * @subpackage Response
- */
-
-/**
- * Handles managing of what types of responses the client can handle and which
- * one was requested.
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- * @subpackage Response
- */
-class Horde_Controller_Mime_Type
-{
- public $symbol;
- public $synonyms;
- public $string;
-
- public static $set = array();
- public static $lookup = array();
- public static $extensionLookup = array();
- public static $registered = false;
-
- public function __construct($string, $symbol = null, $synonyms = array())
- {
- $this->string = $string;
- $this->symbol = $symbol;
- $this->synonyms = $synonyms;
- }
-
- public function __toString()
- {
- return $this->symbol;
- }
-
- public static function lookup($string)
- {
- if (!empty(self::$lookup[$string])) {
- return self::$lookup[$string];
- } else {
- return null;
- }
- }
-
- public static function lookupByExtension($ext)
- {
- if (!empty(self::$extensionLookup[$ext])) {
- return self::$extensionLookup[$ext];
- } else {
- return null;
- }
- }
-
- public static function register($string, $symbol, $synonyms = array(), $extSynonyms = array())
- {
- $type = new Horde_Controller_Mime_Type($string, $symbol, $synonyms);
- self::$set[] = $type;
-
- // add lookup strings
- foreach (array_merge((array)$string, $synonyms) as $string) {
- self::$lookup[$string] = $type;
- }
-
- // add extesnsion lookups
- foreach (array_merge((array)$symbol, $extSynonyms) as $ext) {
- self::$extensionLookup[$ext] = $type;
- }
- }
-
- /**
- * @todo - actually parse the header. This is simply mocked out
- * with common types for now
- */
- public static function parse($acceptHeader)
- {
- $types = array();
-
- if (strstr($acceptHeader, 'text/javascript')) {
- if (isset(self::$extensionLookup['js'])) {
- $types[] = self::$extensionLookup['js'];
- }
-
- } elseif (strstr($acceptHeader, 'text/html')) {
- if (isset(self::$extensionLookup['html'])) {
- $types[] = self::$extensionLookup['html'];
- }
-
- } elseif (strstr($acceptHeader, 'text/xml')) {
- if (isset(self::$extensionLookup['xml'])) {
- $types[] = self::$extensionLookup['xml'];
- }
-
- // default to html
- } else {
- if (isset(self::$extensionLookup['html'])) {
- $types[] = self::$extensionLookup['html'];
- }
- }
- return $types;
- }
-
- /**
- * Register mime types
- * @todo - move this elsewhere?
- */
- public static function registerTypes()
- {
- if (!self::$registered) {
- Horde_Controller_Mime_Type::register('*/*', 'all');
- Horde_Controller_Mime_Type::register('text/plain', 'text', array(), array('txt'));
- Horde_Controller_Mime_Type::register('text/html', 'html', array('application/xhtml+xml'), array('xhtml'));
- Horde_Controller_Mime_Type::register('text/javascript', 'js', array('application/javascript', 'application/x-javascript'), array('xhtml'));
- Horde_Controller_Mime_Type::register('application/json', 'json');
- Horde_Controller_Mime_Type::register('text/xml', 'rss');
- Horde_Controller_Mime_Type::register('application/atom+xml', 'atom');
- Horde_Controller_Mime_Type::register('text/csv', 'csv');
- Horde_Controller_Mime_Type::register('application/xml', 'xml', array('text/xml', 'application/x-xml'));
- self::$registered = true;
- }
- }
-
-}
--- /dev/null
+<?php
+/**
+ * Null controller object. Useful for filter tests that don't use the
+ * controller object.
+ *
+ * @category Horde
+ * @package Horde_Controller
+ * @author Bob McKee <bob@bluestatedigital.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Controller_Null implements Horde_Controller
+{
+ public function processRequest(Horde_Controller_Request $request, Horde_Controller_Response $response)
+ {
+ }
+}
--- /dev/null
+<?php
+/**
+ * Interface for filters that are executed after the controller has generated the response
+ *
+ * @category Horde
+ * @package Horde_Controller
+ * @author James Pepin <james@bluestatedigital.com>
+ * @author Bob McKee <bob@bluestatedigital.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ */
+interface Horde_Controller_PostFilter
+{
+ public function processResponse(Horde_Controller_Request $request, Horde_Controller_Response $response, Horde_Controller $controller);
+}
--- /dev/null
+<?php
+/**
+ * Interface for filers to be run before the controller is executed
+ *
+ * @category Horde
+ * @package Horde_Controller
+ * @author James Pepin <james@bluestatedigital.com>
+ * @author Bob McKee <bob@bluestatedigital.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ */
+interface Horde_Controller_PreFilter
+{
+ const REQUEST_HANDLED = true;
+ const REQUEST_CONTINUE = false;
+
+ public function processRequest(Horde_Controller_Request $request, Horde_Controller_Response $response, Horde_Controller $controller);
+}
--- /dev/null
+<?php
+/**
+ * Interface for a request object
+ *
+ * @category Horde
+ * @package Horde_Controller
+ * @author James Pepin <james@bluestatedigital.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ */
+interface Horde_Controller_Request
+{
+ /**
+ */
+ public function getPath();
+
+ /**
+ */
+ public function getMethod();
+
+ /**
+ */
+ public function getGetVars();
+
+ /**
+ */
+ public function getFileVars();
+
+ /**
+ */
+ public function getServerVars();
+
+ /**
+ */
+ public function getPostVars();
+
+ /**
+ */
+ public function getCookieVars();
+
+ /**
+ */
+ public function getRequestVars();
+
+ /**
+ */
+ public function getSessionId();
+}
+++ /dev/null
-<?php
-/**
- * Copyright 2007 Maintainable Software, LLC
- * Copyright 2008-2010 The Horde Project (http://www.horde.org/)
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- * @subpackage Request
- *
- * http://pythonpaste.org/webob/
- * http://usrportage.de/archives/875-Dojo-and-the-Zend-Framework.html
- * http://framework.zend.com/manual/en/zend.filter.input.html
- * http://www.lornajane.net/posts/2009/Adding-PUT-variables-to-Request-Object-in-Zend-Framework
- */
-
-/**
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- * @subpackage Request
- */
-abstract class Horde_Controller_Request_Base
-{
- /**
- * Request timestamp
- *
- * @var integer
- */
- protected $_timestamp;
-
- /**
- * The SAPI
- *
- * @var string
- */
- protected $_sapi;
-
- /**
- * Unique id per request.
- * @var string
- */
- protected $_requestId;
-
- protected $_server;
- protected $_env;
-
- protected $_body;
-
- /**
- */
- public function __construct($options = array())
- {
- $this->_initRequestId();
-
- $this->_server = isset($options['server']) ? $options['server'] : $_SERVER;
- $this->_env = isset($options['env']) ? $options['env'] : $_ENV;
-
- if (isset($_SERVER['REQUEST_TIME'])) {
- $this->_timestamp = $_SERVER['REQUEST_TIME'];
- } else {
- $this->_timestamp = time();
- }
-
- $this->_sapi = php_sapi_name();
- }
-
- /**
- * Get request timestamp
- *
- * @return integer
- */
- public function getTimestamp()
- {
- return $this->_timestamp;
- }
-
- /**
- * Get server variable with the specified $name
- *
- * @param string $name
- * @return string
- */
- public function getServer($name)
- {
- if ($name == 'SCRIPT_NAME' && strncmp($this->_sapi, 'cgi', 3) === 0) {
- $name = 'SCRIPT_URL';
- }
- return isset($this->_server[$name]) ? $this->_server[$name] : null;
- }
-
- /**
- * Get environment variable with the specified $name
- *
- * @param string $name
- * @return string
- */
- public function getEnv($name)
- {
- return isset($this->_env[$name]) ? $this->_env[$name] : null;
- }
-
- /**
- * Get a combination of all parameters. We have to do
- * some wacky loops to make sure that nested values in one
- * param list don't overwrite other nested values
- *
- * @return array
- */
- public function getParameters()
- {
- $allParams = array();
- $paramArrays = array($this->_pathParams, $this->_formattedRequestParams);
-
- foreach ($paramArrays as $params) {
- foreach ((array)$params as $key => $value) {
- if (!is_array($value) || !isset($allParams[$key])) {
- $allParams[$key] = $value;
- } else {
- $allParams[$key] = array_merge($allParams[$key], $value);
- }
- }
- }
- return $allParams;
- }
-
- /**
- * Get entire list of parameters set by {@link Horde_Controller_Route_Path} for
- * the current request
- *
- * @return array
- */
- public function getPathParams()
- {
- return $this->_pathParams;
- }
-
- /**
- * When the {@link Horde_Controller_Dispatcher} determines the
- * correct {@link Horde_Controller_Route_Path} to match the url, it uses the
- * Routing object data to set appropriate variables so that they can be passed
- * to the Controller object.
- *
- * @param array $params
- */
- public function setPathParams($params)
- {
- $this->_pathParams = !empty($params) ? $params : array();
- }
-
- /**
- * Get the unique ID generated for this request
- * @see _initRequestId()
- * @return string
- */
- public function getRequestId()
- {
- return $this->_requestId;
- }
-
- /**
- * The request body
- *
- * @TODO Allow overriding php://input, and make the default interface to
- * return an SplFileObject, or a (doesn't currently exist) Horde_File
- * object, instead of the raw data.
- *
- * @return string
- */
- public function getBody()
- {
- if (!isset($this->_body)) {
- $this->_body = file_get_contents('php://input');
- }
- return $this->_body;
- }
-
- /**
- * Return the request content length
- *
- * @return int
- */
- public function getContentLength()
- {
- return strlen($this->getBody());
- }
-
- /**
- * Turn this request into a URL-encoded query string.
- */
- public function __toString()
- {
- return http_build_query($this);
- }
-
- abstract public function getPath();
-
- /**
- * Uniquely identify each request from others. This aids in threading
- * related log requests during troubleshooting on a busy server
- */
- private function _initRequestId()
- {
- $this->_requestId = (string)new Horde_Support_Uuid;
- }
-}
+++ /dev/null
-<?php
-/**
- * Copyright 2007 Maintainable Software, LLC
- * Copyright 2008-2010 The Horde Project (http://www.horde.org/)
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- * @subpackage Request
- */
-
-/**
- * Represents a command line request invocation.
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- * @subpackage Request
- */
-class Horde_Controller_Request_Cli extends Horde_Controller_Request_Base
-{
- /**
- * Command line arguments
- */
- protected $_argv;
-
- /**
- * Constructor
- *
- * In addition to the $options from Horde_Controller_Request_Base, you can
- * pass a 'path' argument as a string, or a Horde_Argv_Parser object as
- * 'argvParser' to override the path of the cli request.
- */
- public function __construct($options = array())
- {
- parent::__construct($options);
-
- $pathArgs = null;
- if (isset($options['path'])) {
- $pathArgs = $options['path'];
- } elseif (isset($options['argvParser'])) {
- $pathArgs = $options['argvParser'];
- }
-
- $this->setPath($pathArgs);
- }
-
- public function getUri()
- {
- return $this->getPath();
- }
-
- public function getMethod()
- {
- return 'CLI';
- }
-
- public function setArgv($args)
- {
- $this->_argv = $args;
- }
-
- public function getPath()
- {
- return $this->_path;
- }
-
- public function setPath($args = null)
- {
- if (is_string($args)) {
- $this->_path = $args;
- } else {
- if ($args instanceof Horde_Argv_Parser) {
- $parser = $args;
- } else {
- $parser = new Horde_Argv_Parser(array(
- 'allowUnknownArgs' => true,
- 'addHelpOption' => false,
- ));
- }
-
- list($this->_argv, $args) = $parser->parseArgs();
- if (!count($args)) {
- throw new Horde_Controller_Exception('unknown command: ' . implode(' ', $args));
- }
- $this->_path = $args[0];
- $this->_path = str_replace('-', '_', $this->_path);
- }
- }
-
- /**
- * Get all command line parameters.
- * some wacky loops to make sure that nested values in one
- * param list don't overwrite other nested values
- *
- * @return array
- */
- public function getParameters()
- {
- $allParams = array();
- $paramArrays = array($this->_pathParams, $this->_argv);
-
- foreach ($paramArrays as $params) {
- foreach ((array)$params as $key => $value) {
- if (!is_array($value) || !isset($allParams[$key])) {
- $allParams[$key] = $value;
- } else {
- $allParams[$key] = array_merge($allParams[$key], $value);
- }
- }
- }
- return $allParams;
- }
-
-}
<?php
/**
- * Copyright 2007 Maintainable Software, LLC
- * Copyright 2008-2010 The Horde Project (http://www.horde.org/)
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- * @subpackage Request
+ * @category Horde
+ * @package Horde_Controller
+ * @author James Pepin <james@bluestatedigital.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
*/
-
-/**
- * Represents an HTTP request to the server. This class handles all
- * headers/cookies/session data so that it all has one point of entry for being
- * written/retrieved.
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- * @subpackage Request
- */
-class Horde_Controller_Request_Http extends Horde_Controller_Request_Base
+class Horde_Controller_Request_Http implements Horde_Controller_Request
{
+ protected $_path;
+
/**
* All the headers.
* @var array
*/
protected $_headers = null;
- /**
- * PHPSESSID
- * @var string
- */
- protected $_sessionId;
-
- // superglobal arrays
- protected $_get;
- protected $_post;
- protected $_files;
- protected $_request;
-
- // cookie/session info
- protected $_cookie;
- protected $_session;
-
- protected $_contentType;
- protected $_accepts;
- protected $_format;
- protected $_method;
- protected $_remoteIp;
- protected $_port;
- protected $_https;
- protected $_isAjax;
-
- protected $_domain;
- protected $_uri;
- protected $_pathParams;
-
/*##########################################################################
# Construct/Destruct
##########################################################################*/
- /**
- * Request is populated with all the superglobals from page request if
- * data is not passed in.
- *
- * @param array $options Associative array with all superglobals
- */
- public function __construct($options = array())
- {
- try {
- if (!empty($options['session_control']) && $options['session_control'] != 'none') {
- $this->_initSessionData();
- }
-
- // register default mime types
- Horde_Controller_Mime_Type::registerTypes();
-
- // superglobal data if not passed in thru constructor
- $this->_get = isset($options['get']) ? $options['get'] : $_GET;
- $this->_post = isset($options['post']) ? $options['post'] : $_POST;
- $this->_cookie = isset($options['cookie']) ? $options['cookie'] : $_COOKIE;
- $this->_request = isset($options['request']) ? $options['request'] : $_REQUEST;
-
- parent::__construct($options);
-
- $this->_pathParams = array();
- //$this->_formattedRequestParams = $this->_parseFormattedRequestParameters();
-
- // use FileUpload object to store files
- $this->_setFilesSuperglobals();
-
- // disable all superglobal data to force us to use correct way
- //@TODO
- //$_GET = $_POST = $_FILES = $_COOKIE = $_REQUEST = $_SERVER = array();
-
- $this->_domain = $this->getServer('SERVER_NAME');
- $this->_uri = trim($this->getServer('REQUEST_URI'), '/');
- $this->_method = $this->getServer('REQUEST_METHOD');
- // @TODO look at HTTP_X_FORWARDED_FOR, handling multiple addresses: http://weblogs.asp.net/james_crowley/archive/2007/06/19/gotcha-http-x-forwarded-for-returns-multiple-ip-addresses.aspx
- $this->_remoteIp = $this->getServer('REMOTE_ADDR');
- $this->_port = $this->getServer('SERVER_PORT');
- $this->_https = $this->getServer('HTTPS') || $this->getServer('SSL_PROTOCOL') || $this->getServer('HTTP_X_CLUSTER_SSL');
- $this->_isAjax = $this->getServer('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest';
- } catch (Exception $e) {
- $this->_malformed = true;
- $this->_exception = $e;
- }
- }
-
-
- /*##########################################################################
- # Public Methods
- ##########################################################################*/
-
- /**
- * Get the http request method:
- * eg. GET, POST, PUT, DELETE
- *
- * @return string
- */
- public function getMethod()
- {
- $methods = array('GET', 'HEAD', 'PUT', 'POST', 'DELETE', 'OPTIONS');
-
- if ($this->_method == 'POST') {
- $params = $this->getParameters();
- if (isset($params['_method'])) {
- $faked = strtoupper($params['_method']);
- if (in_array($faked, $methods)) return $faked;
- }
- }
-
- return $this->_method;
- }
-
- /**
- * Get list of all superglobals to pass into a different request
- *
- * @return array
- */
- public function getGlobals()
- {
- return array('get' => $this->_get,
- 'post' => $this->_post,
- 'cookie' => $this->_cookie,
- 'session' => $this->_session,
- 'files' => $this->_files,
- 'request' => $this->_request,
- 'server' => $this->_server,
- 'env' => $this->_env);
- }
-
- /**
- * Get the domain for the current request
- * eg. https://www.maintainable.com/articles/show/123
- * $domain is -> www.maintainable.com
- *
- * @return string
- */
- public function getDomain()
+ public function __construct($path)
{
- return $this->_domain;
+ $this->_path = $path;
}
- /**
- * Get the host for the current request
- * eg. http://www.maintainable.com:3000/articles/show/123
- * $host is -> http://www.maintainablesoftware.com:3000
- *
- * @param boolean $usePort
- * @return string
- */
- public function getHost($usePort = false)
- {
- $scheme = 'http' . ($this->_https == 'on' ? 's' : null);
- $port = $usePort && !empty($this->_port) && $this->_port != '80' ? ':' . $this->_port : null;
- return "{$scheme}://{$this->_domain}$port";
- }
- /**
- * @todo add ssl support
- * @return string
- */
- public function getProtocol()
- {
- // return $this->getServer('SERVER_PROTOCOL');
- return 'http://';
- }
-
- /**
- * Get the uri for the current request
- * eg. https://www.maintainable.com/articles/show/123?page=1
- * $uri is -> articles/show/123?page=1
- *
- * @return string
- */
- public function getUri()
- {
- return $this->_uri;
- }
-
- /**
- * Get the path from the URI. (strip get params)
- * eg. https://www.maintainable.com/articles/show/123?page=1
- * $path is -> articles/show/123
- *
- * @return string
- */
public function getPath()
{
- $path = $this->_uri;
- if (strstr($path, '?')) {
- $path = trim(substr($path, 0, strpos($path, '?')), '/');
- }
- return $path;
- }
-
- public function getContentType()
- {
- if (!isset($this->_contentType)) {
- $type = $this->getServer('CONTENT_TYPE');
- // strip parameters from content-type like "; charset=UTF-8"
- if (is_string($type)) {
- if (preg_match('/^([^,\;]*)/', $type, $matches)) {
- $type = $matches[1];
- }
- }
-
- $this->_contentType = Horde_Controller_Mime_Type::lookup($type);
- }
- return $this->_contentType;
- }
-
- /**
- * @return array
- */
- public function getAccepts()
- {
- if (!isset($this->_accepts)) {
- $accept = $this->getServer('HTTP_ACCEPT');
- if (empty($accept)) {
- $types = array();
- $contentType = $this->getContentType();
- if ($contentType) { $types[] = $contentType; }
- $types[] = Horde_Controller_Mime_Type::lookupByExtension('all');
- $accepts = $types;
- } else {
- $accepts = Horde_Controller_Mime_Type::parse($accept);
- }
- $this->_accepts = $accepts;
- }
- return $this->_accepts;
+ return $this->_path;
}
-
- /**
- * Returns the Mime type for the format used in the request. If there is no
- * format available, the first of the
- *
- * @return string
- */
- public function getFormat()
- {
- if (!isset($this->_format)) {
- $params = $this->getParameters();
- if (isset($params['format'])) {
- $this->_format = Horde_Controller_Mime_Type::lookupByExtension($params['format']);
- } else {
- $this->_format = current($this->getAccepts());
- }
- }
- return $this->_format;
- }
-
- /**
- * Get the remote Ip address as a dotted decimal string.
- *
- * @return string
- */
- public function getRemoteIp()
+ public function getMethod()
{
- return $this->_remoteIp;
+ $serverVars = $this->getServerVars();
+ return $serverVars['REQUEST_METHOD'];
}
/**
- * Get cookie value from specified $name OR get All when $name isn't passed in
+ * Gets the request variables GET, POST, COOKIE, SERVER, REQUEST etc.
*
- * @param string $name
- * @param string $default
- * @return string
+ * @param string $name The name of the superglobal whose vars to return
*/
- public function getCookie($name=null, $default=null)
+ protected function getVars($name)
{
- if (isset($name)) {
- return isset($this->_cookie[$name]) ? $this->_cookie[$name] : $default;
- } else {
- return $this->_cookie;
- }
+ return $GLOBALS['_' . $name];
}
- /**
- * Get session value from session data by $name or ALL when $name isn't passed in
- *
- * @param string $name
- * @param string $default
- * @return mixed
- */
- public function getSession($name=null, $default=null)
+ public function getGetVars()
{
- if (isset($name)) {
- return isset($this->_session[$name]) ? $this->_session[$name] : $default;
- } else {
- return $this->_session;
- }
+ return $this->getVars('GET');
}
- /**
- * Get entire list of $_COOKIE parameters
- *
- * @return array
- */
- public function getCookieParams()
+ public function getFileVars()
{
- return $this->_cookie;
+ return $this->getVars('FILES');
}
- /**
- * Get entire list of $_SERVER parameters
- *
- * @return array
- */
- public function getServerParams()
+ public function getServerVars()
{
- return $this->_server;
+ return $this->getVars('SERVER');
}
- /**
- * Get a combination of all parameters. We have to do
- * some wacky loops to make sure that nested values in one
- * param list don't overwrite other nested values
- *
- * @return array
- */
- public function getParameters()
+ public function getPostVars()
{
- $allParams = array();
- $paramArrays = array($this->_pathParams, /*$this->_formattedRequestParams, */
- $this->_get, $this->_post, $this->_files);
-
- foreach ($paramArrays as $params) {
- foreach ((array)$params as $key => $value) {
- if (!is_array($value) || !isset($allParams[$key])) {
- $allParams[$key] = $value;
- } else {
- $allParams[$key] = array_merge($allParams[$key], $value);
- }
- }
- }
- return $allParams;
+ return $this->getVars('POST');
}
- /**
- * Get entire list of $_GET parameters
- * @return array
- */
- public function getGetParams()
+ public function getCookieVars()
{
- return $this->_get;
+ return $this->getVars('COOKIE');
}
- /**
- * Get entire list of $_POST parameters
- *
- * @return array
- */
- public function getPostParams()
+ public function getRequestVars()
{
- return $this->_post;
+ return $this->getVars('REQUEST');
}
- /**
- * Get entire list of $_FILES parameters
- *
- * @return array
- */
- public function getFilesParams()
- {
- return $this->_files;
- }
-
- /**
- * Get the session ID of this request (PHPSESSID)
- * @see _initSession()
- * @return string
- */
public function getSessionId()
{
- return $this->_sessionId;
- }
-
-
- /*##########################################################################
- # Modifiers
- ##########################################################################*/
-
- /**
- * Set the uri and parse it for useful info
- *
- * @param string $uri
- */
- public function setUri($uri)
- {
- $this->_uri = trim($uri, '/');
- }
-
- /**
- * Set the session array.
- *
- * @param string $name
- * @param mixed $value
- */
- public function setSession($name, $value=null)
- {
- if (is_array($name)) {
- $this->_session = $name;
- } else {
- $this->_session[$name] = $value;
- }
- }
-
-
- /*##########################################################################
- # Private Methods
- ##########################################################################*/
-
- /**
- * Start up default session storage, and get stored data.
- *
- * @todo further investigate session_cache_limiter() on ie6 (see below)
- * @todo implement active record session store
- */
- protected function _initSessionData()
- {
- $this->_sessionId = session_id();
-
- if (! strlen($this->_sessionId)) {
- // internet explorer 6 will ignore the filename/content-type during
- // sendfile over ssl unless session_cache_limiter('public') is set
- // http://joseph.randomnetworks.com/archives/2004/10/01/making-ie-accept-file-downloads/
- $agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
- if (strpos($agent, 'MSIE') !== false) {
- session_cache_limiter("public");
- }
-
- session_start();
- $this->_sessionId = session_id();
- }
-
- // Important: Setting "$this->_session = $_SESSION" does NOT work.
- $this->_session = array();
- if (is_array($_SESSION)) {
- foreach ($_SESSION as $key => $value) {
- $this->_session[$key] = $value;
- }
- }
- }
-
- /**
- * Initialize the File upload information
- */
- protected function _setFilesSuperglobals()
- {
- if (empty($_FILES)) {
- $this->_files = array();
- return;
- }
- $_FILES = array_map(array($this, '_fixNestedFiles'), $_FILES);
-
- // create FileUpload object of the file options
- foreach ((array)$_FILES as $name => $options) {
- if (isset($options['tmp_name'])) {
- $this->_files[$name] = new Horde_Controller_FileUpload($options);
- } else {
- foreach ($options as $attr => $data) {
- $this->_files[$name][$attr] = new Horde_Controller_FileUpload($data);
- }
- }
- }
- }
-
- /**
- * fix $_FILES superglobal array. (PHP mungles data when we use brackets)
- *
- * @link http://www.shauninman.com/archive/2006/11/30/fixing_the_files_superglobal
- * @param array $group
- */
- protected function _fixNestedFiles($group)
- {
- // only rearrange nested files
- if (!is_array($group['tmp_name'])) { return $group; }
-
- foreach ($group as $property => $arr) {
- foreach ($arr as $item => $value) {
- $result[$item][$property] = $value;
- }
- }
- return $result;
+ //TODO: how do we get session ID?
+ //should probably be passing it in the constructor, or via setSession
+ //we should definitely lazy-load sessions though cause we don't always care about it
+ //perhaps a preFilter to start the session if the controller requests it, and then call setSession on the request
+ //object
+ return 0;
}
/**
return $result;
}
-
}
+++ /dev/null
-<?php
-/**
- * Copyright 2007 Maintainable Software, LLC
- * Copyright 2008-2010 The Horde Project (http://www.horde.org/)
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- * @subpackage Request
- */
-
-/**
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- * @subpackage Request
- */
-class Horde_Controller_Request_Mock extends Horde_Controller_Request_Base
-{
- public function getPath()
- {
- }
-}
--- /dev/null
+<?php
+/**
+ * Null request object.
+ *
+ * Useful for filter tests that don't use the request object.
+ *
+ * @category Horde
+ * @package Horde_Controller
+ * @author Bob McKee <bob@bluestatedigital.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Controller_Request_Null implements Horde_Controller_Request
+{
+ /**
+ */
+ public function getMethod()
+ {
+ }
+
+ /**
+ */
+ public function getPath()
+ {
+ }
+
+ /**
+ */
+ public function getParameters()
+ {
+ }
+
+ /**
+ */
+ public function getGetVars()
+ {
+ }
+
+ /**
+ */
+ public function getFileVars()
+ {
+ }
+
+ /**
+ */
+ public function getServerVars()
+ {
+ }
+
+ /**
+ */
+ public function getPostVars()
+ {
+ }
+
+ /**
+ */
+ public function getCookieVars()
+ {
+ }
+
+ /**
+ */
+ public function getRequestVars()
+ {
+ }
+
+ /**
+ */
+ public function getSessionId()
+ {
+ }
+}
--- /dev/null
+<?php
+/**
+ * @category Horde
+ * @package Horde_Controller
+ * @author Bob McKee <bob@bluestatedigital.com>
+ * @author James Pepin <james@bluestatedigital.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ */
+interface Horde_Controller_RequestConfiguration
+{
+ public function getControllerName();
+
+ public function setControllerName($controllerName);
+
+ public function getSettingsExporterName();
+
+ public function setSettingsExporterName($settingsName);
+}
--- /dev/null
+<?php
+/**
+ * @category Horde
+ * @package Horde_Controller
+ * @author James Pepin <james@bluestatedigital.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Controller_Response
+{
+ protected $_headers = array();
+ protected $_body;
+ protected $_requestConfiguration;
+
+ public function __construct()
+ {
+ }
+
+ public function setHeaders(array $headers)
+ {
+ $this->_headers = array_merge($this->_headers, $headers);
+ }
+
+ public function setHeader($name, $value)
+ {
+ $this->_headers[$name] = $value;
+ }
+
+ public function setBody($body)
+ {
+ $this->_body = $body;
+ }
+
+ public function getHeaders()
+ {
+ return $this->_headers;
+ }
+
+ public function getBody()
+ {
+ return $this->_body;
+ }
+
+ public function internalRedirect()
+ {
+ return $this->_requestConfiguration != null;
+ }
+
+ public function setRedirectUrl($url)
+ {
+ $this->_headers['Location'] = $url;
+ }
+
+ public function getRedirectConfiguration()
+ {
+ return $this->_requestConfiguration;
+ }
+
+ public function setRedirectConfiguration(Horde_Controller_RequestConfiguration $config)
+ {
+ $this->_requestConfiguration = $config;
+ }
+}
+++ /dev/null
-<?php
-/**
- * Copyright 2007 Maintainable Software, LLC
- * Copyright 2008-2010 The Horde Project (http://www.horde.org/)
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- * @subpackage Response
- */
-
-/**
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- * @subpackage Response
- */
-class Horde_Controller_Response_Base
-{
- protected $_body = '';
-
- /**
- */
- public function send()
- {
- echo $this->_body;
- }
-
- public function setBody($body)
- {
- $this->_body = $body;
- }
-}
+++ /dev/null
-<?php
-/**
- * Copyright 2007 Maintainable Software, LLC
- * Copyright 2008-2010 The Horde Project (http://www.horde.org/)
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- * @subpackage Response
- */
-
-/**
- * @TODO Allow specifying the stream where output is going instead of assuming
- * STDOUT.
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- * @subpackage Response
- */
-class Horde_Controller_Response_Cli extends Horde_Controller_Response_Base
-{
- /**
- * @var stream
- */
- protected $_stream;
-
- public function construct()
- {
- $this->_stream = fopen('php://stdout');
- }
-
- /**
- * Writes a string to the Response stream
- *
- * Can be called with an array of parameters or with a variable number of
- * parameters like printf.
- *
- * @param string $string The string to write to the reponse stream
- * @param array|params $params The parameters to replace in the string (think printf)
- */
- public function write($string, $params = null)
- {
- if (!is_array($params)) {
- $params = func_get_args();
- array_shift($params);
- }
- fwrite($this->_stream, vsprintf($string, $params));
- }
-
- /**
- * Writes a newline-terminated string to the Response stream
- *
- * Can be called with an array of parameters or with a variable number of
- * parameters like printf.
- *
- * @param string $string The string to write to the reponse stream
- * @param array|params $params The parameters to replace in the string (think printf)
- */
- public function writeLn($string, $params = array())
- {
- if (!is_array($params)) {
- $params = func_get_args();
- array_shift($params);
- }
- $line = vsprintf($string, $params);
- if (substr($line, -1) != "\n") {
- $line .= "\n";
- }
- fwrite($this->_stream, $line);
- }
-}
+++ /dev/null
-<?php
-/**
- * Copyright 2007 Maintainable Software, LLC
- * Copyright 2008-2010 The Horde Project (http://www.horde.org/)
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- * @subpackage Response
- */
-
-/**
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- * @subpackage Response
- */
-class Horde_Controller_Response_Http extends Horde_Controller_Response_Base
-{
- /**
- * Cookies sent with response
- * @var array
- */
- protected $_cookie = array();
-
- /**
- * Stored session data
- * @var array
- */
- protected $_session = array();
-
- /**
- * The url to redirect the request to
- * @var string
- */
- protected $_redirectUrl = null;
-
- /**
- * The http status code. Default to OK
- * @var string
- */
- protected $_status = '200 OK';
-
- /**
- * HTTP headers to send
- * @var array
- */
- protected $_headers = array();
-
- /**
- * prevent cached content (ie)
- * @var array
- */
- protected $_preventCache = true;
-
- /**
- * Body of the rendered page
- * @var string
- */
- protected $_body = null;
-
-
- /*##########################################################################
- # Construct
- ##########################################################################*/
-
- /**
- * Construct response
- */
- public function __construct(){}
-
-
- /*##########################################################################
- # Instance methods
- ##########################################################################*/
-
- /**
- * Set the url for redirection
- *
- * @param string $toUrl
- */
- public function redirect($toUrl)
- {
- /* Alternate 301 branch - should allow choosing status:
- $this->_status = '301 Moved Permanently';
- $this->_redirectUrl = $toUrl;
- $this->_headers["Location: $toUrl"] = true;
- $this->_headers["Connection: close"] = true;
- */
-
- $this->_status = '302 Found';
- $this->_redirectUrl = $toUrl;
- $this->_headers["Location: $toUrl"] = true;
- }
-
- /**
- * Page was not found
- */
- public function pageNotFound()
- {
- $this->_status = '404 Page Not Found';
- }
-
- /**
- * Send content to the browser.
- *
- * After the body content has been sent, terminates the execution of the
- * PHP script.
- */
- public function send()
- {
- // send all headers
- foreach ($this->getHeaders() as $header => $replace) {
- header($header, $replace);
- }
-
- // set cookies
- foreach ($this->_cookie as $name => $options) {
- setcookie($name, $options['value'], $options['expiration'], $options['path']);
- }
-
- // set session data
- foreach ($this->_session as $name => $value) {
- $_SESSION[$name] = $value;
- }
-
- // send body
- print $this->getBody();
- }
-
-
- /*##########################################################################
- # Accessors
- ##########################################################################*/
-
- /**
- * Set a cookie
- *
- * @param string $name
- * @param string $value
- * @param int $expiration
- * @param string $path
- */
- public function setCookie($name, $value, $expiration=0, $path=null)
- {
- // only set cookies for this matter by default
- $this->_cookie[$name] = array('value' => $value,
- 'expiration' => $expiration,
- 'path' => isset($path) ? $path : '/');
- }
-
- /**
- * Set a session variable OR all session variables (by array).
- *
- * <code>
- * // set single session var
- * $this->setSession('NAME', 'my session');
- *
- * // set all session vars (overwrites previous single sessions set)
- * $this->setSession(array('NAME 1' => 'my session 1',
- * 'NAME 2' => 'my session 2'));
- * </code>
- *
- * @param mixed $name
- * @param mixed $value
- */
- public function setSession($name, $value=null)
- {
- // Set by name or all at once
- if (is_string($name)) {
- $this->_session[$name] = $value;
- } elseif (is_array($name)) {
- $this->_session = $name;
- }
- }
-
- /**
- * Add header information
- *
- * @param string $header
- * @param boolean $replace
- */
- public function setHeader($header, $replace=true)
- {
- $this->_headers[$header] = $replace;
- }
-
- /**
- * Set the body of the response
- *
- * @param string $body
- */
- public function setBody($body)
- {
- $this->_body = $body;
- }
-
- /**
- * Set the HTTP status code
- *
- * @param string $status
- */
- public function setStatus($status)
- {
- $this->_status = $status;
- }
-
- /**
- * Get the headers of the response
- *
- * @return array
- */
- public function getHeaders()
- {
- $headers["HTTP/1.1 $this->_status"] = true;
-
- if ($this->_status == '200 OK') {
- $headers["Connection: close"] = true;
- $headers["Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"] = true;
-
- // Try to keep browser from caching any screen to ensure current data.
- if ($this->_preventCache && !isset($this->_headers["Expires: 0"])) {
- $headers["Expires: Mon, 26 Jul 1997 05:00:00 GMT"] = true;
- $headers["Cache-Control: no-store, no-cache, must-revalidate"] = true;
- $headers["Pragma: no-cache"] = true;
- }
- }
- return array_merge($this->_headers, $headers);
- }
-
- /**
- * Get the body of the response
- *
- * @return string
- */
- public function getBody()
- {
- return $this->_body;
- }
-
- /**
- * Get the HTTP status of the response
- *
- * @return string
- */
- public function getStatus()
- {
- return $this->_status;
- }
-
- /**
- * Get 3 digit http code from the status
- *
- * @return int
- */
- public function getStatusCode()
- {
- preg_match("/(\d\d\d)/", $this->_status, $matches);
- return isset($matches[1]) ? (int) $matches[1] : 0;
- }
-
- /**
- * @todo charset
- */
- public function setContentType($mimeType)
- {
- $this->setHeader("Content-Type: $mimeType", $replace=true);
- }
-
- /**
- * Get if the response is a 200 OK
- *
- * @return boolean
- */
- public function isOk()
- {
- return substr($this->_status, 0, 1) == '2';
- }
-
- /**
- * Get if the response is a redirection
- *
- * @return boolean
- */
- public function isRedirect()
- {
- return substr($this->_status, 0, 1) == '3';
- }
-
- /**
- * Get where the page is redirecting to
- *
- * @return string
- */
- public function getRedirectUrl()
- {
- return $this->_redirectUrl;
- }
-}
+++ /dev/null
-<?php
-/**
- * Copyright 2007 Maintainable Software, LLC
- * Copyright 2008-2010 The Horde Project (http://www.horde.org/)
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- * @subpackage Response
- */
-
-/**
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- * @subpackage Response
- */
-class Horde_Controller_Response_Mock extends Horde_Controller_Response_Base
-{
-}
--- /dev/null
+<?php
+/**
+ * @category Horde
+ * @package Horde_Controller
+ * @author James Pepin <james@bluestatedigital.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ */
+interface Horde_Controller_ResponseWriter
+{
+ public function writeResponse(Horde_Controller_Response $response);
+}
--- /dev/null
+<?php
+/**
+ * @category Horde
+ * @package Horde_Controller
+ * @author James Pepin <james@bluestatedigital.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Controller_ResponseWriter_Web implements Horde_Controller_ResponseWriter
+{
+ /**
+ */
+ public function writeResponse(Horde_Controller_Response $response)
+ {
+ foreach ($response->getHeaders() as $key => $value) {
+ header("$key: $value");
+ }
+ echo $response->getBody();
+ }
+}
--- /dev/null
+<?php
+/**
+ * @category Horde
+ * @package Horde_Controller
+ * @author James Pepin <james@bluestatedigital.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Controller_ResponseWriter_WebDebug implements Horde_Controller_ResponseWriter
+{
+ public function writeResponse(Horde_Controller_Response $response)
+ {
+ $headerHtml = '<div><strong>Headers:</strong><pre>';
+ $headers = $response->getHeaders();
+ foreach ($headers as $key => $value) {
+ $headerHtml .= "$key: $value\n";
+ }
+ echo htmlspecialchars($headerHtml) . '</pre></div>';
+
+ if ($headers['Location']) {
+ echo '<p>Redirect To: <a href="' . htmlspecialchars($headers['Location']) . '">' . htmlspecialchars($headers['Location']) . '</a></p>';
+ }
+
+ if (isset($headers['Content-Encoding']) && $headers['Content-Encoding'] == 'gzip') {
+ // Strip off the header and inflate it
+ echo gzinflate(substr($response->getBody(), 10));
+ } else {
+ echo $response->getBody();
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Class to execute the controller request
+ *
+ * @category Horde
+ * @package Horde_Controller
+ * @author James Pepin <james@bluestatedigital.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Controller_Runner
+{
+ protected $_logger;
+
+ public function __construct(Horde_Log_Logger $logger)
+ {
+ $this->_logger = $logger;
+ }
+
+ public function execute(Horde_Injector $injector, Horde_Controller_Request $request, Horde_Controller_RequestConfiguration $config)
+ {
+ $this->_logger->debug('RequestConfiguration in Horde_Controller_Runner: ' . print_r($config, true));
+
+ $exporter = $injector->getInstance($config->getSettingsExporterName());
+ $exporter->exportBindings($injector);
+
+ $controller = $config->getControllerName();
+ if (!$controller) {
+ throw new Horde_Controller_Exception('No controller defined');
+ }
+
+ $implementationBinder = new Horde_Injector_Binder_Implementation($controller);
+ $injector->addBinder('Horde_Controller', new Horde_Injector_Binder_AnnotatedSetters($implementationBinder));
+
+ $filterRunner = $injector->createInstance('Horde_Controller_FilterRunner');
+ $exporter->exportFilters($filterRunner, $injector);
+
+ $response = $filterRunner->processRequest($request, $injector->createInstance('Horde_Controller_Response'));
+ if ($response->internalRedirect()) {
+ $this->_logger->debug('Internal redirect');
+ return $this->execute($injector->createChildInjector(), $request, $response->getRedirectConfiguration());
+ }
+
+ $this->_logger->debug('Returning Horde_Controller_Response');
+ return $response;
+ }
+}
+++ /dev/null
-<?php
-/**
- * Copyright 2007 Maintainable Software, LLC
- * Copyright 2008-2010 The Horde Project (http://www.horde.org/)
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- */
-
-/**
- * Horde_Routes_Mapper requires a list of all possible controller names
- * in order to build the regular expressions it uses for matching routes.
- * It uses a callback, controllerScan, to get this list.
- *
- * Depending on the routes connected to the mapper, it may be possible to
- * determine all of the controller names from the routes themselves. If
- * not, the filesystem must be scanned to determine the controller names.
- *
- * This class contains two controllerScan strategies, one that scans the
- * filesystem and one that doesn't, and can determine the most efficient
- * strategy to use for a given mapper.
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @author Derek DeVries <derek@maintainable.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @license http://opensource.org/licenses/bsd-license.php
- * @category Horde
- * @package Horde_Controller
- */
-class Horde_Controller_Scanner
-{
- /**
- * @var Horde_Routes_Mapper
- */
- protected $_mapper;
-
- /**
- * controllerScan strategy selected for this mapper.
- * @var callback
- */
- protected $_callback;
-
- /**
- * Array of controller names collected from route hardcodes
- * @var array
- */
- protected $_controllers;
-
-
- /**
- * Constructor. Analyze the routes connected to this mapper to
- * select a controllerScan strategy.
- *
- * @param Horde_Routes_Mapper
- */
- public function __construct($mapper)
- {
- $this->_mapper = $mapper;
- $this->analyze();
- }
-
- /**
- * Analyze the routes connected to the mapper. If all of the possible
- * controller names can be determined from the routes themselves, select
- * the scanHardcodes() strategy that returns them collected from the
- * routes. If the possible controller names cannot be determined this
- * way, select the scanFilesystem() strategy.
- */
- public function analyze()
- {
- $needScan = false;
- $controllers = array();
- foreach ($this->_mapper->matchList as $route) {
- if (in_array('controller', $route->hardCoded)) {
- $controllers[ $route->defaults['controller'] ] = true;
- } else {
- $needScan = true;
- break;
- }
- }
- $this->_controllers = array_keys($controllers);
-
- if ($needScan || empty($this->_controllers)) {
- $this->_callback = array($this, 'scanFilesystem');
- } else {
- $this->_callback = array($this, 'scanHardcodes');
- }
- }
-
- /**
- * Get the controllerScan callback stategy selected for this mapper.
- *
- * @return callback
- */
- public function getCallback()
- {
- return $this->_callback;
- }
-
- /**
- * Scan a directory and return an array of the controllers it contains.
- * The array is used by Horde_Routes to build its matching regexps.
- *
- * @param string $dirname Controller directory
- * @param string $prefix Prefix controllers found with string
- * @return array Controller names
- */
- public function scanFilesystem($dirname = null, $prefix = '')
- {
- $controllers = array();
-
- if ($dirname === null) {
- return $controllers;
- }
-
- $baseregexp = preg_quote($dirname, '/');
-
- foreach (new RecursiveIteratorIterator(
- new RecursiveDirectoryIterator($dirname)) as $entry) {
-
- if ($entry->isFile()) {
- // match .php files that don't start with an underscore
- if (preg_match('/^[^_]{1,1}.*\.php$/', basename($entry->getFilename())) != 0) {
- // strip off base path: dirname/admin/users.php -> admin/users.php
- $controller = preg_replace("/^$baseregexp(.*)\.php/", '\\1', $entry->getPathname());
-
- // PrepareController -> prepare_controller -> prepare
- $controller = strtolower(preg_replace('/([a-z])([A-Z])/', "\${1}_\${2}", $controller));
- $controller = substr($controller, 0, -(strlen('_controller')));
-
- // add to controller list
- $controllers[] = $prefix . $controller;
- }
- }
- }
-
- $callback = array('Horde_Routes_Utils', 'longestFirst');
- usort($controllers, $callback);
-
- return $controllers;
- }
-
- /**
- * Return an array of controller names that were collected from the
- * hardcodes of the routes connected to this mapper.
- *
- * @param string $dirname For method signature compatibility only
- * @param string $prefix Prefix controllers found with string
- * @return array Controller names
- */
- public function scanHardcodes($dirname = null, $prefix = null)
- {
- if ($prefix === null) {
- $controllers = $this->_controllers;
- } else {
- $controllers = array();
- foreach ($this->_controllers as $controller) {
- $controllers[] = $prefix . $controller;
- }
- }
-
- usort($controllers, 'Horde_Routes_Utils::longestFirst');
- return $controllers;
- }
-
-}
\ No newline at end of file
--- /dev/null
+<?php
+/**
+ * Interface for the object that builds a request chain around a controller.
+ *
+ * @category Horde
+ * @package Horde_Controller
+ * @author Bob McKee <bob@bluestatedigital.com>
+ * @author James Pepin <james@bluestatedigital.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ */
+interface Horde_Controller_SettingsExporter
+{
+ /**
+ */
+ public function exportBindings(Horde_Injector $injector);
+
+ /**
+ */
+ public function exportFilters(Horde_Controller_FilterCollection $filters, Horde_Injector $injector);
+}
--- /dev/null
+<?php
+/**
+ * Default controller request builder
+ *
+ * @category Horde
+ * @package Horde_Controller
+ * @author Bob McKee <bob@bluestatedigital.com>
+ * @author James Pepin <james@bluestatedigital.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ */
+class Horde_Controller_SettingsExporter_Default implements Horde_Controller_SettingsExporter
+{
+ /**
+ */
+ public function exportBindings(Horde_Injector $injector)
+ {
+ }
+
+ /**
+ */
+ public function exportFilters(Horde_Controller_FilterCollection $filters, Horde_Injector $injector)
+ {
+ }
+}
+++ /dev/null
-<?php
-/**
- * Copyright 2007-2008 Maintainable Software, LLC
- * Copyright 2008-2010 The Horde Project (http://www.horde.org)
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @license http://opensource.org/licenses/bsd-license.php BSD
- * @category Horde
- * @package Horde_Controller
- */
-class Horde_Controller_StatusCodes
-{
- /**
- * All known status codes and their messages
- * @var array
- */
- public static $statusCodes = array(
- 100 => "Continue",
- 101 => "Switching Protocols",
- 102 => "Processing",
-
- 200 => "OK",
- 201 => "Created",
- 202 => "Accepted",
- 203 => "Non-Authoritative Information",
- 204 => "No Content",
- 205 => "Reset Content",
- 206 => "Partial Content",
- 207 => "Multi-Status",
- 226 => "IM Used",
-
- 300 => "Multiple Choices",
- 301 => "Moved Permanently",
- 302 => "Found",
- 303 => "See Other",
- 304 => "Not Modified",
- 305 => "Use Proxy",
- 307 => "Temporary Redirect",
-
- 400 => "Bad Request",
- 401 => "Unauthorized",
- 402 => "Payment Required",
- 403 => "Forbidden",
- 404 => "Not Found",
- 405 => "Method Not Allowed",
- 406 => "Not Acceptable",
- 407 => "Proxy Authentication Required",
- 408 => "Request Timeout",
- 409 => "Conflict",
- 410 => "Gone",
- 411 => "Length Required",
- 412 => "Precondition Failed",
- 413 => "Request Entity Too Large",
- 414 => "Request-URI Too Long",
- 415 => "Unsupported Media Type",
- 416 => "Requested Range Not Satisfiable",
- 417 => "Expectation Failed",
- 422 => "Unprocessable Entity",
- 423 => "Locked",
- 424 => "Failed Dependency",
- 426 => "Upgrade Required",
-
- 500 => "Internal Server Error",
- 501 => "Not Implemented",
- 502 => "Bad Gateway",
- 503 => "Service Unavailable",
- 504 => "Gateway Timeout",
- 505 => "HTTP Version Not Supported",
- 507 => "Insufficient Storage",
- 510 => "Not Extended"
- );
-
- /**
- * Given a status parameter, determine whether it needs to be converted
- * to a string. If it is an integer, use the $statusCodes hash to lookup
- * the default message. If it is a string, build $symbolToStatusCode
- * and convert it.
- *
- * interpret(404) => "404 Not Found"
- * interpret("notFound") => "404 Not Found"
- *
- * Differences from Rails:
- * - $status is camelized, not underscored.
- * - an unknown status raises an exception
- *
- * @param string|integer Status code or "symbol"
- * @return string Header
- */
- public static function interpret($status)
- {
- // Status from integer or numeric string
- if (is_numeric($status)) {
- if (isset(self::$statusCodes[$status])) {
- return $status . ' ' . self::$statusCodes[$status];
- } else {
- $msg = 'Unknown status code: ' . $status;
- throw new InvalidArgumentException($msg);
- }
-
- // Status from string
- } elseif (is_string($status)) {
- // Build a string-to-integer lookup for converting a symbol (like
- // 'created' or 'notImplemented') into its corresponding HTTP status
- // code (like 200 or 501).
- static $symbolToStatusCode = array();
- $inflector = new Horde_Support_Inflector();
- if (empty($symbolToStatusCode)) {
- foreach (self::$statusCodes as $code => $message) {
- $symbol = $inflector->camelize($message, $first='lower');
- $symbolToStatusCode[$symbol] = $code;
- }
- }
-
- // Convert status symbol to integer code, return header
- if (isset($symbolToStatusCode[$status])) {
- return self::interpret($symbolToStatusCode[$status]);
- }
-
- // Error: Status symbol could not be converted to an integer code
- // Try to help if the developer mixed up underscore/camel
- $msg = 'Unknown status: \'' . $status . '\'';
- if (strpos($status, '_')) {
- $status = $inflector->camelize($status, $first='lower');
- if (isset($symbolToStatusCode[$status])) {
- $msg .= ' (underscore), did you mean \'' . $status . '\' (camel)?';
- }
- }
- throw new InvalidArgumentException($msg);
-
- // Status is an unknown type
- } else {
- $msg = '$status must be numeric or string, got '
- . gettype($status);
- throw new InvalidArgumentException($msg);
- }
-
- }
-
-}
+++ /dev/null
-<?php
-/**
- * Copyright 2007-2008 Maintainable Software, LLC
- * Copyright 2008-2010 The Horde Project (http://www.horde.org)
- *
- * @author Mike Naberezny <mike@maintainable.com>
- * @license http://opensource.org/licenses/bsd-license.php BSD
- * @category Horde
- * @package Horde_Controller
- */
-class Horde_Controller_UrlWriter
-{
- /**
- * Defaults to merge into route parameters when not using named routes.
- * @var array
- */
- protected $_defaults;
-
- /**
- * @var Horde_Routes_Util
- */
- protected $_utils;
-
- /**
- * Class constructor
- *
- * @param array $defaults Defaults to merge for urlFor()
- * @param null|Horde_Route_Utils $utils Route utilities
- */
- public function __construct($defaults = array(), $utils = null)
- {
- $this->_defaults = $defaults;
- if ($utils === null) {
- $utils = Horde_Controller_Dispatcher::singleton()->getRouteUtils();
- }
- $this->_utils = $utils;
- }
-
- /**
- * Generate a URL. Same signature as Horde_Routes_Utils->urlFor().
- *
- * @param $first mixed
- * @param $second mixed
- * @return string
- */
- public function urlFor($first, $second = array())
- {
- // anonymous route: serialize to params & merge defaults
- // urlFor(array('controller' => 'books'))
- if (is_array($first)) {
- $first = array_merge($this->_defaults,
- $this->_serializeToParams($first));
- }
-
- // named route: serialize to params only (no merge)
- // urlFor('notes', array('action' => 'show', 'id' => 1))
- if (is_array($second)) {
- $second = $this->_serializeToParams($second);
- }
-
- // url generation "route memory" is not useful here
- $this->_utils->mapperDict = array();
-
- // generate url
- return $this->_utils->urlFor($first, $second);
- }
-
- /**
- * Serialize any objects in the collection supporting toParam() before
- * passing the collection to Horde_Routes.
- *
- * @param array $collection
- * @param array
- */
- protected function _serializeToParams($collection)
- {
- foreach ($collection as &$value) {
- if (is_object($value) && method_exists($value, 'toParam')) {
- $value = $value->toParam();
- }
- }
- return $collection;
- }
-}
\ No newline at end of file
<dir name="lib">
<dir name="Horde">
<dir name="Controller">
- <dir name="Mime">
- <file name="Type.php" role="php" />
- </dir> <!-- /lib/Horde/Controller/Mime -->
+ <dir name="Filter">
+ <file name="Gzip.php" role="php" />
+ </dir> <!-- /lib/Horde/Controller/Filter -->
<dir name="Request">
- <file name="Base.php" role="php" />
- <file name="Cli.php" role="php" />
<file name="Http.php" role="php" />
- <file name="Mock.php" role="php" />
+ <file name="Null.php" role="php" />
</dir> <!-- /lib/Horde/Controller/Request -->
- <dir name="Response">
- <file name="Base.php" role="php" />
- <file name="Cli.php" role="php" />
- <file name="Http.php" role="php" />
- <file name="Mock.php" role="php" />
- </dir> <!-- /lib/Horde/Controller/Response -->
+ <dir name="ResponseWriter">
+ <file name="Web.php" role="php" />
+ <file name="WebDebug.php" role="php" />
+ </dir> <!-- /lib/Horde/Controller/ResponseWriter -->
+ <dir name="SettingsExporter">
+ <file name="Default.php" role="php" />
+ </dir> <!-- /lib/Horde/Controller/SettingsExporter -->
<file name="Base.php" role="php" />
- <file name="Dispatcher.php" role="php" />
<file name="Exception.php" role="php" />
- <file name="FileUpload.php" role="php" />
- <file name="Scanner.php" role="php" />
- <file name="StatusCodes.php" role="php" />
- <file name="UrlWriter.php" role="php" />
+ <file name="FilterCollection.php" role="php" />
+ <file name="FilterRunner.php" role="php" />
+ <file name="Null.php" role="php" />
+ <file name="PostFilter.php" role="php" />
+ <file name="PreFilter.php" role="php" />
+ <file name="Request.php" role="php" />
+ <file name="RequestConfiguration.php" role="php" />
+ <file name="Response.php" role="php" />
+ <file name="ResponseWriter.php" role="php" />
+ <file name="Runner.php" role="php" />
+ <file name="SettingsExporter.php" role="php" />
</dir> <!-- /lib/Horde/Controller -->
+ <file name="Controller.php" role="php" />
</dir> <!-- /lib/Horde -->
</dir> <!-- /lib -->
</dir> <!-- / -->
<phprelease>
<filelist>
<install name="lib/Horde/Controller/Base.php" as="Horde/Controller/Base.php" />
- <install name="lib/Horde/Controller/Dispatcher.php" as="Horde/Controller/Dispatcher.php" />
<install name="lib/Horde/Controller/Exception.php" as="Horde/Controller/Exception.php" />
- <install name="lib/Horde/Controller/FileUpload.php" as="Horde/Controller/FileUpload.php" />
- <install name="lib/Horde/Controller/Scanner.php" as="Horde/Controller/Scanner.php" />
- <install name="lib/Horde/Controller/StatusCodes.php" as="Horde/Controller/StatusCodes.php" />
- <install name="lib/Horde/Controller/UrlWriter.php" as="Horde/Controller/UrlWriter.php" />
- <install name="lib/Horde/Controller/Mime/Type.php" as="Horde/Controller/Mime/Type.php" />
- <install name="lib/Horde/Controller/Request/Base.php" as="Horde/Controller/Request/Base.php" />
- <install name="lib/Horde/Controller/Request/Cli.php" as="Horde/Controller/Request/Cli.php" />
+ <install name="lib/Horde/Controller/Filter/Gzip.php" as="Horde/Controller/Filter/Gzip.php" />
+ <install name="lib/Horde/Controller/FilterCollection.php" as="Horde/Controller/FilterCollection.php" />
+ <install name="lib/Horde/Controller/FilterRunner.php" as="Horde/Controller/FilterRunner.php" />
+ <install name="lib/Horde/Controller/Null.php" as="Horde/Controller/Null.php" />
+ <install name="lib/Horde/Controller/PostFilter.php" as="Horde/Controller/PostFilter.php" />
+ <install name="lib/Horde/Controller/PreFilter.php" as="Horde/Controller/PreFilter.php" />
<install name="lib/Horde/Controller/Request/Http.php" as="Horde/Controller/Request/Http.php" />
- <install name="lib/Horde/Controller/Request/Mock.php" as="Horde/Controller/Request/Mock.php" />
- <install name="lib/Horde/Controller/Response/Base.php" as="Horde/Controller/Response/Base.php" />
- <install name="lib/Horde/Controller/Response/Cli.php" as="Horde/Controller/Response/Cli.php" />
- <install name="lib/Horde/Controller/Response/Http.php" as="Horde/Controller/Response/Http.php" />
- <install name="lib/Horde/Controller/Response/Mock.php" as="Horde/Controller/Response/Mock.php" />
+ <install name="lib/Horde/Controller/Request/Null.php" as="Horde/Controller/Request/Null.php" />
+ <install name="lib/Horde/Controller/Request.php" as="Horde/Controller/Request.php" />
+ <install name="lib/Horde/Controller/RequestConfiguration.php" as="Horde/Controller/RequestConfiguration.php" />
+ <install name="lib/Horde/Controller/Response.php" as="Horde/Controller/Response.php" />
+ <install name="lib/Horde/Controller/ResponseWriter/Web.php" as="Horde/Controller/ResponseWriter/Web.php" />
+ <install name="lib/Horde/Controller/ResponseWriter/WebDebug.php" as="Horde/Controller/ResponseWriter/WebDebug.php" />
+ <install name="lib/Horde/Controller/ResponseWriter.php" as="Horde/Controller/ResponseWriter.php" />
+ <install name="lib/Horde/Controller/Runner.php" as="Horde/Controller/Runner.php" />
+ <install name="lib/Horde/Controller/SettingsExporter/Default.php" as="Horde/Controller/SettingsExporter/Default.php" />
+ <install name="lib/Horde/Controller/SettingsExporter.php" as="Horde/Controller/SettingsExporter.php" />
+ <install name="lib/Horde/Controller.php" as="Horde/Controller.php" />
</filelist>
</phprelease>
</package>
--- /dev/null
+<?php
+class Horde_Controller_FilterRunnerTest extends Horde_Test_Case
+{
+ public function testFilterRunnerDoesNotCallControllerWhenAPreFilterHandlesTheRequest()
+ {
+ $filter = $this->getMock('Horde_Controller_PreFilter', array('processRequest'));
+ $filter->expects($this->once())
+ ->method('processRequest')
+ ->will($this->returnValue(Horde_Controller_PreFilter::REQUEST_HANDLED));
+
+ $runner = new Horde_Controller_FilterRunner($this->_getControllerMockNeverCalled());
+ $runner->addPreFilter($filter);
+ $runner->processRequest($this->getMock('Horde_Controller_Request'), new Horde_Controller_Response());
+ }
+
+ public function testShouldUsePreFiltersInFirstInFirstOutOrder()
+ {
+ // The second filter should never be called because first filter returns
+ // REQUEST_HANDLED, meaning it can handle the request.
+ $preFilter1 = $this->getMock('Horde_Controller_PreFilter', array('processRequest'));
+ $preFilter1->expects($this->once())
+ ->method('processRequest')
+ ->will($this->returnValue(Horde_Controller_PreFilter::REQUEST_HANDLED));
+
+ $preFilter2 = $this->getMock('Horde_Controller_PreFilter', array('processRequest'));
+ $preFilter2->expects($this->never())
+ ->method('processRequest');
+
+ $runner = new Horde_Controller_FilterRunner($this->_getControllerMockNeverCalled());
+ $runner->addPreFilter($preFilter1);
+ $runner->addPreFilter($preFilter2);
+ $this->_runFilterRunner($runner);
+ }
+
+ public function testShouldUsePostFiltersInFirstInLastOutOrder()
+ {
+ // Both filters should be called because the first filter returns
+ // REQUEST_HANDLED, meaning it can handle the request
+ $postFilter1 = $this->getMock('Horde_Controller_PostFilter', array('processResponse'));
+ $postFilter1->expects($this->once())
+ ->method('processResponse')
+ ->will($this->returnValue(Horde_Controller_PreFilter::REQUEST_HANDLED));
+
+ $postFilter2 = $this->getMock('Horde_Controller_PostFilter', array('processResponse'));
+ $postFilter2->expects($this->once())
+ ->method('processResponse');
+
+
+ $controller = $this->getMock('Horde_Controller', array('processRequest'));
+ $controller->expects($this->once())
+ ->method('processRequest');
+
+ $runner = new Horde_Controller_FilterRunner($controller);
+ $runner->addPostFilter($postFilter1);
+ $runner->addPostFilter($postFilter2);
+ $this->_runFilterRunner($runner);
+ }
+
+ private function _getControllerMockNeverCalled()
+ {
+ $controller = $this->getMock('Horde_Controller', array('processRequest'));
+ $controller->expects($this->never())
+ ->method('processRequest');
+ return $controller;
+ }
+
+ private function _runFilterRunner(Horde_Controller_FilterRunner $runner)
+ {
+ $response = $this->getMock('Horde_Controller_Response', array('processRequest'));
+ $response->expects($this->never())->method('processRequest');
+ $runner->processRequest(new Horde_Controller_Request_Null(), $response);
+ }
+}
--- /dev/null
+<?php
+class Horde_Core_Binder_Mapper implements Horde_Injector_Binder
+{
+ public function create(Horde_Injector $injector)
+ {
+ $mapper = new Horde_Routes_Mapper();
+
+
+ return $mapper;
+ }
+
+ public function equals(Horde_Injector_Binder $binder)
+ {
+ return false;
+ }
+}
--- /dev/null
+<?php
+class Horde_Core_Controller_NotFound implements Horde_Controller
+{
+ /**
+ */
+ public function processRequest(Horde_Controller_Request $request, Horde_Controller_Response $response)
+ {
+ $response->setHeader('HTTP/1.0 404 ', 'Not Found');
+ $response->setBody('<h1>404 File Not Found</h1>');
+ }
+}
--- /dev/null
+<?php
+/**
+ * Object to contain request information as it relates to which controller to
+ * create.
+ *
+ * @category Horde
+ * @package Horde_Core
+ */
+class Horde_Core_Controller_RequestConfiguration implements Horde_Controller_RequestConfiguration
+{
+ /**
+ */
+ protected $_classNames = array();
+
+ /**
+ */
+ protected $_application;
+
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ $this->_classNames = array(
+ 'controller' => 'Horde_Core_Controller_NotFound',
+ 'settings' => 'Horde_Controller_SettingsExporter_Default',
+ );
+ }
+
+ /**
+ */
+ public function setApplication($application)
+ {
+ $this->_application = $application;
+ }
+
+ /**
+ */
+ public function getApplication()
+ {
+ return $this->_application;
+ }
+
+ /**
+ */
+ public function setControllerName($controllerName)
+ {
+ $this->_classNames['controller'] = $controllerName;
+ }
+
+ /**
+ */
+ public function getControllerName()
+ {
+ return $this->_classNames['controller'];
+ }
+
+ /**
+ */
+ public function setSettingsExporterName($settingsName)
+ {
+ $this->_classNames['settings'] = $settingsName;
+ }
+
+ /**
+ */
+ public function getSettingsExporterName()
+ {
+ return $this->_classNames['settings'];
+ }
+}
--- /dev/null
+<?php
+class Horde_Core_Controller_RequestMapper
+{
+ /**
+ * @var Horde_Routes_Mapper $mapper
+ */
+ protected $_mapper;
+
+ public function __construct(Horde_Routes_Mapper $mapper)
+ {
+ $this->_mapper = $mapper;
+ }
+
+ public function getRequestConfiguration(Horde_Injector $injector)
+ {
+ $request = $injector->getInstance('Horde_Controller_Request');
+ $registry = $injector->getInstance('Horde_Registry');
+ $settingsFinder = $injector->getInstance('Horde_Core_Controller_SettingsFinder');
+
+ $config = $injector->createInstance('Horde_Core_Controller_RequestConfiguration');
+
+ $uri = substr($request->getPath(), strlen($registry->get('webroot', 'horde')));
+ $uri = trim($uri, '/');
+ if (strpos($uri, '/') === false) {
+ $app = $uri;
+ } else {
+ list($app,) = explode('/', $uri, 2);
+ }
+
+ // Check for route definitions.
+ $fileroot = $registry->get('fileroot', $app);
+ $routeFile = $fileroot . '/config/routes.php';
+ if (!file_exists($routeFile)) {
+ throw new Horde_Routes_Exception('Not routable: ' . $uri . '. ' . $routeFile . ' does not exist.');
+ }
+
+ // Push $app onto the registry
+ $registry->pushApp($app);
+ $config->setApplication($app);
+
+ // Application routes are relative only to the application. Let the
+ // mapper know where they start.
+ $this->_mapper->prefix = $registry->get('webroot', $app);
+
+ // Set the application controller directory
+ $this->_mapper->directory = $registry->get('fileroot', $app) . '/app/controllers';
+
+ // Load application routes.
+ $mapper = $this->_mapper;
+ include $routeFile;
+
+ // Match
+ // @TODO Cache routes
+ $match = $this->_mapper->match($request->getPath());
+
+ if (isset($match['controller'])) {
+ $config->setControllerName(ucfirst($app) . '_' . ucfirst($match['controller']) . '_Controller');
+ $config->setSettingsExporterName($settingsFinder->getSettingsExporterName($config->getControllerName()));
+ } else {
+ $config->setControllerName('Horde_Core_Controller_NotFound');
+ }
+
+ return $config;
+ }
+}
--- /dev/null
+<?php
+class Horde_Core_Controller_SettingsFinder
+{
+ public function getSettingsExporterName($controllerName)
+ {
+ $settingsName = $this->_mapName($controllerName);
+ $current = $controllerName;
+ while (class_exists($current)) {
+ $settingsName = $this->_mapName($current);
+ if (class_exists($settingsName)) {
+ return $settingsName;
+ }
+
+ $current = $this->_getParentName($current);
+ }
+
+ return 'Horde_Controller_SettingsExporter_Default';
+ }
+
+ private function _mapName($controllerName)
+ {
+ return str_replace('_Controller', '_SettingsExporter', $controllerName);
+ }
+
+ private function _getParentName($controllerName)
+ {
+ $klass = new ReflectionClass($controllerName);
+ $parent = $klass->getParentClass();
+ return $parent->name;
+ }
+}
--- /dev/null
+<?php
+/**
+ */
+class Horde_Core_Factory_Request
+{
+ public function create(Horde_Injector $injector)
+ {
+ return new Horde_Controller_Request_Http($_SERVER['REQUEST_URI']);
+ }
+}
'Horde_Tree' => new Horde_Core_Binder_Tree(),
'Horde_Token' => new Horde_Core_Binder_Token(),
'Horde_Vfs' => new Horde_Core_Binder_Vfs(),
- 'Net_DNS_Resolver' => new Horde_Core_Binder_Dns()
+ 'Net_DNS_Resolver' => new Horde_Core_Binder_Dns(),
);
/* Define factories. */
$factories = array(
+ 'Horde_Controller_Request' => array(
+ 'Horde_Core_Factory_Request',
+ 'create',
+ ),
+ 'Horde_Controller_RequestConfiguration' => array(
+ 'Horde_Core_Controller_RequestMapper',
+ 'getRequestConfiguration',
+ ),
'Horde_Kolab_Server_Composite' => array(
'Horde_Core_Factory_KolabServer',
- 'getComposite'
+ 'getComposite',
),
'Horde_Kolab_Session' => array(
'Horde_Core_Factory_KolabSession',
- 'getSession'
+ 'getSession',
),
'Horde_Kolab_Storage' => array(
'Horde_Core_Factory_KolabStorage',
- 'getStorage'
+ 'getStorage',
)
);
+ /* Define implementations. */
+ $implementations = array(
+ 'Horde_Controller_ResponseWriter' => 'Horde_Controller_ResponseWriter_Web',
+ 'Horde_View_Base' => 'Horde_View',
+ );
+
/* Setup injector. */
$GLOBALS['injector'] = $injector = new Horde_Injector(new Horde_Injector_TopLevel());
foreach ($factories as $key => $val) {
$injector->bindFactory($key, $val[0], $val[1]);
}
+ foreach ($implementations as $key => $val) {
+ $injector->bindImplementation($key, $val);
+ }
$GLOBALS['registry'] = $this;
$injector->setInstance('Horde_Registry', $this);
* be done here because it is possible to try to load app-specific
* libraries from other applications. */
$app_lib = $this->get('fileroot', $app) . '/lib';
- $GLOBALS['injector']->getInstance('Horde_Autoloader')->addClassPathMapper(new Horde_Autoloader_ClassPathMapper_Prefix('/^' . $app . '(?:$|_)/i', $app_lib));
+ $autoloader = $GLOBALS['injector']->getInstance('Horde_Autoloader');
+ $autoloader->addClassPathMapper(new Horde_Autoloader_ClassPathMapper_Prefix('/^' . $app . '(?:$|_)/i', $app_lib));
+ $applicationMapper = new Horde_Autoloader_ClassPathMapper_Application($this->get('fileroot', $app) . '/app');
+ $applicationMapper->addMapping('Controller', 'controllers');
+ $applicationMapper->addMapping('SettingsExporter', 'settings');
+ $autoloader->addClassPathMapper($applicationMapper);
$checkPerms = !isset($options['check_perms']) || !empty($options['check_perms']);
<file name="Twitter.php" role="php" />
<file name="Vfs.php" role="php" />
</dir> <!-- /lib/Horde/Core/Binder -->
+ <dir name="Controller">
+ <file name="NotFound.php" role="php" />
+ <file name="RequestConfiguration.php" role="php" />
+ <file name="RequestMapper.php" role="php" />
+ <file name="SettingsFinder.php" role="php" />
+ </dir> <!-- /lib/Horde/Core/Controller -->
<dir name="Factory">
<file name="Ajax.php" role="php" />
<file name="Auth.php" role="php" />
<file name="KolabStorage.php" role="php" />
<file name="Ldap.php" role="php" />
<file name="LoginTasks.php" role="php" />
+ <file name="Request.php" role="php" />
<file name="Share.php" role="php" />
<file name="Tree.php" role="php" />
<file name="Vfs.php" role="php" />
<install as="Horde/Core/Auth/Signup/Null.php" name="lib/Horde/Core/Auth/Signup/Null.php" />
<install as="Horde/Core/Auth/Signup/Sql.php" name="lib/Horde/Core/Auth/Signup/Sql.php" />
<install as="Horde/Core/Auth/Signup/SqlObject.php" name="lib/Horde/Core/Auth/Signup/SqlObject.php" />
+ <install as="Horde/Core/Autoloader.php" name="lib/Horde/Core/Autoloader.php" />
<install as="Horde/Core/Autoloader/Callback/Mime.php" name="lib/Horde/Core/Autoloader/Callback/Mime.php" />
<install as="Horde/Core/Autoloader/Callback/Nls.php" name="lib/Horde/Core/Autoloader/Callback/Nls.php" />
<install as="Horde/Core/Binder/Ajax.php" name="lib/Horde/Core/Binder/Ajax.php" />
<install as="Horde/Core/Binder/Token.php" name="lib/Horde/Core/Binder/Token.php" />
<install as="Horde/Core/Binder/Twitter.php" name="lib/Horde/Core/Binder/Twitter.php" />
<install as="Horde/Core/Binder/Vfs.php" name="lib/Horde/Core/Binder/Vfs.php" />
+ <install as="Horde/Core/Controller/NotFound.php" name="lib/Horde/Core/Controller/NotFound.php" />
+ <install as="Horde/Core/Controller/RequestConfiguration.php" name="lib/Horde/Core/Controller/RequestConfiguration.php" />
+ <install as="Horde/Core/Controller/RequestMapper.php" name="lib/Horde/Core/Controller/RequestMapper.php" />
+ <install as="Horde/Core/Controller/SettingsFinder.php" name="lib/Horde/Core/Controller/SettingsFinder.php" />
<install as="Horde/Core/Factory/Ajax.php" name="lib/Horde/Core/Factory/Ajax.php" />
<install as="Horde/Core/Factory/Auth.php" name="lib/Horde/Core/Factory/Auth.php" />
<install as="Horde/Core/Factory/Crypt.php" name="lib/Horde/Core/Factory/Crypt.php" />
<install as="Horde/Core/Factory/KolabStorage.php" name="lib/Horde/Core/Factory/KolabStorage.php" />
<install as="Horde/Core/Factory/Ldap.php" name="lib/Horde/Core/Factory/Ldap.php" />
<install as="Horde/Core/Factory/LoginTasks.php" name="lib/Horde/Core/Factory/LoginTasks.php" />
+ <install as="Horde/Core/Factory/Request.php" name="lib/Horde/Core/Factory/Request.php" />
<install as="Horde/Core/Factory/Share.php" name="lib/Horde/Core/Factory/Share.php" />
<install as="Horde/Core/Factory/Tree.php" name="lib/Horde/Core/Factory/Tree.php" />
<install as="Horde/Core/Factory/Vfs.php" name="lib/Horde/Core/Factory/Vfs.php" />
<install as="Horde/Themes/Element.php" name="lib/Horde/Themes/Element.php" />
<install as="Horde/Themes/Image.php" name="lib/Horde/Themes/Image.php" />
<install as="Horde/Themes/Sound.php" name="lib/Horde/Themes/Sound.php" />
- <install as="Horde/Core/AllTests.php" name="test/Horde/Core/AllTests.php" />
- <install as="Horde/Core/Autoload.php" name="test/Horde/Core/Autoload.php" />
- <install as="Horde/Core/phpunit.xml" name="test/Horde/Core/phpunit.xml" />
- <install as="Horde/Core/url.phpt" name="test/Horde/Core/url.phpt" />
- <install as="Horde/Core/Binder/CacheTest.php" name="test/Horde/Core/Binder/CacheTest.php" />
- <install as="Horde/Core/Factory/KolabServerTest.php" name="test/Horde/Core/Factory/KolabServerTest.php" />
- <install as="Horde/Core/Factory/KolabSessionTest.php" name="test/Horde/Core/Factory/KolabSessionTest.php" />
</filelist>
</phprelease>
<changelog>
* Controllers/
* FooController.php -> class App_FooController
* no nested components?
+
+request processing steps:
+
+- bootstrap
+- injector bindings
+* customization point
+- create request
+- create request mapper
+- $config = $mapper->getRquestConfiguration($request)
+- create runner
+- execute runner
+ - get settings exporter
+ - export bindings
+ - get controller name
+ - create response
+ - create controller builder
+ - create filter runner
+ - export filters
+ - handle internal redirects
+ - return response
+- write response
+
+add filtered requests/blue_filter port to Horde?
*/
require_once dirname(__FILE__) . '/lib/Application.php';
Horde_Registry::appInit('horde');
-// Set up our request and routing objects
-$request = new Horde_Controller_Request_Http();
-$mapper = new Horde_Routes_Mapper();
-
-$uri = substr($request->getUri(), strlen($registry->get('webroot', 'horde')));
-if (strpos($uri, '/') === false) {
- $app = $uri;
- $path = '';
-} else {
- list($app, $path) = explode('/', $uri, 2);
-}
-
-// Check for route definitions.
-$fileroot = $registry->get('fileroot', $app);
-$routeFile = $fileroot . '/config/routes.php';
-if (!file_exists($routeFile)) {
- throw new Horde_Controller_Exception('Not routable: ' . $uri);
-}
-
-// @TODO Use the registry to check app permissions, etc.
-// $registry->pushApp($app);
-
-// Application routes are relative only to the application. Let the mapper know
-// where they start.
-$mapper->prefix = $registry->get('webroot', 'horde') . '/' . $app;
-
-// @TODO ? $mapper->createRegs(array('blogs', 'comments', 'posts')) would avoid
-// the directory scan entirely. The argument is the name of every controller in
-// the system. Should also cache the controller scan.
-
-// Load application routes.
-include $routeFile;
-
-// Set up application class and controller loading
-// @TODO separate $app from class names so that there can be multiple instances
-// of an app in the registry?
-$injector->getInstance('Horde_Autoloader')->addClassPathMapper(new Horde_Autoloader_ClassPathMapper_Prefix('/^' . $app . '(?:$|_)/i', $fileroot . '/lib/'));
+$request = $injector->getInstance('Horde_Controller_Request');
-// Create our controller context.
-$context = array(
- 'mapper' => $mapper,
- 'controllerDir' => $fileroot . '/app/controllers',
- 'viewsDir' => $fileroot . '/app/views',
- // 'logger' => '',
-);
+$runner = $injector->getInstance('Horde_Controller_Runner');
+$config = $injector->getInstance('Horde_Controller_RequestConfiguration');
+$response = $runner->execute($injector, $request, $config);
-// Dispatch.
-$dispatcher = Horde_Controller_Dispatcher::singleton($context);
-$dispatcher->dispatch($request);
+$responseWriter = $injector->getInstance('Horde_Controller_ResponseWriter');
+$responseWriter->writeResponse($response);