From: Gunnar Wrobel
Date: Fri, 11 Sep 2009 09:50:16 +0000 (+0200)
Subject: Started converting the Kolab Free/Busy application into a Horde MVC
X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=47b9ccfffb10e89122fc0538fc0a77b6146ce7b8;p=horde.git
Started converting the Kolab Free/Busy application into a Horde MVC
based webapp. Also began to remove the use of singletons in order to
facilitate unit testing the system. Horde_Kolab_FreeBusy now serves as
Registry/ServiceLocator to the various services required.
---
diff --git a/framework/Kolab_FreeBusy/lib/Horde/Kolab/FreeBusy.php b/framework/Kolab_FreeBusy/lib/Horde/Kolab/FreeBusy.php
index 32112746e..d9f75a5cb 100644
--- a/framework/Kolab_FreeBusy/lib/Horde/Kolab/FreeBusy.php
+++ b/framework/Kolab_FreeBusy/lib/Horde/Kolab/FreeBusy.php
@@ -1,340 +1,320 @@
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Kolab_FreeBusy
*/
-/** PEAR for raising errors */
-require_once 'PEAR.php';
-
-/** View classes for the result */
-require_once 'Horde/Kolab/FreeBusy/View.php';
-
-/** A class that handles access restrictions */
-require_once 'Horde/Kolab/FreeBusy/Access.php';
-
/**
- * How to use this class
- *
- * require_once 'config.php';
- *
- * $fb = new Kolab_Freebusy();
- *
- * $fb->trigger();
- *
- * OR
- *
- * $fb->fetch();
+ * The Horde_Kolab_FreeBusy class serves as Registry aka ServiceLocator for the
+ * Free/Busy application. It also provides the entry point into the the Horde
+ * MVC system and allows to dispatch a request.
*
- * $Horde: framework/Kolab_FreeBusy/lib/Horde/Kolab/FreeBusy.php,v 1.14 2009/07/14 00:28:33 mrubinsk Exp $
+ * Copyright 2009 The Horde Project (http://www.horde.org/)
*
- * Copyright 2004-2008 Klarälvdalens Datakonsult AB
+ * See the enclosed file COPYING for license information (LGPL). If you did not
+ * receive this file, see
+ * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
*
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
- *
- * @since Horde 3.2
- * @author Steffen Hansen
- * @author Thomas Arendsen Hein
+ * 'script' - (string) Script name in relation to the document root.
+ * [optional]
+ *
+ * 'config' - (array) Indicates where to find configuration options.
+ * [optional]
+ *
+ * 'dir' - (string) Configuration files can be found in this
+ * directory.
+ *
+ * 'request' - (array) Options for the request object. [optional]
+ *
+ * 'class' - (string) The class of request object to use (should
+ * obviously match the request type).
+ * 'params' - (array) Additional parameters to use on request
+ * object construction.
+ *
+ * 'mapper' - (array) Options for the mapper object. [optional]
+ *
+ * 'params' - (array) Additional parameters to use on mapper
+ * object construction.
+ *
+ * 'dispatch'- (array) Options for the dispatcher object. [optional]
+ *
+ * 'controllerDir' - (string) The directory holding controllers.
+ * 'viewsDir' - (string) The directory holding views.
+ *
+ *
+ *
+ * @return Horde_Kolab_FreeBusy The Horde_Registry instance.
*/
- function &trigger()
+ static public function singleton($params = array())
{
- global $conf;
-
- /* Get the folder name */
- $req_folder = Horde_Util::getFormData('folder', '');
-
- Horde::logMessage(sprintf("Starting generation of partial free/busy data for folder %s",
- $req_folder), __FILE__, __LINE__, PEAR_LOG_DEBUG);
-
- /* Validate folder access */
- $access = new Horde_Kolab_FreeBusy_Access();
- $result = $access->parseFolder($req_folder);
- if (is_a($result, 'PEAR_Error')) {
- $error = array('type' => FREEBUSY_ERROR_NOTFOUND,
- 'error' => $result);
- $view = new Horde_Kolab_FreeBusy_View_error($error);
- return $view;
+ if (!isset(self::$instance)) {
+ self::$instance = new Horde_Kolab_FreeBusy($params);
}
- Horde::logMessage(sprintf("Partial free/busy data of owner %s on server %s requested by user %s.",
- $access->owner, $access->freebusyserver, $access->user),
- __FILE__, __LINE__, PEAR_LOG_DEBUG);
-
- /* Get the cache request variables */
- $req_cache = Horde_Util::getFormData('cache', false);
- $req_extended = Horde_Util::getFormData('extended', false);
-
- /* Try to fetch the data if it is stored on a remote server */
- $result = $access->fetchRemote(true, $req_extended);
- if (is_a($result, 'PEAR_Error')) {
- $error = array('type' => FREEBUSY_ERROR_UNAUTHORIZED,
- 'error' => $result);
- $view = new Horde_Kolab_FreeBusy_View_error($error);
- return $view;
- }
+ return self::$instance;
+ }
- $this->_initCache();
+ /**
+ * Destroy the application context.
+ *
+ * @return NULL
+ */
+ static public function destroy()
+ {
+ self::$instance = null;
+ }
- if (!$req_cache) {
- /* User wants to regenerate the cache */
+ /**
+ * Inject the request object into the application context.
+ *
+ * @param Horde_Controller_Request_Base $request The object that should
+ * represent the current
+ * request.
+ *
+ * @return NULL
+ */
+ public function setRequest(Horde_Controller_Request_Base $request)
+ {
+ $this->_request = $request;
+ }
- /* Here we really need an authenticated IMAP user */
- $result = $access->authenticated();
- if (is_a($result, 'PEAR_Error')) {
- $error = array('type' => FREEBUSY_ERROR_UNAUTHORIZED,
- 'error' => $result);
- $view = new Horde_Kolab_FreeBusy_View_error($error);
- return $view;
+ /**
+ * Return the object representing the current request.
+ *
+ * @return Horde_Controller_Request_Base The current request.
+ *
+ * @throws Horde_Exception
+ */
+ public function getRequest()
+ {
+ if (!isset($this->_request)) {
+ if (!empty($this->_params['request']['class'])) {
+ $request_class = $this->_params['request']['class'];
+ } else {
+ $request_class = 'Horde_Controller_Request_Http';
}
-
- if (empty($access->owner)) {
- $message = sprintf(_("No such account %s!"),
- htmlentities($access->req_owner));
- $error = array('type' => FREEBUSY_ERROR_NOTFOUND,
- 'error' => PEAR::raiseError($message));
- $view = new Horde_Kolab_FreeBusy_View_error($error);
- return $view;
+ if (!empty($this->_params['request']['params'])) {
+ $params = $this->_params['request']['params'];
+ } else {
+ $params = array();
}
-
- /* Update the cache */
- $result = $this->_cache->store($access);
- if (is_a($result, 'PEAR_Error')) {
- $error = array('type' => FREEBUSY_ERROR_NOTFOUND,
- 'error' => $result);
- $view = new Horde_Kolab_FreeBusy_View_error($error);
- return $view;
+ // Set up our request and routing objects
+ $this->_request = new $request_class($params);
+ /**
+ * The HTTP request object would hide errors. Display them.
+ */
+ if (isset($this->request->_exception)) {
+ throw $this->request->_exception;
}
}
- /* Load the cache data */
- $vfb = $this->_cache->loadPartial($access, $req_extended);
- if (is_a($vfb, 'PEAR_Error')) {
- $error = array('type' => FREEBUSY_ERROR_NOTFOUND,
- 'error' => $vfb);
- $view = new Horde_Kolab_FreeBusy_View_error($error);
- return $view;
- }
-
- Horde::logMessage("Delivering partial free/busy data.", __FILE__, __LINE__, PEAR_LOG_DEBUG);
-
- /* Generate the renderer */
- $data = array('fb' => $vfb, 'name' => $access->owner . '.ifb');
- $view = new Horde_Kolab_FreeBusy_View_vfb($data);
-
- /* Finish up */
- Horde::logMessage("Free/busy generation complete.", __FILE__, __LINE__, PEAR_LOG_DEBUG);
-
- return $view;
+ return $this->_request;
}
/**
- * Fetch the free/busy data for a user.
+ * Inject the mapper object into the application context.
+ *
+ * @param Horde_Route_Mapper $mapper The object that handles mapping.
+ *
+ * @return NULL
*/
- function &fetch()
+ public function setMapper(Horde_Route_Mapper $mapper)
{
- global $conf;
-
- /* Get the user requsted */
- $req_owner = Horde_Util::getFormData('uid');
-
- Horde::logMessage(sprintf("Starting generation of free/busy data for user %s",
- $req_owner), __FILE__, __LINE__, PEAR_LOG_DEBUG);
-
- /* Validate folder access */
- $access = new Horde_Kolab_FreeBusy_Access();
- $result = $access->parseOwner($req_owner);
- if (is_a($result, 'PEAR_Error')) {
- $error = array('type' => FREEBUSY_ERROR_NOTFOUND, 'error' => $result);
- $view = new Horde_Kolab_FreeBusy_View_error($error);
- return $view;
- }
-
- Horde::logMessage(sprintf("Free/busy data of owner %s on server %s requested by user %s.",
- $access->owner, $access->freebusyserver, $access->user),
- __FILE__, __LINE__, PEAR_LOG_DEBUG);
-
- $req_extended = Horde_Util::getFormData('extended', false);
-
- /* Try to fetch the data if it is stored on a remote server */
- $result = $access->fetchRemote(false, $req_extended);
- if (is_a($result, 'PEAR_Error')) {
- $error = array('type' => FREEBUSY_ERROR_UNAUTHORIZED, 'error' => $result);
- $view = new Horde_Kolab_FreeBusy_View_error($error);
- return $view;
- }
-
- $this->_initCache();
-
- $result = $this->_cache->load($access, $req_extended);
- if (is_a($result, 'PEAR_Error')) {
- $error = array('type' => FREEBUSY_ERROR_NOTFOUND, 'error' => $result);
- $view = new Horde_Kolab_FreeBusy_View_error($error);
- return $view;
- }
-
- Horde::logMessage("Delivering complete free/busy data.", __FILE__, __LINE__, PEAR_LOG_DEBUG);
-
- /* Generate the renderer */
- $data = array('fb' => $result, 'name' => $access->owner . '.vfb');
- $view = new Horde_Kolab_FreeBusy_View_vfb($data);
-
- /* Finish up */
- Horde::logMessage("Free/busy generation complete.", __FILE__, __LINE__, PEAR_LOG_DEBUG);
-
- return $view;
+ $this->_mapper = $mapper;
}
/**
- * Regenerate the free/busy cache.
+ * Return the mapper.
+ *
+ * @return Horde_Route_Mapper The mapper.
+ *
+ * @throws Horde_Exception
*/
- function ®enerate($reporter)
+ public function getMapper()
{
- $access = new Horde_Kolab_FreeBusy_Access();
- $result = $access->authenticated();
- if (is_a($result, 'PEAR_Error')) {
- return $result->getMessage();
- }
-
- /* Load the required Kolab libraries */
- require_once "Horde/Kolab/Storage/List.php";
-
- $list = &Kolab_List::singleton();
- $calendars = $list->getByType('event');
- if (is_a($calendars, 'PEAR_Error')) {
- return $calendars->getMessage();
- }
-
- $this->_initCache();
-
- $lines = array();
+ if (!isset($this->_mapper)) {
+ if (!empty($this->_params['mapper']['params'])) {
+ $params = $this->_params['mapper']['params'];
+ } else {
+ $params = array();
+ }
+ $this->_mapper = new Horde_Routes_Mapper($params);
- foreach ($calendars as $calendar) {
/**
- * We are using imap folders for our calendar list but
- * the library expects us to follow the trigger format
- * used by pfb.php
+ * Application routes are relative only to the application. Let the
+ * mapper know where they start.
*/
- $req_domain = explode('@', $calendar->name);
- if (isset($req_domain[1])) {
- $domain = $req_domain[1];
+ if (!empty($this->_params['script'])) {
+ $this->_mapper->prefix = dirname($this->_params['script']);
} else {
- $domain = null;
+ $this->_mapper->prefix = dirname($_SERVER['PHP_SELF']);
+ }
+
+ // Check for route definitions.
+ if (!empty($this->_params['config']['dir'])) {
+ $routeFile = $this->_params['config']['dir'] . '/routes.php';
}
- $req_folder = explode('/', $req_domain[0]);
- if ($req_folder[0] == 'user') {
- unset($req_folder[0]);
- $owner = $req_folder[1];
- unset($req_folder[1]);
- } else if ($req_folder[0] == 'INBOX') {
- $owner = $access->user;
- unset($req_folder[0]);
+ if (empty($this->_params['config']['dir'])
+ || !file_exists($routeFile)) {
+ $this->_mapper->connect('*(id).:(type)',
+ array('controller' => 'freebusy',
+ 'action' => 'fetch',
+ 'requirements' => array('type' => '(i|x|v|p|px)fb')
+ ));
+
+ $this->_mapper->connect('trigger/:id/:folder',
+ array('controller' => 'freebusy',
+ 'action' => 'trigger'));
+
+ $this->_mapper->connect('delete/:id',
+ array('controller' => 'freebusy',
+ 'action' => 'delete'));
+
+ $this->_mapper->connect('regenerate/:id',
+ array('controller' => 'freebusy',
+ 'action' => 'delete'));
+ } else {
+ // Load application routes.
+ include $routeFile;
}
+ }
- $trigger = $owner . ($domain ? '@' . $domain : '') . '/' . join('/', $req_folder);
- $trigger = Horde_String::convertCharset($trigger, 'UTF7-IMAP', 'UTF-8');
+ return $this->_mapper;
+ }
- /* Validate folder access */
- $result = $access->parseFolder($trigger);
- if (is_a($result, 'PEAR_Error')) {
- $reporter->failure($calendar->name, $result->getMessage());
- continue;
- }
+ /**
+ * Inject the dispatcher object into the application context.
+ *
+ * @param Horde_Controller_Dispatcher $dispatcher The object that handles
+ * dispatching.
+ *
+ * @return NULL
+ */
+ public function setDispatcher(Horde_Controller_Dispatcher $dispatcher)
+ {
+ $this->_dispatcher = $dispatcher;
+ }
- /* Hack for allowing manager access */
- if ($access->user == 'manager') {
- $imapc = &Horde_Kolab_IMAP::singleton($GLOBALS['conf']['kolab']['imap']['server'],
- $GLOBALS['conf']['kolab']['imap']['port']);
- $result = $imapc->connect($access->user, Horde_Auth::getCredential('password'));
- if (is_a($result, 'PEAR_Error')) {
- $reporter->failure($calendar->name, $result->getMessage());
- continue;
- }
- $acl = $imapc->getACL($calendar->name);
- if (is_a($acl, 'PEAR_Error')) {
- $reporter->failure($calendar->name, $result->getMessage());
- continue;
- }
- $oldacl = '';
- if (isset($acl['manager'])) {
- $oldacl = $acl['manager'];
- }
- $result = $imapc->setACL($calendar->name, 'manager', 'lrs');
- if (is_a($result, 'PEAR_Error')) {
- $reporter->failure($calendar->name, $result->getMessage());
- continue;
- }
+ /**
+ * Return the dispatcher.
+ *
+ * @return Horde_Controller_Dispatcher The dispatcher.
+ *
+ * @throws Horde_Exception
+ */
+ public function getDispatcher()
+ {
+ if (!isset($this->_dispatcher)) {
+ if (empty($this->_params['dispatch']['controllerDir'])) {
+ $controllerDir = dirname(__FILE__) . '/FreeBusy/Controller';
+ } else {
+ $controllerDir = $this->_params['dispatch']['controllerDir'];
}
- /* Update the cache */
- $result = $this->_cache->store($access);
- if (is_a($result, 'PEAR_Error')) {
- $reporter->failure($calendar->name, $result->getMessage());
- continue;
+ if (empty($this->_params['dispatch']['viewsDir'])) {
+ $viewsDir = dirname(__FILE__) . '/FreeBusy/View';
+ } else {
+ $viewsDir = $this->_params['dispatch']['viewsDir'];
}
- /* Revert the acl */
- if ($access->user == 'manager' && $oldacl) {
- $result = $imapc->setACL($calendar->name, 'manager', $oldacl);
- if (is_a($result, 'PEAR_Error')) {
- $reporter->failure($calendar->name, $result->getMessage());
- continue;
- }
- }
+ $context = array(
+ 'mapper' => $this->getMapper(),
+ 'controllerDir' => $controllerDir,
+ 'viewsDir' => $viewsDir,
+ // 'logger' => '',
+ );
- $reporter->success($calendar->name);
+ $this->_dispatcher = Horde_Controller_Dispatcher::singleton($context);
+ }
+ return $this->_dispatcher;
+ }
+
+ /**
+ * Handle the current request.
+ *
+ * @return NULL
+ */
+ public function dispatch()
+ {
+ try {
+ $this->getDispatcher()->dispatch($this->getRequest());
+ } catch (Exception $e) {
+ //@todo: Error view
+ throw $e;
}
- return $lines;
}
}
-
-
diff --git a/framework/Kolab_FreeBusy/lib/Horde/Kolab/FreeBusy/Controller/FreebusyController.php b/framework/Kolab_FreeBusy/lib/Horde/Kolab/FreeBusy/Controller/FreebusyController.php
new file mode 100644
index 000000000..6902ea1de
--- /dev/null
+++ b/framework/Kolab_FreeBusy/lib/Horde/Kolab/FreeBusy/Controller/FreebusyController.php
@@ -0,0 +1,347 @@
+
+ * @author Steffen Hansen