From b0a6bf08d2387ca6175c83c8d1e0a8757942624b Mon Sep 17 00:00:00 2001 From: Gunnar Wrobel Date: Sat, 10 Oct 2009 23:12:06 +0200 Subject: [PATCH] Intermediate step in refactoring Kolab_Server. --- framework/Kolab_Server/lib/Horde/Kolab/Server.php | 720 ++------------------- .../Kolab_Server/lib/Horde/Kolab/Server/Base.php | 327 ++++++++++ .../lib/Horde/Kolab/Server/Connection.php | 43 ++ .../Horde/Kolab/Server/Connection/Simpleldap.php | 67 ++ .../Horde/Kolab/Server/Connection/Splittedldap.php | 78 +++ .../lib/Horde/Kolab/Server/Exception.php | 49 +- .../lib/Horde/Kolab/Server/Factory.php | 324 ++++++++-- .../Kolab_Server/lib/Horde/Kolab/Server/File.php | 40 +- .../lib/Horde/Kolab/Server/Filtered.php | 75 +++ .../Kolab_Server/lib/Horde/Kolab/Server/Ldap.php | 652 +++++-------------- .../Kolab_Server/lib/Horde/Kolab/Server/List.php | 43 ++ .../lib/Horde/Kolab/Server/List/Base.php | 105 +++ .../Kolab_Server/lib/Horde/Kolab/Server/Logged.php | 227 +++++++ .../Kolab_Server/lib/Horde/Kolab/Server/Mapped.php | 309 +++++++++ .../Kolab_Server/lib/Horde/Kolab/Server/Object.php | 10 +- .../Kolab/Server/Object/Kolabgroupofnames.php | 2 +- .../lib/Horde/Kolab/Server/Objects.php | 112 ++++ .../lib/Horde/Kolab/Server/Objects/Base.php | 243 +++++++ .../Kolab_Server/lib/Horde/Kolab/Server/Query.php | 126 ++++ .../lib/Horde/Kolab/Server/Query/Element.php | 58 ++ .../lib/Horde/Kolab/Server/Query/Element/And.php | 40 ++ .../Horde/Kolab/Server/Query/Element/Approx.php | 40 ++ .../Horde/Kolab/Server/Query/Element/Begins.php | 40 ++ .../Horde/Kolab/Server/Query/Element/Contains.php | 40 ++ .../lib/Horde/Kolab/Server/Query/Element/Ends.php | 40 ++ .../Horde/Kolab/Server/Query/Element/Equals.php | 40 ++ .../Horde/Kolab/Server/Query/Element/Greater.php | 40 ++ .../lib/Horde/Kolab/Server/Query/Element/Group.php | 81 +++ .../lib/Horde/Kolab/Server/Query/Element/Less.php | 40 ++ .../Horde/Kolab/Server/Query/Element/Mapped.php | 104 +++ .../lib/Horde/Kolab/Server/Query/Element/Not.php | 49 ++ .../lib/Horde/Kolab/Server/Query/Element/Or.php | 40 ++ .../Horde/Kolab/Server/Query/Element/Single.php | 88 +++ .../lib/Horde/Kolab/Server/Query/Ldap.php | 268 ++++++++ .../Kolab_Server/lib/Horde/Kolab/Server/Result.php | 50 ++ .../lib/Horde/Kolab/Server/Result/Ldap.php | 76 +++ .../Kolab_Server/lib/Horde/Kolab/Server/Schema.php | 62 ++ .../lib/Horde/Kolab/Server/Schema/Base.php | 273 ++++++++ .../Kolab_Server/lib/Horde/Kolab/Server/Search.php | 48 ++ .../lib/Horde/Kolab/Server/Search/Base.php | 103 +++ .../lib/Horde/Kolab/Server/Standard.php | 47 ++ .../lib/Horde/Kolab/Server/Structure.php | 63 +- .../lib/Horde/Kolab/Server/Structure/Base.php | 139 ++++ .../lib/Horde/Kolab/Server/Structure/Ldap.php | 27 +- .../Kolab_Server/lib/Horde/Kolab/Server/Test.php | 53 +- framework/Kolab_Server/package.xml | 112 +++- .../test/Horde/Kolab/Server/AdminTest.php | 2 + .../test/Horde/Kolab/Server/Autoload.php | 19 +- .../Kolab/Server/Connection/SimpleldapTest.php | 72 +++ .../Kolab/Server/Connection/SplittedldapTest.php | 78 +++ .../test/Horde/Kolab/Server/GroupTest.php | 4 +- .../test/Horde/Kolab/Server/InetorgpersonTest.php | 2 + .../Server/KolabgermanbankarrangementTest.php | 2 + .../Horde/Kolab/Server/KolabinetorgpersonTest.php | 2 + .../Horde/Kolab/Server/Kolabpop3accountTest.php | 14 +- .../test/Horde/Kolab/Server/LdapBase.php | 45 ++ .../test/Horde/Kolab/Server/ObjectTest.php | 2 + .../test/Horde/Kolab/Server/OrgPersonTest.php | 2 + .../test/Horde/Kolab/Server/PersonTest.php | 2 + .../test/Horde/Kolab/Server/Query/ElementTest.php | 212 ++++++ .../test/Horde/Kolab/Server/Query/LdapTest.php | 181 ++++++ .../test/Horde/Kolab/Server/Result/LdapTest.php | 90 +++ .../test/Horde/Kolab/Server/Scenario.php | 36 +- .../test/Horde/Kolab/Server/Server/FactoryTest.php | 120 ++++ .../Horde/Kolab/Server/Server/InterfaceTest.php | 36 ++ .../test/Horde/Kolab/Server/Server/LdapTest.php | 363 +++++++++++ .../test/Horde/Kolab/Server/Server/LoggedTest.php | 167 +++++ .../test/Horde/Kolab/Server/Server/SearchTest.php | 221 +++++++ .../test/Horde/Kolab/Server/Server/ServerTest.php | 329 ++++++++++ .../test/Horde/Kolab/Server/Server/TestTest.php | 626 ++++++++++++++++++ .../test/Horde/Kolab/Server/UserTest.php | 2 + 71 files changed, 6820 insertions(+), 1422 deletions(-) create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Base.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Connection.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Connection/Simpleldap.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Connection/Splittedldap.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Filtered.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/List.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/List/Base.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Logged.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Mapped.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Objects.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Objects/Base.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Query.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/And.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Approx.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Begins.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Contains.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Ends.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Equals.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Greater.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Group.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Less.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Mapped.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Not.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Or.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Single.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Ldap.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Result.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Result/Ldap.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Schema.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Schema/Base.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Search.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Search/Base.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Standard.php create mode 100644 framework/Kolab_Server/lib/Horde/Kolab/Server/Structure/Base.php create mode 100644 framework/Kolab_Server/test/Horde/Kolab/Server/Connection/SimpleldapTest.php create mode 100644 framework/Kolab_Server/test/Horde/Kolab/Server/Connection/SplittedldapTest.php create mode 100644 framework/Kolab_Server/test/Horde/Kolab/Server/LdapBase.php create mode 100644 framework/Kolab_Server/test/Horde/Kolab/Server/Query/ElementTest.php create mode 100644 framework/Kolab_Server/test/Horde/Kolab/Server/Query/LdapTest.php create mode 100644 framework/Kolab_Server/test/Horde/Kolab/Server/Result/LdapTest.php create mode 100644 framework/Kolab_Server/test/Horde/Kolab/Server/Server/FactoryTest.php create mode 100644 framework/Kolab_Server/test/Horde/Kolab/Server/Server/InterfaceTest.php create mode 100644 framework/Kolab_Server/test/Horde/Kolab/Server/Server/LdapTest.php create mode 100644 framework/Kolab_Server/test/Horde/Kolab/Server/Server/LoggedTest.php create mode 100644 framework/Kolab_Server/test/Horde/Kolab/Server/Server/SearchTest.php create mode 100644 framework/Kolab_Server/test/Horde/Kolab/Server/Server/ServerTest.php create mode 100644 framework/Kolab_Server/test/Horde/Kolab/Server/Server/TestTest.php diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server.php b/framework/Kolab_Server/lib/Horde/Kolab/Server.php index 47f327d35..facd7fe44 100644 --- a/framework/Kolab_Server/lib/Horde/Kolab/Server.php +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server.php @@ -12,18 +12,7 @@ */ /** - * The Autoloader allows us to omit "require/include" statements. - */ -require_once 'Horde/Autoloader.php'; - -/** - * We need Log.php for the Log constants - */ -require_once 'Log.php'; - -/** - * This class provides methods to deal with Kolab objects stored in - * the Kolab object db. + * This class defines the interface of a generic Kolab user database. * * Copyright 2008-2009 The Horde Project (http://www.horde.org/) * @@ -36,715 +25,142 @@ require_once 'Log.php'; * @license http://www.fsf.org/copyleft/lgpl.html LGPL * @link http://pear.horde.org/index.php?package=Kolab_Server */ -abstract class Horde_Kolab_Server +interface Horde_Kolab_Server { - /** Maximum accepted level for the object class hierarchy */ - const MAX_HIERARCHY = 100; - - /** - * Server parameters. - * - * @var array - */ - public $params = array(); - - /** - * The UID of the current user. - * - * @var string - */ - public $uid; - - /** - * The search methods offered by the object defined for this server. - * - * @var array - */ - protected $searches; - - /** - * The structure handler for this server. - * - * @var Horde_Kolab_Server_Structure - */ - public $structure; - - /** - * A cache for object attribute definitions. - * - * @var array - */ - protected $attributes; - - /** - * The data cache. - * - * @var Horde_Cache - */ - protected $cache; - - /** - * The log handler. - * - * @var Horde_Log_Logger - */ - protected $logger; - - /** - * Construct a new Horde_Kolab_Server object. - * - * @param array $params Parameter array. - */ - public function __construct(Horde_Kolab_Server_Structure $structure, - $params = array()) - { - $structure->setServer($this); - $this->structure = $structure; - $this->params = $params; - - if (!isset($this->params['cache_lifetime'])) { - $this->params['cache_lifetime'] = 300; - } - - if (isset($params['uid'])) { - $this->uid = $params['uid']; - } - - /** Initialize the search operations supported by this server. */ - $this->searches = $this->getSearchOperations(); - } - - /** - * Set the optional log handler. - * - * @param Horde_Log_Logger $logger The log handler. - * - * @return NULL - */ - public function setLogger(Horde_Log_Logger $logger) - { - $this->logger = $logger; - } - - /** - * Set the optional cache handler. - * - * @param Horde_Cache $cache The cache handler. - * - * @return NULL - */ - public function setCache(Horde_Cache $cache) - { - $this->cache = $cache; - } - - /** - * Attempts to return a reference to a concrete Horde_Kolab_Server - * instance based on $driver. It will only create a new instance - * if no Horde_Kolab_Server instance with the same parameters currently - * exists. - * - * This method must be invoked as: - * $var = &Horde_Kolab_Server::singleton() - * - * @param array $params An array of optional login parameters. May - * contain "uid" (for the login uid), "user" - * (if the uid is not yet known), and "pass" - * (for a password). - * - * @return Horde_Kolab_Server The concrete Horde_Kolab_Server reference. - * - * @throws Horde_Kolab_Server_Exception If the driver configuration is - * missing or the given user could not - * be identified. - */ - static public function &singleton($params = array()) - { - global $conf; - - static $instances = array(); - - $provider = new stdClass; - - $sparam = $params; - $sparam['pass'] = isset($sparam['pass']) - ? hash('sha256', $sparam['pass']) : ''; - ksort($sparam); - $signature = serialize($sparam); - - if (empty($instances[$signature])) { - - $user_pass = ''; - - if (!empty($params['driver'])) { - $provider->kolab_server_driver = $params['driver']; - unset($params['driver']); - } else if (isset($conf['kolab']['server']['driver'])) { - $provider->kolab_server_driver = $conf['kolab']['server']['driver']; - if (isset($conf['kolab']['server']['params'])) { - if (!is_array($params)) { - $params = $conf['kolab']['server']['params']; - } else { - if (isset($params['user']) && isset($params['pass'])) { - $user_pass = $params['pass']; - unset($params['pass']); - } - $params = array_merge($conf['kolab']['server']['params'], - $params); - } - } - } else { - throw new Horde_Kolab_Server_Exception( - 'The configuration for the Kolab server driver is missing!'); - } - - /* Provide caching */ - if (!empty($params['cache']['driver']) && class_exists('Horde_Cache')) { - $provider->cache = Horde_Cache::singleton($params['cache']['driver'], - isset($params['cache']['params']) - ? $params['cache']['params'] : null); - } - - /* Provide the structure */ - $structure = isset($params['structure']['driver']) - ? $params['structure']['driver'] : 'kolab'; - $structure_params = isset($params['structure']['params']) - ? $params['structure']['params'] : array(); - - $provider->kolab_server_structure = &Horde_Kolab_Server_Structure::factory($structure, - $structure_params); - - if (isset($params['user'])) { - - $provider->kolab_server_params = $params; - - $tmp_server = &Horde_Kolab_Server_Factory::getServer($provider); - - try { - $uid = $tmp_server->uidForIdOrMail($params['user']); - } catch (Horde_Kolab_Server_Exception $e) { - throw new Horde_Kolab_Server_Exception( - sprintf(_("Failed identifying the UID of the Kolab user %s. Error was: %s"), - $params['user'], - $e->getMessage())); - } - if ($uid === false) { - throw new Horde_Kolab_Server_MissingObjectException( - sprintf(_("Failed identifying the UID of the Kolab user %s. No such user."), - $params['user'])); - } - $params['uid'] = $uid; - unset($params['user']); - $params['pass'] = $user_pass; - } - - if (!empty($params['write']) && isset($params['host_master'])) { - $params['host'] = $params['host_master']; - } - - $provider->kolab_server_params = $params; - - $instances[$signature] = &Horde_Kolab_Server_Factory::getServer($provider); - } - - return $instances[$signature]; - } - - /** - * Get the connection to the master server for write access. - * - * @return Horde_Kolab_Server The Horde_Kolab_Server reference to the master - * server. - */ - function &getMaster() - { - if (!isset($this->params['host_master']) - || !empty($this->params['write']) - || $this->params['host_master'] == $this->params['host']) { - return $this; - } - $params = $this->params; - $params['write'] = true; - return Horde_Kolab_Server::singleton($params); - } - /** - * Stores the attribute definitions in the cache. + * Connect to the server. * - * @return Horde_Kolab_Server The concrete Horde_Kolab_Server reference. - */ - function shutdown() - { - if (isset($this->attributes)) { - if (isset($this->cache)) { - foreach ($this->attributes as $key => $value) { - $this->cache->set('attributes_' . $key, @serialize($value)); - } - } - } - } - - /** - * Fetch a Kolab object. - * - * This method will not retrieve any data from the server - * immediately. Instead it will simply generate a new instance for the - * desired object. - * - * The server data will only be accessed once you start reading the object - * data. - * - * This method can also be used in order to fetch non-existing objects that - * will be saved later. This is however not recommended and you should - * rather use the add($info) method for that. + * @param string $guid The global unique id of the user. + * @param string $pass The password. * - * If you do not provide the object type the server will try to determine it - * automatically based on the uid. As this requires reading data from the - * server it is recommended to specify the object type whenever it is known. - * - * If you do not specify a uid the object corresponding to the user bound to - * the server will be returned. - * - * @param string $uid The UID of the object to fetch. - * @param string $type The type of the object to fetch. - * - * @return Kolab_Object The corresponding Kolab object. + * @return NULL. * - * @throws Horde_Kolab_Server_Exception + * @throws Horde_Kolab_Server_Exception If the connection failed. */ - public function &fetch($uid = null, $type = null) - { - if (!isset($uid)) { - $uid = $this->uid; - } - if (empty($type)) { - $type = $this->determineType($uid); - } - - $object = &Horde_Kolab_Server_Object::factory($type, $uid, $this); - return $object; - } + public function connectGuid($guid = null, $pass = null); /** - * Add a Kolab object. - * - * @param array $info The object to store. + * Low level access to reading object data. * - * @return Kolab_Object The newly created Kolab object. + * This function provides direct access to the Server data. * - * @throws Horde_Kolab_Server_Exception If the type of the object to add has - * been left undefined or the object - * already exists. - */ - public function &add($info) - { - if (!isset($info['type'])) { - throw new Horde_Kolab_Server_Exception( - 'The type of a new object must be specified!'); - } - - $type = $info['type']; - unset($info['type']); - $object = &Horde_Kolab_Server_Object::factory($type, null, $this, $info); - if ($object->exists()) { - throw new Horde_Kolab_Server_Exception( - sprintf(_("The object with the uid \"%s\" does already exist!"), - $object->get(Horde_Kolab_Server_Object::ATTRIBUTE_UID))); - } - $object->save(); - return $object; - } - - /** - * Generate a hash representation for a list of objects. + * Usually you should use * - * The approach taken here is somewhat slow as the server data gets fetched - * into objects first which are then converted to hashes again. Since a - * server search will usually deliver the result as a hash the intermediate - * object conversion is inefficient. + * + * $object = $server->fetch('a server uid'); + * $variable = $object['attribute'] + * * - * But as the object classes are able to treat the attributes returned from - * the server with custom parsing, this is currently the preferred - * method. Especially for large result sets it would be better if this - * method would call a static object class function that operate on the - * result array returned from the server without using objects. + * to access object attributes. This is slower but takes special object + * handling into account (e.g. custom attribute parsing). * - * @param string $type The type of the objects to be listed - * @param array $params Additional parameters. + * @param string $guid The object to retrieve. * - * @return array An array of Kolab objects. + * @return array An array of attributes. * * @throws Horde_Kolab_Server_Exception - * - * @todo The LDAP driver needs a more efficient version of this call as it - * is not required to generate objects before returning data as a - * hash. It can be derived directly from the LDAP result. */ - public function listHash($type, $params = null) - { - $list = $this->listObjects($type, $params); - - if (isset($params['attributes'])) { - $attributes = $params['attributes']; - } else { - $attributes = null; - } - - $hash = array(); - foreach ($list as $uid => $entry) { - $hash[$uid] = $entry->toHash($attributes); - } - - return $hash; - } - - /** - * Returns the set of objects supported by this server. - * - * @return array An array of supported objects. - */ - public function getSupportedObjects() - { - return $this->structure->getSupportedObjects(); - } - - /** - * Determine the type of an object by its tree position and other - * parameters. - * - * @param string $uid The UID of the object to examine. - * - * @return string The class name of the corresponding object type. - * - * @throws Horde_Kolab_Server_Exception If the object type is unknown. - */ - public function determineType($uid) - { - return $this->structure->determineType($uid); - } + public function read($guid); /** - * Generates a UID for the given information. + * Low level access to reading some object attributes. * - * @param string $type The class name of the object to create. - * @param string $id The id of the object. - * @param array $info Any additional information about the object to create. + * @param string $guid The object to retrieve. + * @param string $attrs Restrict to these attributes. * - * @return string The UID. + * @return array An array of attributes. * * @throws Horde_Kolab_Server_Exception - */ - public function generateServerUid($type, $id, $info) - { - return $this->structure->generateServerUid($type, $id, $info); - } - - /** - * Return the attributes supported by the given object class. - * - * @param string $class Determine the attributes for this class. - * - * @return array The supported attributes. - * - * @throws Horde_Kolab_Server_Exception If the schema analysis fails. - */ - public function &getAttributes($class) - { - if (!isset($this->attributes)) { - if (isset($this->cache)) { - register_shutdown_function(array($this, 'shutdown')); - } - } - if (empty($this->attributes[$class])) { - - if (isset($this->cache)) { - $this->attributes[$class] = @unserialize($cache->get('attributes_' . $class, - $this->params['cache_lifetime'])); - } - - if (empty($this->attributes[$class])) { - - $childclass = $class; - $classes = array(); - $level = 0; - while ($childclass != 'Horde_Kolab_Server_Object' - && $level < self::MAX_HIERARCHY) { - $classes[] = $childclass; - $childclass = get_parent_class($childclass); - $level++; - } - - /** Finally add the basic object class */ - $classes[] = $childclass; - - if ($level == self::MAX_HIERARCHY) { - if (isset($this->logger)) { - $logger->err(sprintf('The maximal level of the object hierarchy has been exceeded for class \"%s\"!', - $class)); - } - } - - /** - * Collect attributes from bottom to top. - */ - $classes = array_reverse($classes); - - $types = array('defined', 'required', 'derived', 'collapsed', - 'defaults', 'locked', 'object_classes'); - foreach ($types as $type) { - $$type = array(); - } - - foreach ($classes as $childclass) { - $vars = get_class_vars($childclass); - if (isset($vars['init_attributes'])) { - foreach ($types as $type) { - /** - * If the user wishes to adhere to the schema - * information from the server we will skip the - * attributes defined within the object class here. - */ - if (!empty($this->params['schema_override']) - && in_array($type, 'defined', 'required')) { - continue; - } - if (isset($vars['init_attributes'][$type])) { - $$type = array_merge($$type, - $vars['init_attributes'][$type]); - } - } - } - } - - $attrs = array(); - - foreach ($object_classes as $object_class) { - $info = $this->getObjectclassSchema($object_class); - if (isset($info['may'])) { - $defined = array_merge($defined, $info['may']); - } - if (isset($info['must'])) { - $defined = array_merge($defined, $info['must']); - $required = array_merge($required, $info['must']); - } - foreach ($defined as $attribute) { - try { - $attrs[$attribute] = $this->getAttributeSchema($attribute); - } catch (Horde_Kolab_Server_Exception $e) { - /** - * If the server considers the attribute to be - * invalid we mark it. - */ - $attrs[$attribute] = array('invalid' => true); - } - } - foreach ($required as $attribute) { - $attrs[$attribute]['required'] = true; - } - foreach ($locked as $attribute) { - $attrs[$attribute]['locked'] = true; - } - foreach ($defaults as $attribute => $default) { - $attrs[$attribute]['default'] = $default; - } - $attrs[Horde_Kolab_Server_Object::ATTRIBUTE_OC]['default'] = $object_classes; - } - foreach ($derived as $key => $attributes) { - $supported = true; - if (isset($attributes['base'])) { - foreach ($attributes['base'] as $attribute) { - /** - * Usually derived attribute are determined on basis - * of one or more attributes. If any of these is not - * supported the derived attribute should not be - * included into the set of supported attributes. - */ - if (!isset($attrs[$attribute])) { - unset($derived[$attribute]); - $supported = false; - break; - } - } - } - if ($supported) { - $attrs[$key] = $attributes; - } - } - $check_collapsed = $collapsed; - foreach ($check_collapsed as $key => $attributes) { - if (isset($attributes['base'])) { - foreach ($attributes['base'] as $attribute) { - /** - * Usually collapsed attribute are determined on basis - * of one or more attributes. If any of these is not - * supported the collapsed attribute should not be - * included into the set of supported attributes. - */ - if (!isset($attrs[$attribute])) { - unset($collapsed[$attribute]); - } - } - } - } - $this->attributes[$class] = array($attrs, - array( - 'derived' => array_keys($derived), - 'collapsed' => $collapsed, - 'locked' => $locked, - 'required' => $required)); - } - } - return $this->attributes[$class]; - } - - /** - * Return the schema for the given objectClass. - * - * @param string $objectclass Fetch the schema for this objectClass. - * - * @return array The schema for the given objectClass. * - * @throws Horde_Kolab_Server_Exception If retrieval of the schema failed. + * @see Horde_Kolab_Server::read */ - protected function getObjectclassSchema($objectclass) - { - return array(); - } + public function readAttributes($guid, array $attrs); /** - * Return the schema for the given attribute. - * - * @param string $attribute Fetch the schema for this attribute. + * Finds object data matching a given set of criteria. * - * @return array The schema for the given attribute. + * @param Horde_Kolab_Server_Query $query The criteria for the search. + * @param array $params Additional search parameters. * - * @throws Horde_Kolab_Server_Exception If retrieval of the schema failed. - */ - protected function getAttributeSchema($attribute) - { - return array(); - } - - /** - * Returns the set of search operations supported by this server type. - * - * @return array An array of supported search operations. - */ - public function getSearchOperations() - { - $server_searches = array(); - foreach ($this->getSupportedObjects() as $sobj) { - if (in_array('getSearchOperations', get_class_methods($sobj))) { - $searches = call_user_func(array($sobj, 'getSearchOperations')); - foreach ($searches as $search) { - $server_searches[$search] = array('class' => $sobj); - } - } - } - return $server_searches; - } - - /** - * Capture undefined calls. - * - * @param string $method The name of the called method. - * @param array $args Arguments of the call. - * - * @return NULL. + * @return Horde_Kolab_Server_Result The result object. * * @throws Horde_Kolab_Server_Exception */ - public function __call($method, $args) - { - if (in_array($method, array_keys($this->searches))) { - array_unshift($args, $this); - if (isset($this->searches[$method])) { - return call_user_func_array(array($this->searches[$method]['class'], - $method), $args); - } - } - throw new Horde_Kolab_Server_Exception( - sprintf("The server type \"%s\" does not support method \"%s\"!", - get_class($this), $method)); - } + public function find( + Horde_Kolab_Server_Query $query, + array $params = array() + ); /** - * Stub for reading object data. + * Finds all object data below a parent matching a given set of criteria. * - * @param string $uid The object to retrieve. - * @param string $attrs Restrict to these attributes. + * @param Horde_Kolab_Server_Query $query The criteria for the search. + * @param string $parent The parent to search below. + * @param array $params Additional search parameters. * - * @return array An array of attributes. + * @return Horde_Kolab_Server_Result The result object. * * @throws Horde_Kolab_Server_Exception */ - abstract public function read($uid, $attrs = null); + public function findBelow( + Horde_Kolab_Server_Query $query, + $parent, + array $params = array() + ); /** - * Find object data matching a given set of criteria. + * Modify existing object data. * - * @param array $criteria The criteria for the search. - * @param string $params Additional search parameters. + * @param string $guid The GUID of the object to be added. + * @param array $data The attributes of the object to be stored. * - * @return array The result array. + * @return NULL * * @throws Horde_Kolab_Server_Exception */ - abstract public function find($criteria, $params = array()); + public function save($guid, array $data); /** - * Stub for saving object data. + * Add new object data. * - * @param string $uid The UID of the object to be added. - * @param array $data The attributes of the object to be added. - * @param boolean $exists Does the object already exist on the server? + * @param string $guid The GUID of the object to be added. + * @param array $data The attributes of the object to be added. * - * @return boolean True if saving succeeded. + * @return NULL * * @throws Horde_Kolab_Server_Exception */ - abstract public function save($uid, $data, $exists = false); + public function add($guid, array $data); /** - * Stub for deleting an object. + * Delete an object. * - * @param string $uid The UID of the object to be deleted. + * @param string $guid The GUID of the object to be deleted. * - * @return boolean True if deleting the object succeeded. + * @return NULL * * @throws Horde_Kolab_Server_Exception */ - abstract public function delete($uid); + public function delete($guid); /** - * Stub for renaming an object. + * Rename an object. * - * @param string $uid The UID of the object to be renamed. - * @param string $new The new UID of the object. + * @param string $guid The GUID of the object to be renamed. + * @param string $new The new GUID of the object. * - * @return boolean True if renaming succeeded. + * @return NULL * * @throws Horde_Kolab_Server_Exception */ - abstract public function rename($uid, $new); + public function rename($guid, $new); /** - * List all objects of a specific type - * - * @param string $type The type of the objects to be listed - * @param array $params Additional parameters. + * Return the database schema description. * - * @return array An array of Kolab objects. - * - * @throws Horde_Kolab_Server_Exception - */ - abstract public function listObjects($type, $params = null); - - /** - * Return the root of the UID values on this server. + * @return array The schema. * - * @return string The base UID on this server (base DN on ldap). + * @throws Horde_Kolab_Server_Exception If retrieval of the schema failed. */ - abstract public function getBaseUid(); - -} + public function getSchema(); +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Base.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Base.php new file mode 100644 index 000000000..6f244cefe --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Base.php @@ -0,0 +1,327 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * This class provides methods to deal with Kolab objects stored in + * the Kolab object db. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +abstract class Horde_Kolab_Server_Base implements Horde_Kolab_Server, + Horde_Kolab_Server_Objects, + Horde_Kolab_Server_Schema, + Horde_Kolab_Server_Search, + Horde_Kolab_Server_Structure +{ + /** + * Server parameters. + * + * @var array + */ + protected $params = array(); + + /** + * The user name of the current user. + * + * @var string + */ + private $_user = null; + + /** + * The structure handler for this server. + * + * @var Horde_Kolab_Server_Structure + */ + protected $structure; + + /** + * The search handler for this server. + * + * @var Horde_Kolab_Server_Search + */ + protected $search; + + /** + * The object handler for this server. + * + * @var Horde_Kolab_Server_Objects + */ + protected $objects; + + /** + * The data cache. + * + * @var mixed + */ + protected $cache = null; + + /** + * Construct a new Horde_Kolab_Server object. + * + * @param array $params Parameter array. + */ + public function __construct( + Horde_Kolab_Server_Objects $objects, + Horde_Kolab_Server_Structure $structure, + Horde_Kolab_Server_Search $search, + Horde_Kolab_Server_Schema $schema + ) { + $objects->setServer($this); + $structure->setServer($this); + $search->setServer($this); + $schema->setServer($this); + + $this->objects = $objects; + $this->structure = $structure; + $this->search = $search; + $this->schema = $schema; + } + + /** + * Set configuration parameters. + * + * @param array $params The parameters. + * + * @return NULL + */ + public function setParams(array $params) + { + $this->params = array_merge($this->params, $params); + + if (isset($this->params['uid'])) { + $this->uid = $this->params['uid']; + } + } + + /** + * Set the cache handler. + * + * @param mixed $cache The cache handler. + * + * @return NULL + */ + public function setCache($cache) + { + $this->cache = $cache; + } + + /** + * Connect to the server. + * + * @param string $user The user name. + * @param string $pass The password. + * + * @return NULL. + * + * @throws Horde_Kolab_Server_Exception If the connection failed. + */ + public function connect($user = null, $pass = null) + { + /** Do we need to switch the user? */ + if ($user !== $this->_current_user) { + $this->user = $this->_connect($user, $pass); + } + } + + /** + * Connect to the server. + * + * @param string $uid The unique id of the user. + * @param string $pass The password. + * + * @return NULL. + * + * @throws Horde_Kolab_Server_Exception If the connection failed. + */ + public function connectUid($uid = null, $pass = null) + { + } + + /** + * Add a Kolab object. + * + * @param array $info The object to store. + * + * @return Kolab_Object The newly created Kolab object. + * + * @throws Horde_Kolab_Server_Exception If the type of the object to add has + * been left undefined or the object + * already exists. + */ + public function add(array $info) + { + return $this->objects->add($info); + } + + /** + * Fetch a Kolab object. + * + * @param string $uid The UID of the object to fetch. + * @param string $type The type of the object to fetch. + * + * @return Kolab_Object The corresponding Kolab object. + * + * @throws Horde_Kolab_Server_Exception + */ + public function fetch($uid = null, $type = null) + { + return $this->objects->fetch($uid = null, $type = null); + } + + /** + * List all objects of a specific type + * + * @param string $type The type of the objects to be listed + * @param array $params Additional parameters. + * + * @return array An array of Kolab objects. + * + * @throws Horde_Kolab_Server_Exception + */ + public function listObjects($type, $params = null) + { + return $this->objects->listObjects($type, $params = null); + } + + /** + * Generate a hash representation for a list of objects. + * + * @param string $type The type of the objects to be listed + * @param array $params Additional parameters. + * + * @return array An array of Kolab objects. + * + * @throws Horde_Kolab_Server_Exception + */ + public function listHash($type, $params = null) + { + return $this->objects->listHash($type, $params = null); + } + + /** + * Returns the set of objects supported by this server. + * + * @return array An array of supported objects. + */ + public function getSupportedObjects() + { + return $this->structure->getSupportedObjects(); + } + + /** + * Determine the type of an object by its tree position and other + * parameters. + * + * @param string $uid The UID of the object to examine. + * + * @return string The class name of the corresponding object type. + * + * @throws Horde_Kolab_Server_Exception If the object type is unknown. + */ + public function determineType($uid) + { + return $this->structure->determineType($uid); + } + + /** + * Generates a UID for the given information. + * + * @param string $type The class name of the object to create. + * @param string $id The id of the object. + * @param array $info Any additional information about the object to create. + * + * @return string The UID. + * + * @throws Horde_Kolab_Server_Exception + */ + public function generateServerUid($type, $id, $info) + { + return $this->structure->generateServerUid($type, $id, $info); + } + + /** + * Return the schema for the given objectClass. + * + * @param string $objectclass Fetch the schema for this objectClass. + * + * @return array The schema for the given objectClass. + * + * @throws Horde_Kolab_Server_Exception If retrieval of the schema failed. + */ + public function getObjectclassSchema($objectclass) + { + return $this->schema->getObjectclassSchema($objectclass); + } + + /** + * Return the schema for the given attribute. + * + * @param string $attribute Fetch the schema for this attribute. + * + * @return array The schema for the given attribute. + * + * @throws Horde_Kolab_Server_Exception If retrieval of the schema failed. + */ + public function getAttributeSchema($attribute) + { + return $this->schema->getAttributeSchema($attribute); + } + + /** + * Return the attributes supported by the given object class. + * + * @param string $class Determine the attributes for this class. + * + * @return array The supported attributes. + * + * @throws Horde_Kolab_Server_Exception If the schema analysis fails. + */ + public function &getAttributes($class) + { + return $this->schema->getAttributes($class); + } + + /** + * Returns the set of search operations supported by this server type. + * + * @return array An array of supported search operations. + */ + public function getSearchOperations() + { + return $this->search->getSearchOperations(); + } + + /** + * Capture undefined calls and assume they refer to a search operation. + * + * @param string $method The name of the called method. + * @param array $args Arguments of the call. + * + * @return NULL. + * + * @throws Horde_Kolab_Server_Exception + */ + public function __call($method, $args) + { + return $this->search->__call($method, $args); + } +} diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Connection.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Connection.php new file mode 100644 index 000000000..2da34a2fe --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Connection.php @@ -0,0 +1,43 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Interface for connection handling. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +interface Horde_Kolab_Server_Connection +{ + /** + * Get the server read connection. + * + * @return mixed The connection for reading data. + */ + public function getRead(); + + /** + * Get the server write connection. + * + * @return mixed The connection for writing data. + */ + public function getWrite(); +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Connection/Simpleldap.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Connection/Simpleldap.php new file mode 100644 index 000000000..73c903f20 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Connection/Simpleldap.php @@ -0,0 +1,67 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * A simple LDAP setup without read-only slaves. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Connection_Simpleldap +implements Horde_Kolab_Server_Connection +{ + /** + * The LDAP connection handle. + * + * @var Net_LDAP2 + */ + private $_ldap; + + /** + * Constructor + * + * @param Net_LDAP2 $ldap The ldap connection. + */ + public function __construct(Net_LDAP2 $ldap) + { + $this->_ldap = $ldap; + } + + /** + * Get the server read connection. + * + * @return mixed The connection for reading data. + */ + public function getRead() + { + return $this->_ldap; + } + + /** + * Get the server write connection. + * + * @return mixed The connection for writing data. + */ + public function getWrite() + { + return $this->_ldap; + } +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Connection/Splittedldap.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Connection/Splittedldap.php new file mode 100644 index 000000000..b5781a7f1 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Connection/Splittedldap.php @@ -0,0 +1,78 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * A connection to a LDAP master/slave setup. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Connection_Splittedldap +implements Horde_Kolab_Server_Connection +{ + /** + * LDAP read connection handle. + * + * @var Net_LDAP2 + */ + private $_ldap_read; + + /** + * LDAP write connection handle. + * + * @var Net_LDAP2 + */ + private $_ldap_write; + + /** + * Constructor + * + * @param Net_LDAP2 $ldap_read The ldap_read connection. + * @param Net_LDAP2 $ldap_write The ldap_write connection. + */ + public function __construct( + Net_LDAP2 $ldap_read, + Net_LDAP2 $ldap_write + ) { + $this->_ldap_read = $ldap_read; + $this->_ldap_write = $ldap_write; + } + + /** + * Get the server read connection. + * + * @return mixed The connection for reading data. + */ + public function getRead() + { + return $this->_ldap_read; + } + + /** + * Get the server write connection. + * + * @return mixed The connection for writing data. + */ + public function getWrite() + { + return $this->_ldap_write; + } +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Exception.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Exception.php index dfc1cfedc..44260dddc 100644 --- a/framework/Kolab_Server/lib/Horde/Kolab/Server/Exception.php +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Exception.php @@ -30,45 +30,20 @@ class Horde_Kolab_Server_Exception extends Horde_Exception /** * Constants to define the error type. */ - const SYSTEM = 1; - const EMPTY_RESULT = 2; - const INVALID_INFORMATION = 3; - /** - * The array of available error messages. These are connected to the error - * codes used above and might be used to differentiate between what we show - * the user in the frontend and what we actually log in the backend. - * - * @var array - */ - protected $messages; + /** Unknown error type */ + const SYSTEM = 1; - /** - * Exception constructor - * - * @param mixed $message The exception message, a PEAR_Error object, or an - * Exception object. - * @param mixed $code A numeric error code, or - * an array from error_get_last(). - */ - public function __construct($message = null, $code = null) - { - $this->setMessages(); + /** The LDAP extension is missing */ + const MISSING_LDAP_EXTENSION = 2; - parent::__construct($message, $code); - } + /** Binding to the LDAP server failed */ + const BIND_FAILED = 3; + + const EMPTY_RESULT = 4; + + const INVALID_INFORMATION = 5; + + const INVALID_QUERY = 6; - /** - * Initialize the messages handled by this exception. - * - * @return NULL - */ - protected function setMessages() - { - $this->messages = array( - self::SYSTEM => _("An internal error occured."), - self::EMPTY_RESULT => _("No result was found."), - self::INVALID_INFORMATION => _("The information provided is invalid."), - ); - } } diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Factory.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Factory.php index 06d8e5843..a9938ccd6 100644 --- a/framework/Kolab_Server/lib/Horde/Kolab/Server/Factory.php +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Factory.php @@ -12,11 +12,6 @@ */ /** - * The Autoloader allows us to omit "require/include" statements. - */ -require_once 'Horde/Autoloader.php'; - -/** * A factory for Kolab server objects. * * Copyright 2008-2009 The Horde Project (http://www.horde.org/) @@ -33,90 +28,297 @@ require_once 'Horde/Autoloader.php'; class Horde_Kolab_Server_Factory { /** - * Attempts to return a concrete Horde_Kolab_Server instance. + * Singleton instances. * - * @param Horde_Injector $injector The object providing our dependencies. + * @var array + */ + static private $_instances = array(); + + /** + * Setup the machinery to create Horde_Kolab_Server objects. * - * @return Horde_Kolab_Server The newly created concrete Horde_Kolab_Server - * instance. + * @param array $configuration The parameters required to create + * the desired Horde_Kolab_Server object. + * @param Horde_Injector $injector The object providing our dependencies. * - * @throws Horde_Kolab_Server_Exception If the requested Horde_Kolab_Server - * subclass could not be found. + * @return NULL */ - static public function &getServer(Horde_Injector $injector) + static public function setup(array $configuration, Horde_Injector $injector) { - $driver = 'Horde_Kolab_Server_Ldap'; - $params = array(); + self::setupObjects($injector); + self::setupSearch($injector); + self::setupSchema($injector); - try { - $config = $injector->getInstance('Horde_Kolab_Server_Config'); + self::setupStructure( + isset($configuration['structure']) + ? $configuration['structure'] : array(), + $injector + ); + unset($configuration['structure']); - if (isset($config->driver)) { - $driver = $config->driver; - } - if (isset($config->params)) { - $params = $config->params; - } - } catch (ReflectionException $e) { - } + self::setupCache( + $injector, + isset($configuration['cache']) + ? $configuration['cache'] : null + ); + unset($configuration['cache']); - $class = 'Horde_Kolab_Server_' . ucfirst(basename($driver)); - if (!class_exists($class)) { - throw new Horde_Kolab_Server_Exception('Server type definition "' . $class . '" missing.'); - } + self::setupLogger( + $injector, + isset($configuration['logger']) + ? $configuration['logger'] : null + ); + unset($configuration['logger']); - $server = new $class($injector->getInstance('Horde_Kolab_Server_Structure'), - $params); + self::setupServer($configuration, $injector); + } + + /** + * Setup the machinery to create a Horde_Kolab_Server_Objects handler. + * + * @param Horde_Injector $injector The object providing our dependencies. + * + * @return NULL + */ + static protected function setupObjects(Horde_Injector $injector) + { + $injector->bindImplementation( + 'Horde_Kolab_Server_Objects', + 'Horde_Kolab_Server_Objects_Base' + ); + } - try { - $server->setCache($injector->getInstance('Horde_Kolab_Server_Cache')); - } catch (ReflectionException $e) { + /** + * Setup the machinery to create a Horde_Kolab_Server_Structure handler. + * + * @param array $configuration The parameters required to create + * the desired + * Horde_Kolab_Server_Structure handler. + * @param Horde_Injector $injector The object providing our dependencies. + * + * @return NULL + */ + static protected function setupStructure( + array $configuration, + Horde_Injector $injector + ) { + if (!isset($configuration['driver'])) { + $configuration['driver'] = 'Horde_Kolab_Server_Structure_Kolab'; } - try { - $server->setLogger($injector->getInstance('Horde_Kolab_Server_Logger')); - } catch (ReflectionException $e) { + switch (ucfirst(strtolower($configuration['driver']))) { + case 'Ldap': + case 'Kolab': + $driver = 'Horde_Kolab_Server_Structure_' + . ucfirst(strtolower($configuration['driver'])); + break; + default: + $driver = $configuration['driver']; + break; } - return $server; + $injector->bindImplementation('Horde_Kolab_Server_Structure', $driver); } /** - * Attempts to return a concrete Horde_Kolab_Server_Structure instance. + * Setup the machinery to create a Horde_Kolab_Server_Search handler. * * @param Horde_Injector $injector The object providing our dependencies. * - * @return Horde_Kolab_Server_Structure The newly created concrete - * Horde_Kolab_Server_Structure - * instance. + * @return NULL + */ + static protected function setupSearch(Horde_Injector $injector) + { + $injector->bindImplementation( + 'Horde_Kolab_Server_Search', + 'Horde_Kolab_Server_Search_Base' + ); + } + + /** + * Setup the machinery to create a Horde_Kolab_Server_Schema handler. + * + * @param Horde_Injector $injector The object providing our dependencies. * - * @throws Horde_Kolab_Server_Exception If the requested - * Horde_Kolab_Server_Structure - * subclass could not be found. + * @return NULL */ - static public function &getStructure(Horde_Injector $injector) + static protected function setupSchema(Horde_Injector $injector) { - $driver = 'Horde_Kolab_Server_Structure_Kolab'; - $params = array(); + $injector->bindImplementation( + 'Horde_Kolab_Server_Schema', + 'Horde_Kolab_Server_Schema_Base' + ); + } - try { - $config = $injector->getInstance('Horde_Kolab_Server_Structure_Config'); + /** + * Provide a cache handler for Horde_Kolab_Server. + * + * @param Horde_Injector $injector The object providing our dependencies. + * @param mixed $instance The cache handler or empty if it + * should be created. + * + * @return NULL + */ + static protected function setupCache( + Horde_Injector $injector, + $instance = null + ) { + if (empty($instance)) { + $instance = new Horde_Cache_Null(); + } + $injector->setInstance('Horde_Kolab_Server_Cache', $instance); + } - if (isset($config->driver)) { - $driver = $config->driver; - } - if (isset($config->params)) { - $params = $config->params; + /** + * Provide a log handler for Horde_Kolab_Server. + * + * @param Horde_Injector $injector The object providing our dependencies. + * @param mixed $instance The log handler or empty if it + * should be created. + * + * @return NULL + */ + static protected function setupLogger( + Horde_Injector $injector, + $instance = null + ) { + if (empty($instance)) { + $instance = new Horde_Log_Logger(new Horde_Log_Handler_Null()); + } + $injector->setInstance('Horde_Kolab_Server_Logger', $instance); + } + + if (empty($this->_ldap_read)) { + $this->handleError( + Net_LDAP2::checkLDAPExtension(), + Horde_Kolab_Server_Exception::MISSING_LDAP_EXTENSION + ); + + $this->_ldap_read = new Net_LDAP2($this->params); + + if (isset($this->params['host_master']) + && $this->params['host_master'] == $this->params['host'] + ) { + + $params = $this->params; + $params['host'] = $this->params['host_master']; + + $this->_ldap_write = new Net_LDAP2($params); + } else { + $this->_ldap_write = $this->_ldap_read; } - } catch (ReflectionException $e) { } - //@todo: either we use driver names or real class names. - //$class = 'Horde_Kolab_Server_Structure_' . ucfirst(basename($driver)); - if (!class_exists($driver)) { - throw new Horde_Kolab_Server_Exception('Structure type definition "' . $driver . '" missing.'); + if ($write) { + return $this->_ldap_write; + } else { + return $this->_ldap_read; + } + + /** + * Setup the machinery to create a Horde_Kolab_Server. + * + * @param array $configuration The parameters required to create + * the desired Horde_Kolab_Server. + * @param Horde_Injector $injector The object providing our dependencies. + * + * @return NULL + */ + static protected function setupServer( + array $configuration, + Horde_Injector $injector + ) { + if (empty($configuration['driver'])) { + $configuration['driver'] = 'Horde_Kolab_Server_Ldap'; + } + + $config = new stdClass; + + switch (ucfirst(strtolower($configuration['driver']))) { + case 'Ldap': + case 'Test': + case 'File': + $config->driver = 'Horde_Kolab_Server_' + . ucfirst(strtolower($configuration['driver'])); + break; + default: + $config->driver = $configuration['driver']; + break; + } + + $config->params = isset($configuration['params']) + ? $configuration['params'] : array(); + + $injector->setInstance('Horde_Kolab_Server_Config', $config); + + $injector->bindFactory( + 'Horde_Kolab_Server', + 'Horde_Kolab_Server_Factory', + 'getServer' + ); + } + + /** + * Attempts to return a concrete Horde_Kolab_Server instance. + * + * @param Horde_Injector $injector The object providing our dependencies. + * + * @return Horde_Kolab_Server The newly created concrete Horde_Kolab_Server + * instance. + */ + static public function &getServer(Horde_Injector $injector) + { + $config = $injector->getInstance('Horde_Kolab_Server_Config'); + $driver = $config->driver; + $server = new $driver( + $injector->getInstance('Horde_Kolab_Server_Objects'), + $injector->getInstance('Horde_Kolab_Server_Structure'), + $injector->getInstance('Horde_Kolab_Server_Search'), + $injector->getInstance('Horde_Kolab_Server_Schema') + ); + $server->setParams($config->params); + $server->setCache($injector->getInstance('Horde_Kolab_Server_Cache')); + $server->setLogger($injector->getInstance('Horde_Kolab_Server_Logger')); + + return $server; + } + + /** + * Attempts to return a reference to a concrete Horde_Kolab_Server + * instance based on $driver. It will only create a new instance + * if no Horde_Kolab_Server instance with the same parameters currently + * exists. + * + * This method must be invoked as: + * + * $var = &Horde_Kolab_Server::singleton() + * + * + * @param array $params An array of parameters. + * + * @return Horde_Kolab_Server The concrete Horde_Kolab_Server reference. + */ + static public function &singleton($params = array()) + { + $signature = hash('md5', serialize(ksort($params))); + + if (!isset(self::$_instances[$signature])) { + $params['cache'] = Horde_Cache::singleton( + $GLOBALS['conf']['cache']['driver'], + //@todo: Can we omit Horde:: here? + Horde::getDriverConfig( + 'cache', + $GLOBALS['conf']['cache']['driver'] + ) + ); + $params['logger'] = Horde::getLogger(); + $injector = new Horde_Injector(new Horde_Injector_TopLevel()); + self::setup($params, $injector); + self::$_instances[$signature] = $injector->getInstance( + 'Horde_Kolab_Server' + ); } - $structure = new $driver($params); - return $structure; + + return self::$_instances[$signature]; } } \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/File.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/File.php index 5cb63b7d0..ba69a17f2 100644 --- a/framework/Kolab_Server/lib/Horde/Kolab/Server/File.php +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/File.php @@ -37,21 +37,33 @@ class Horde_Kolab_Server_File extends Horde_Kolab_Server_Test private $_file; /** - * Construct a new Horde_Kolab_Server object. + * Set configuration parameters. * - * @param array $params Parameter array. + * @param array $params The parameters. + * + * @return NULL */ - public function __construct(Horde_Kolab_Server_Structure $structure, - $params = array()) + public function setParams(array $params) { if (isset($params['file'])) { $this->_file = $params['file']; - } else { - throw new Horde_Kolab_Server_Exception('The file based driver requires a \'file\' parameter.'); } - parent::__construct($structure, $params); + + parent::setParams($params); } + /** + * Get the file parameter. + * + * @return NULL + */ + private function _getFile() + { + if (empty($this->_file)) { + throw new Horde_Kolab_Server_Exception('The file based driver requires a \'file\' parameter.'); + } + return $this->_file; + } /** * Load the current state of the database. @@ -60,7 +72,7 @@ class Horde_Kolab_Server_File extends Horde_Kolab_Server_Test */ protected function load() { - $raw_data = file_get_contents($this->_file); + $raw_data = file_get_contents($this->_getFile()); if (!$raw_data === false) { $data = @unserialize($raw_data); if ($data !== false) { @@ -69,7 +81,7 @@ class Horde_Kolab_Server_File extends Horde_Kolab_Server_Test $error = error_get_last(); if (isset($this->logger)) { $this->logger->warn(sprintf('Horde_Kolab_Server_file failed to read the database from %s. Error was: %s', - $this->_file, $error['message'])); + $this->_getFile(), $error['message'])); } $this->data = array(); } @@ -84,12 +96,12 @@ class Horde_Kolab_Server_File extends Horde_Kolab_Server_Test protected function store() { $raw_data = serialize($this->data); - $result = @file_put_contents($this->_file, $raw_data); + $result = @file_put_contents($this->_getFile(), $raw_data); if ($result === false) { $error = error_get_last(); if (isset($this->logger)) { $this->logger->warn(sprintf('Horde_Kolab_Server_file failed to store the database in %s. Error was: %s', - $this->_file, $error['message'])); + $this->_getFile(), $error['message'])); } } } @@ -101,7 +113,7 @@ class Horde_Kolab_Server_File extends Horde_Kolab_Server_Test */ public function clean() { - unlink($this->_file); + unlink($this->_getFile()); $this->data = array(); $this->store(); } @@ -111,8 +123,8 @@ class Horde_Kolab_Server_File extends Horde_Kolab_Server_Test * * @return string The path to the database. */ - public function getStoragePAth() + public function getStoragePath() { - return $this->_file; + return $this->_getFile(); } } diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Filtered.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Filtered.php new file mode 100644 index 000000000..ab77cbede --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Filtered.php @@ -0,0 +1,75 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * This class provides methods to deal with objects stored in + * a filtered LDAP db. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Filtered extends Horde_Kolab_Server_Ldap +{ + /** + * A global filter to add to each query. + * + * @var string + */ + private $_filter; + + /** + * Constructor. + * + * @param Horde_Kolab_Server_Connection $connection The LDAP connection. + * @param string $base_dn The LDAP server base DN. + * @param string $filter A global filter to add + * to all queries. + */ + public function __construct( + Horde_Kolab_Server_Connection $connection, + $base_dn, + $filter = null + ) { + parent::__construct($connection, $base_dn); + $this->_filter = $filter; + } + + /** + * Finds all object data below a parent matching a given set of criteria. + * + * @param array $criteria The criteria for the search. + * @param string $parent The parent to search below. + * @param array $params Additional search parameters. + * + * @return Horde_Kolab_Server_Result The result object. + * + * @throws Horde_Kolab_Server_Exception + */ + public function findBelow(array $criteria, $parent, array $params = array()) + { + $query = new Horde_Kolab_Server_Query_Ldap($criteria); + $query_string = (string) $query; + if (!empty($this->_filter)) { + $query_string = '(&(' . $this->_filter . ')' . $query_string . ')'; + } + return $this->_search($query_string, $params, $parent); + } +} diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Ldap.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Ldap.php index 61aad377c..8294e2e9b 100644 --- a/framework/Kolab_Server/lib/Horde/Kolab/Server/Ldap.php +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Ldap.php @@ -26,21 +26,21 @@ * @license http://www.fsf.org/copyleft/lgpl.html LGPL * @link http://pear.horde.org/index.php?package=Kolab_Server */ -class Horde_Kolab_Server_Ldap extends Horde_Kolab_Server +abstract class Horde_Kolab_Server_Ldap implements Horde_Kolab_Server { /** - * LDAP connection handle. + * The GUID of the current user. * - * @var Net_LDAP2 + * @var string */ - private $_ldap; + private $_guid; /** - * The configuration for connection to the LDAP server. + * LDAP connection handle. * - * @var array + * @var Horde_Kolab_Server_Connection */ - private $_config; + private $_conn; /** * Base DN of the LDAP server. @@ -50,449 +50,242 @@ class Horde_Kolab_Server_Ldap extends Horde_Kolab_Server private $_base_dn; /** - * The LDAP schemas. - * - * @var Net_LDAP2_Schema - */ - private $_schema; - - /** - * The last search result. This can be used to retrieve additional - * information about the LDAP search result (e.g. if the size - * limit for the search has been exceeded). - * - * @var Net_LDAP2_Search - */ - public $lastSearch; - - /** - * Construct a new Horde_Kolab_Server_ldap object. + * Constructor. * - * @param array $params Parameter array. + * @param Horde_Kolab_Server_Connection $connection The LDAP connection. + * @param string $base_dn The LDAP server base DN. + * @param string $filter A global filter to add + * to all queries. */ - public function __construct(Horde_Kolab_Server_Structure $structure, - $params = array()) - { - if (!isset($params['charset'])) { - $params['charset'] = 'UTF-8'; - } - - $base_config = array('host' => 'localhost', - 'port' => 389, - 'version' => 3, - 'starttls' => false, - 'uid' => '', - 'pass' => '', - 'basedn' => '', - 'charset' => '', - 'options' => array(), - 'auto_reconnect' => true); - - $config = array_merge($base_config, $params); - - $this->_base_dn = $config['basedn']; - - $config['binddn'] = $config['uid']; - $config['bindpw'] = $config['pass']; - - $this->_config = $config; - - $this->connect(); - - parent::__construct($structure, $params); + public function __construct( + Horde_Kolab_Server_Connection $connection, + $base_dn, + $filter = null + ) { + $this->_conn = $connection; + $this->_base_dn = $base_dn; } - /** - * Connect to the LDAP server. + * Connect to the server. + * + * @param string $guid The global unique id of the user. + * @param string $pass The password. * * @return NULL. * * @throws Horde_Kolab_Server_Exception If the connection failed. */ - protected function connect() + public function connectGuid($guid = null, $pass = null) { - $this->_ldap = Net_LDAP2::connect($this->_config); - if (is_a($this->_ldap, 'PEAR_Error')) { - throw new Horde_Kolab_Server_Exception($this->_ldap, - Horde_Kolab_Server_Exception::SYSTEM); + /** Do we need to switch the user? */ + if ((empty($guid) && empty($this->_guid)) + || $guid !== $this->_guid + ) { + $this->_handleError( + $this->_conn->getRead()->bind($guid, $pass), + Horde_Kolab_Server_Exception::BIND_FAILED + ); + $this->_guid = $guid; } } /** - * Map attributes defined within this library their their real world - * counterparts. - * - * @param array $data The data that has been read and needs to be mapped. - * - * @return NULL - */ - protected function unmapAttributes(&$data) - { - if (!empty($this->params['map'])) { - foreach ($this->params['map'] as $attribute => $map) { - if (isset($data[$map])) { - $data[$attribute] = $data[$map]; - unset($data[$map]); - } - } - } - } - - /** - * Map attributes defined within this library into their real world - * counterparts. - * - * @param array $data The data to be written. + * Low level access to reading object data. * - * @return NULL - */ - protected function mapAttributes(&$data) - { - if (!empty($this->params['map'])) { - foreach ($this->params['map'] as $attribute => $map) { - if (isset($data[$attribute])) { - $data[$map] = $data[$attribute]; - unset($data[$attribute]); - } - } - } - } - - /** - * Map attribute keys defined within this library into their real world - * counterparts. + * @param string $guid The object to retrieve. * - * @param array $keys The attribute keys. + * @return array An array of attributes. * - * @return NULL + * @throws Horde_Kolab_Server_Exception If the search operation hit an error + * or returned no result. */ - protected function mapKeys(&$keys) + public function read($guid) { - if (!empty($this->params['map'])) { - foreach ($this->params['map'] as $attribute => $map) { - $key = array_search($attribute, $keys); - if ($key !== false) { - $keys[$key] = $map; - } - } - } - } - - /** - * Map a single attribute key defined within this library into its real - * world counterpart. - * - * @param array $field The attribute name. - * - * @return The real name of this attribute on the server we connect to. - */ - protected function mapField($field) - { - if (!empty($this->params['map']) - && isset($this->params['map'][$field])) { - return $this->params['map'][$field]; - } - return $field; + $params = array('scope' => 'base'); + $data = $this->_search(null, $params, $guid)->asArray(); + if ($data->count() == 0) { + throw new Horde_Kolab_Server_Exception( + 'Empty result!', + Horde_Kolab_Server_Exception::EMPTY_RESULT + ); + } + return array_pop($data->asArray()); } /** - * Low level access to reading object data. - * - * This function provides fast access to the Server data. - * - * Usually you should use - * - * $object = $server->fetch('a server uid'); - * $variable = $object['attribute'] - * - * to access object attributes. This is slower but takes special object - * handling into account (e.g. custom attribute parsing). + * Low level access to reading some object attributes. * - * @param string $uid The object to retrieve. + * @param string $guid The object to retrieve. * @param string $attrs Restrict to these attributes. * - * @return array|boolean An array of attributes or false if the specified - * object was not found. + * @return array An array of attributes. * - * @throws Horde_Kolab_Server_Exception If the search operation retrieved a - * problematic result. + * @throws Horde_Kolab_Server_Exception If the search operation hit an error + * or returned no result. */ - public function read($uid, $attrs = null) + public function readAttributes($guid, array $attrs) { - $params = array('scope' => 'base'); - if (!empty($attrs)) { - $params['attributes'] = $attrs; - } - - $data = $this->search(null, $params, $uid); - if (empty($data)) { - throw new Horde_Kolab_Server_Exception(_("Empty result!"), - Horde_Kolab_Server_Exception::EMPTY_RESULT); + $params = array( + 'scope' => 'base', + 'attributes' => $attrs + ); + $data = $this->_search(null, $params, $guid); + if ($data->count() == 0) { + throw new Horde_Kolab_Server_Exception( + 'Empty result!', + Horde_Kolab_Server_Exception::EMPTY_RESULT + ); } - - return array_pop($data); + return array_pop($data->asArray()); } /** - * Save an object. + * Finds object data matching a given set of criteria. + * + * @param Horde_Kolab_Server_Query $query The criteria for the search. + * @param array $params Additional search parameters. * - * @param string $uid The UID of the object to be added. - * @param array $data The attributes of the object to be changed. - * @param boolean $exists Does the object already exist on the server? + * @return Horde_Kolab_Server_Result The result object. * - * @return boolean True if saving succeeded. + * @throws Horde_Kolab_Server_Exception */ - public function save($uid, $data, $exists = false) - { - $this->mapAttributes($data); - - if ($exists === false) { - $entry = Net_LDAP2_Entry::createFresh($uid, $data['add']); - $result = $this->_ldap->add($entry); - if ($result instanceOf PEAR_Error) { - throw new Horde_Kolab_Server_Exception($result, - Horde_Kolab_Server_Exception::SYSTEM); - } - } else { - $entry = $this->_ldap->getEntry($uid, $data['attributes']); - $result = $this->_ldap->modify($entry, $data); - if ($result instanceOf PEAR_Error) { - throw new Horde_Kolab_Server_Exception($result, - Horde_Kolab_Server_Exception::SYSTEM); - } - } - if (isset($this->logger)) { - $this->logger->debug(sprintf('The object \"%s\" has been successfully saved!', - $uid)); - } - return true; + public function find( + Horde_Kolab_Server_Query $query, + array $params = array() + ) { + $this->findBelow($query, $this->_base_dn, $params); } /** - * Delete an object. + * Finds all object data below a parent matching a given set of criteria. * - * @param string $uid The UID of the object to be deleted. + * @param Horde_Kolab_Server_Query $query The criteria for the search. + * @param string $parent The parent to search below. + * @param array $params Additional search parameters. * - * @return boolean True if saving succeeded. + * @return Horde_Kolab_Server_Result The result object. * * @throws Horde_Kolab_Server_Exception */ - public function delete($uid) - { - $result = $this->_ldap->delete($uid); - if ($result instanceOf PEAR_Error) { - throw new Horde_Kolab_Server_Exception($result, - Horde_Kolab_Server_Exception::SYSTEM); - } - if (isset($this->logger)) { - $this->logger(sprintf('The object \"%s\" has been successfully deleted!', - $uid)); - } - return true; - } + abstract public function findBelow( + Horde_Kolab_Server_Query $query, + $parent, + array $params = array() + ); /** - * Rename an object. + * Modify existing object data. * - * @param string $uid The UID of the object to be renamed. - * @param string $new The new UID of the object. + * @param string $guid The GUID of the object to be added. + * @param array $data The attributes of the object to be stored. * - * @return boolean True if renaming succeeded. + * @return NULL * * @throws Horde_Kolab_Server_Exception */ - public function rename($uid, $new) + public function save($guid, array $data) { - /* Net_LDAP modifies the variable */ - $old = $uid; - $result = $this->_ldap->move($old, $new); - if ($result instanceOf PEAR_Error) { - throw new Horde_Kolab_Server_Exception($result, - Horde_Kolab_Server_Exception::SYSTEM); - } - if (isset($this->logger)) { - $this->logger->debug(sprintf('The object \"%s\" has been successfully renamed to \"%s\"!', - $uid, $new)); - } - return true; + $entry = $this->_conn->getWrite()->getEntry($guid, $data['attributes']); + $this->_handleError( + $this->_conn->getWrite()->modify($entry, $data), + Horde_Kolab_Server_Exception::SYSTEM + ); } /** - * List all objects of a specific type. + * Add new object data. * - * @param string $type The type of the objects to be listed - * @param array $params Additional parameters. + * @param string $guid The GUID of the object to be added. + * @param array $data The attributes of the object to be added. * - * @return array An array of Kolab objects. + * @return NULL * * @throws Horde_Kolab_Server_Exception - * - * @todo Sorting */ - public function listObjects($type, $params = null) + public function add($guid, array $data) { - if (empty($params['base_dn'])) { - $base = $this->_base_dn; - } else { - $base = $params['base_dn']; - } - - $result = Horde_Kolab_Server_Object::loadClass($type); - $vars = get_class_vars($type); - $criteria = call_user_func(array($type, 'getFilter')); - $filter = $this->searchQuery($criteria); - $sort = $vars['sort_by']; - - if (isset($params['sort'])) { - $sort = $params['sort']; - } - - $options = array('scope' => 'sub'); - if (isset($params['attributes'])) { - $options['attributes'] = $params['attributes']; - } else { - $options['attributes'] = $this->getAttributes($type); - } - - $data = $this->search($filter, $options, $base); - if (empty($data)) { - return array(); - } - - if ($sort) { - /* FIXME */ - /* $data = $result->as_sorted_struct(); */ - /*$this->sort($result, $sort); */ - } - - if (isset($params['from'])) { - $from = $params['from']; - } else { - $from = -1; - } - - if (isset($params['to'])) { - $sort = $params['to']; - } else { - $to = -1; - } - - if (!empty($vars['required_group'])) { - $required_group = new Horde_Kolab_Server_Object_Kolabgroupofnames($this, - null, - $vars['required_group']); - } - - $objects = array(); - foreach ($data as $uid => $entry) { - if (!empty($vars['required_group'])) { - if (!$required_group->exists() || !$required_group->isMember($uid)) { - continue; - } - } - $objects[$uid] = &Horde_Kolab_Server_Object::factory($type, $uid, - $this, $entry); - } - return $objects; + $entry = Net_LDAP2_Entry::createFresh($guid, $data); + $this->_handleError($entry, Horde_Kolab_Server_Exception::SYSTEM); + $this->_handleError( + $this->_conn->getWrite()->add($entry), + Horde_Kolab_Server_Exception::SYSTEM + ); } /** - * Return the root of the UID values on this server. + * Delete an object. * - * @return string The base UID on this server (base DN on ldap). - */ - public function getBaseUid() - { - return $this->_base_dn; - } - - /** - * Return the ldap schema. + * @param string $guid The UID of the object to be deleted. * - * @return Net_LDAP2_Schema The LDAP schema. + * @return NULL * - * @throws Horde_Kolab_Server_Exception If retrieval of the schema failed. + * @throws Horde_Kolab_Server_Exception */ - private function _getSchema() + public function delete($guid) { - if (!isset($this->_schema)) { - $result = $this->_ldap->schema(); - if ($result instanceOf PEAR_Error) { - throw new Horde_Kolab_Server_Exception($result, - Horde_Kolab_Server_Exception::SYSTEM); - } - $this->_schema = &$result; - } - return $this->_schema; + $this->_handleError( + $this->_conn->getWrite()->delete($guid), + Horde_Kolab_Server_Exception::SYSTEM + ); } /** - * Return the schema for the given objectClass. + * Rename an object. * - * @param string $objectclass Fetch the schema for this objectClass. + * @param string $guid The UID of the object to be renamed. + * @param string $new The new UID of the object. * - * @return array The schema for the given objectClass. + * @return NULL * - * @throws Horde_Kolab_Server_Exception If retrieval of the schema failed. + * @throws Horde_Kolab_Server_Exception */ - protected function getObjectclassSchema($objectclass) + public function rename($guid, $new) { - if (!empty($this->_config['schema_support'])) { - $schema = $this->_getSchema(); - $info = $schema->get('objectclass', $objectclass); - if ($info instanceOf PEAR_Error) { - throw new Horde_Kolab_Server_Exception($info, - Horde_Kolab_Server_Exception::SYSTEM); - } - return $info; - } - return parent::getObjectclassSchema($objectclass); + $this->_handleError( + $this->_conn->getWrite()->move($old, $new), + Horde_Kolab_Server_Exception::SYSTEM + ); } /** - * Return the schema for the given attribute. - * - * @param string $attribute Fetch the schema for this attribute. + * Return the ldap schema. * - * @return array The schema for the given attribute. + * @return Net_LDAP2_Schema The LDAP schema. * * @throws Horde_Kolab_Server_Exception If retrieval of the schema failed. */ - protected function getAttributeSchema($attribute) + public function getSchema() { - if (!empty($this->_config['schema_support'])) { - $schema = $this->_getSchema(); - $info = $schema->get('attribute', $attribute); - if ($info instanceOf PEAR_Error) { - throw new Horde_Kolab_Server_Exception($info, - Horde_Kolab_Server_Exception::SYSTEM); - } - return $info; - } - return parent::getAttributeSchema($attribute); + $result = $this->_conn->getRead()->schema(); + $this->_handleError($result, Horde_Kolab_Server_Exception::SYSTEM); + return $result; } /** - * Find object data matching a given set of criteria. + * Check for a PEAR Error and convert it to an exception if necessary. * - * @param array $criteria The criteria for the search. - * @param string $params Additional search parameters. + * @param mixed $result The result to be tested. + * @param code $code The error code to use in case the result is an error. * - * @return array The result array. + * @return NULL. * - * @throws Horde_Kolab_Server_Exception + * @throws Horde_Kolab_Server_Exception If the connection failed. */ - public function find($criteria, $params = array()) - { - return $this->search($this->searchQuery($criteria), $params); + private function _handleError( + $result, + $code = Horde_Kolab_Server_Exception::SYSTEM + ) { + if (is_a($result, 'PEAR_Error')) { + throw new Horde_Kolab_Server_Exception($result, $code); + } } /** * Search for object data. * * @param string $filter The LDAP search filter. - * @param string $params Additional search parameters. + * @param array $params Additional search parameters. * @param string $base The search base * * @return array The result array. @@ -500,153 +293,14 @@ class Horde_Kolab_Server_Ldap extends Horde_Kolab_Server * @throws Horde_Kolab_Server_Exception If the search operation encountered * a problem. */ - public function search($filter = null, $params = array(), $base = null) - { - if (isset($params['attributes'])) { - $this->mapKeys($params['attributes']); - } - - if (!isset($base)) { - $base = $this->_base_dn; - } - $this->lastSearch = &$this->_ldap->search($base, $filter, $params); - if (is_a($this->lastSearch, 'PEAR_Error')) { - throw new Horde_Kolab_Server_Exception($this->lastSearch, - Horde_Kolab_Server_Exception::SYSTEM); - } - $data = $this->lastSearch->as_struct(); - if (is_a($data, 'PEAR_Error')) { - throw new Horde_Kolab_Server_Exception($data, - Horde_Kolab_Server_Exception::SYSTEM); - } - $this->unmapAttributes($data); - return $data; - } - - /** - * Get the LDAP object classes for the given DN. - * - * @param string $uid DN of the object. - * - * @return array An array of object classes. - * - * @throws Horde_Kolab_Server_Exception If the object has no - * object classes. - */ - public function getObjectClasses($uid) - { - $object = $this->read($uid, array(Horde_Kolab_Server_Object::ATTRIBUTE_OC)); - if (!isset($object[Horde_Kolab_Server_Object::ATTRIBUTE_OC])) { - throw new Horde_Kolab_Server_Exception(sprintf("The object %s has no %s attribute!", - $uid, Horde_Kolab_Server_Object::ATTRIBUTE_OC), - Horde_Kolab_Server_Exception::SYSTEM); - } - $result = array_map('strtolower', - $object[Horde_Kolab_Server_Object::ATTRIBUTE_OC]); - return $result; - } - - /** - * Build a search query. - * - * Taken from the Turba LDAP driver. - * - * @param array $criteria The array of criteria. - * - * @return string An LDAP query filter. - */ - public function searchQuery($criteria) - { - /* Accept everything. */ - $filter = '(' . strtolower(Horde_Kolab_Server_Object::ATTRIBUTE_OC) . '=*)'; - - /* Build the LDAP filter. */ - if (count($criteria)) { - $f = $this->buildSearchQuery($criteria); - if ($f instanceOf Net_LDAP2_Filter) { - $filter = $f->asString(); - } - } - - /* Add source-wide filters, which are _always_ AND-ed. */ - if (!empty($this->params['filter'])) { - $filter = '(&' . '(' . $this->params['filter'] . ')' . $filter . ')'; - } - return $filter; - } - - /** - * Build a piece of a search query. - * - * Taken from the Turba LDAP driver. - * - * @param array $criteria The array of criteria. - * - * @return string An LDAP query fragment. - */ - protected function &buildSearchQuery($criteria) + private function _search($filter, array $params, $base) { - if (!is_array($criteria)) { - throw new Horde_Kolab_Server_Exception(sprintf("Invalid search criteria \"%s\"!", - $criteria), - Horde_Kolab_Server_Exception::SYSTEM); - } - if (isset($criteria['field'])) { - $rhs = isset($criteria['test']) ? $criteria['test'] : ''; - /* Keep this in for reference as we did not really test servers with different encoding yet */ - // require_once 'Horde/Nls.php'; - //$rhs = Horde_String::convertCharset($criteria['test'], Horde_Nls::getCharset(), $this->params['charset']); - switch ($criteria['op']) { - case '=': - $op = 'equals'; - break; - default: - $op = $criteria['op']; - } - return Net_LDAP2_Filter::create($this->mapField($criteria['field']), - $op, $rhs); - } - foreach ($criteria as $key => $vals) { - if (!empty($vals['OR']) - || !empty($vals['AND']) - || !empty($vals['NOT'])) { - $parts = $this->buildSearchQuery($vals); - if (count($parts) > 1) { - if (!empty($vals['OR'])) { - $operator = '|'; - } else if (!empty($vals['NOT'])) { - $operator = '!'; - } else { - $operator = '&'; - } - return Net_LDAP2_Filter::combine($operator, $parts); - } else { - return $parts[0]; - } - } else { - $parts = array(); - foreach ($vals as $test) { - $parts[] = &$this->buildSearchQuery($test); - } - switch ($key) { - case 'OR': - $operator = '|'; - break; - case 'AND': - $operator = '&'; - break; - case 'NOT': - $operator = '!'; - break; - } - if (count($parts) > 1) { - return Net_LDAP2_Filter::combine($operator, $parts); - } else if ($operator == '!') { - return Net_LDAP2_Filter::combine($operator, $parts[0]); - } else { - return $parts[0]; - } - } - } + $this->_lastSearch = &$this->_conn->getRead()->search( + $base, $filter, $params + ); + $this->_handleError( + $this->_lastSearch, Horde_Kolab_Server_Exception::SYSTEM + ); + return new Horde_Kolab_Server_Result_Ldap($this->_lastSearch); } } diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/List.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/List.php new file mode 100644 index 000000000..7a9ad87d6 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/List.php @@ -0,0 +1,43 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Interface for server lists. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +interface Horde_Kolab_Server_List +{ + /** + * List all objects of a specific type. + * + * @param string $type The type of the objects to be listed + * @param array $params Additional parameters. + * + * @return array An array of Kolab objects. + * + * @throws Horde_Kolab_Server_Exception + * + * @todo Sorting + */ + public function listObjects($type, $params = null); +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/List/Base.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/List/Base.php new file mode 100644 index 000000000..2c5785650 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/List/Base.php @@ -0,0 +1,105 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * A server list implementation. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_List_Base implements Horde_Kolab_Server_List +{ + /** + * List all objects of a specific type. + * + * @param string $type The type of the objects to be listed + * @param array $params Additional parameters. + * + * @return array An array of Kolab objects. + * + * @throws Horde_Kolab_Server_Exception + * + * @todo Sorting + */ + public function listObjects($type, $params = null) + { + $result = Horde_Kolab_Server_Object::loadClass($type); + $vars = get_class_vars($type); + $criteria = call_user_func(array($type, 'getFilter')); + $filter = $this->searchQuery($criteria); + $sort = $vars['sort_by']; + + if (isset($params['sort'])) { + $sort = $params['sort']; + } + + $options = array('scope' => 'sub'); + if (isset($params['attributes'])) { + $options['attributes'] = $params['attributes']; + } else { + $options['attributes'] = $this->getAttributes($type); + } + + $data = $this->search($filter, $options, $base); + if (empty($data)) { + return array(); + } + + if ($sort) { + /* FIXME */ + /* $data = $result->as_sorted_struct(); */ + /*$this->sort($result, $sort); */ + } + + if (isset($params['from'])) { + $from = $params['from']; + } else { + $from = -1; + } + + if (isset($params['to'])) { + $sort = $params['to']; + } else { + $to = -1; + } + + if (!empty($vars['required_group'])) { + $required_group = new Horde_Kolab_Server_Object_Kolabgroupofnames( + $this, + null, + $vars['required_group'] + ); + } + + $objects = array(); + foreach ($data as $uid => $entry) { + if (!empty($vars['required_group'])) { + if (!$required_group->exists() || !$required_group->isMember($uid)) { + continue; + } + } + $objects[$uid] = &Horde_Kolab_Server_Object::factory( + $type, $uid, $this, $entry + ); + } + return $objects; + } +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Logged.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Logged.php new file mode 100644 index 000000000..072642bc1 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Logged.php @@ -0,0 +1,227 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * A server delegation that logs server access via Horde_Log_Logger. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Logged implements Horde_Kolab_Server +{ + /** + * The server we delegate to. + * + * @var Horde_Kolab_Server + */ + private $_server; + + /** + * The log handler. + * + * @var Horde_Log_Logger + */ + private $_logger; + + /** + * Constructor. + * + * @param Horde_Kolab_Server $server The base server connection. + * @param Horde_Log_Logger $logger THe log handler. + */ + public function __construct( + Horde_Kolab_Server $server, + Horde_Log_Logger $logger + ) { + $this->_server = $server; + $this->_logger = $logger; + } + + /** + * Connect to the server. + * + * @param string $guid The global unique id of the user. + * @param string $pass The password. + * + * @return NULL. + * + * @throws Horde_Kolab_Server_Exception If the connection failed. + */ + public function connectGuid($guid = null, $pass = null) + { + $this->_server->connectGuid($guid, $pass); + } + + /** + * Low level access to reading object data. + * + * @param string $guid The object to retrieve. + * @param array $attrs Restrict to these attributes. + * + * @return array An array of attributes. + * + * @throws Horde_Kolab_Server_Exception If the search operation hit an error + * or returned no result. + */ + public function read($guid, array $attrs = array()) + { + return $this->_server->read($guid); + } + + /** + * Low level access to reading some object attributes. + * + * @param string $guid The object to retrieve. + * @param string $attrs Restrict to these attributes. + * + * @return array An array of attributes. + * + * @throws Horde_Kolab_Server_Exception + * + * @see Horde_Kolab_Server::read + */ + public function readAttributes($guid, array $attrs) + { + return $this->_server->readAttributes($guid, $attrs); + } + + /** + * Finds object data matching a given set of criteria. + * + * @param Horde_Kolab_Server_Query $query The criteria for the search. + * @param array $params Additional search parameters. + * + * @return Horde_Kolab_Server_Result The result object. + * + * @throws Horde_Kolab_Server_Exception + */ + public function find( + Horde_Kolab_Server_Query $query, + array $params = array() + ) { + return $this->_server->find($query, $params); + } + + /** + * Finds all object data below a parent matching a given set of criteria. + * + * @param Horde_Kolab_Server_Query $query The criteria for the search. + * @param string $parent The parent to search below. + * @param array $params Additional search parameters. + * + * @return Horde_Kolab_Server_Result The result object. + * + * @throws Horde_Kolab_Server_Exception + */ + public function findBelow( + Horde_Kolab_Server_Query $query, + $parent, + array $params = array() + ) { + return $this->_server->findBelow($query, $parent, $params); + } + + /** + * Modify existing object data. + * + * @param string $guid The GUID of the object to be added. + * @param array $data The attributes of the object to be added. + * + * @return NULL + * + * @throws Horde_Kolab_Server_Exception + */ + public function save($guid, array $data) + { + $this->_server->save($guid, $data); + $this->_logger->info( + sprintf("The object \"%s\" has been successfully saved!", $guid) + ); + } + + /** + * Add new object data. + * + * @param string $guid The GUID of the object to be added. + * @param array $data The attributes of the object to be added. + * + * @return NULL + * + * @throws Horde_Kolab_Server_Exception + */ + public function add($guid, array $data) + { + $this->_server->add($guid, $data); + $this->_logger->info( + sprintf("The object \"%s\" has been successfully added!", $guid) + ); + } + + /** + * Delete an object. + * + * @param string $guid The GUID of the object to be deleted. + * + * @return NULL + * + * @throws Horde_Kolab_Server_Exception + */ + public function delete($guid) + { + $this->_server->delete($guid); + $this->_logger->info( + sprintf("The object \"%s\" has been successfully deleted!", $guid) + ); + } + + /** + * Rename an object. + * + * @param string $guid The GUID of the object to be renamed. + * @param string $new The new GUID of the object. + * + * @return NULL + * + * @throws Horde_Kolab_Server_Exception + */ + public function rename($guid, $new) + { + $this->_server->rename($guid, $new); + $this->_logger->info( + sprintf( + "The object \"%s\" has been successfully renamed to \"%s\"!", + $guid, $new + ) + ); + } + + /** + * Return the ldap schema. + * + * @return Net_LDAP2_Schema The LDAP schema. + * + * @throws Horde_Kolab_Server_Exception If retrieval of the schema failed. + */ + public function getSchema() + { + return $this->_server->getSchema(); + } +} diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Mapped.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Mapped.php new file mode 100644 index 000000000..5287b592d --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Mapped.php @@ -0,0 +1,309 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * A server delegation that maps object attributes. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Mapped implements Horde_Kolab_Server +{ + /** + * The server we delegate to. + * + * @var Horde_Kolab_Server + */ + private $_server; + + /** + * The attribute mapping. + * + * @var array + */ + private $_mapping; + + /** + * Constructor. + * + * @param Horde_Kolab_Server $server The base server connection. + * @param array $mapping The attribute mapping. + */ + public function __construct(Horde_Kolab_Server $server, array $mapping) + { + $this->_server = $server; + $this->_mapping = $mapping; + } + + /** + * Connect to the server. Use this method if the user name you can provide + * does not match a GUID. In this case it will be required to map this user + * name first. + * + * @param string $user The user name. + * @param string $pass The password. + * + * @return NULL. + * + * @throws Horde_Kolab_Server_Exception If the connection failed. + */ + public function connect($user = null, $pass = null) + { + $this->_server->connect($user, $pass); + } + + /** + * Connect to the server. + * + * @param string $guid The global unique id of the user. + * @param string $pass The password. + * + * @return NULL. + * + * @throws Horde_Kolab_Server_Exception If the connection failed. + */ + public function connectGuid($guid = null, $pass = null) + { + $this->_server->connectGuid($guid, $pass); + } + + /** + * Low level access to reading object data. + * + * @param string $guid The object to retrieve. + * @param array $attrs Restrict to these attributes. + * + * @return array An array of attributes. + * + * @throws Horde_Kolab_Server_Exception If the search operation hit an error + * or returned no result. + */ + public function read($guid, array $attrs = array()) + { + $data = $this->_server->read($guid); + $this->unmapAttributes($data); + return $data; + } + + /** + * Low level access to reading some object attributes. + * + * @param string $guid The object to retrieve. + * @param string $attrs Restrict to these attributes. + * + * @return array An array of attributes. + * + * @throws Horde_Kolab_Server_Exception + * + * @see Horde_Kolab_Server::read + */ + public function readAttributes($guid, array $attrs) + { + $this->mapKeys($attrs); + $data = $this->_server->readAttributes($guid, $attrs); + $this->unmapAttributes($data); + return $data; + } + + /** + * Finds object data matching a given set of criteria. + * + * @param array $criteria The criteria for the search. + * @param array $params Additional search parameters. + * + * @return array The result array. + * + * @throws Horde_Kolab_Server_Exception + */ + public function find(array $criteria, array $params = array()) + { + $criteria = new Horde_Kolab_Server_Query_Element_Mapped($criteria, $this); + $data = $this->_server->find($criteria, $params); + $this->unmapAttributes($data); + return $data; + } + + /** + * Finds all object data below a parent matching a given set of criteria. + * + * @param array $criteria The criteria for the search. + * @param string $parent The parent to search below. + * @param array $params Additional search parameters. + * + * @return array The result array. + * + * @throws Horde_Kolab_Server_Exception + */ + public function findBelow(array $criteria, $parent, array $params = array()) + { + $criteria = new Horde_Kolab_Server_Query_Element_Mapped($criteria, $this); + $data = $this->_server->findBelow($criteria, $parent, $params); + $this->unmapAttributes($data); + return $data; + } + + + /** + * Modify existing object data. + * + * @param string $guid The GUID of the object to be added. + * @param array $data The attributes of the object to be added. + * + * @return NULL + * + * @throws Horde_Kolab_Server_Exception + */ + public function save($guid, array $data) + { + $this->mapAttributes($data); + $this->_server->save($guid, $data); + } + + /** + * Add new object data. + * + * @param string $guid The GUID of the object to be added. + * @param array $data The attributes of the object to be added. + * + * @return NULL + * + * @throws Horde_Kolab_Server_Exception + */ + public function add($guid, array $data) + { + $this->mapAttributes($data); + $this->_server->add($guid, $data); + } + + /** + * Delete an object. + * + * @param string $guid The GUID of the object to be deleted. + * + * @return NULL + * + * @throws Horde_Kolab_Server_Exception + */ + public function delete($guid) + { + $this->_server->delete($guid); + } + + /** + * Rename an object. + * + * @param string $guid The GUID of the object to be renamed. + * @param string $new The new GUID of the object. + * + * @return NULL + * + * @throws Horde_Kolab_Server_Exception + */ + public function rename($guid, $new) + { + $this->_server->rename($guid, $new); + } + + /** + * Return the ldap schema. + * + * @return Net_LDAP2_Schema The LDAP schema. + * + * @throws Horde_Kolab_Server_Exception If retrieval of the schema failed. + */ + public function getSchema() + { + return $this->_server->getSchema(); + } + + + /** + * Map attributes defined within this library to their real world + * counterparts. + * + * @param array &$data The data that has been read and needs to be mapped. + * + * @return NULL + */ + protected function unmapAttributes(&$data) + { + foreach ($data as &$element) { + foreach ($this->mapping as $attribute => $map) { + if (isset($element[$map])) { + $element[$attribute] = $element[$map]; + unset($element[$map]); + } + } + } + } + + /** + * Map attributes defined within this library into their real world + * counterparts. + * + * @param array &$data The data to be written. + * + * @return NULL + */ + protected function mapAttributes(&$data) + { + foreach ($this->mapping as $attribute => $map) { + if (isset($data[$attribute])) { + $data[$map] = $data[$attribute]; + unset($data[$attribute]); + } + } + } + + /** + * Map attribute keys defined within this library into their real world + * counterparts. + * + * @param array &$keys The attribute keys. + * + * @return NULL + */ + protected function mapKeys(&$keys) + { + foreach ($this->mapping as $attribute => $map) { + $key = array_search($attribute, $keys); + if ($key !== false) { + $keys[$key] = $map; + } + } + } + + /** + * Map a single attribute key defined within this library into its real + * world counterpart. + * + * @param array $field The attribute name. + * + * @return The real name of this attribute on the server we connect to. + */ + public function mapField($field) + { + if (isset($this->mapping[$field])) { + return $this->mapping[$field]; + } + return $field; + } +} diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Object.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Object.php index c2a5a7167..193c4cac9 100644 --- a/framework/Kolab_Server/lib/Horde/Kolab/Server/Object.php +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Object.php @@ -916,6 +916,8 @@ class Horde_Kolab_Server_Object */ public function prepareChanges($info) { + $changes = array(); + if (!empty($this->attributes)) { foreach ($info as $key => $value) { if (!in_array($key, array_keys($this->attributes))) { @@ -1020,7 +1022,7 @@ class Horde_Kolab_Server_Object * meet the expectations. */ static protected function uidFromResult($result, - $restrict = Horde_Kolab_Server::RESULT_SINGLE) + $restrict = Horde_Kolab_Server_Object::RESULT_SINGLE) { if (empty($result)) { return false; @@ -1053,7 +1055,7 @@ class Horde_Kolab_Server_Object * meet the expectations. */ static protected function attrsFromResult($result, $attrs, - $restrict = Horde_Kolab_Server::RESULT_SINGLE) + $restrict = Horde_Kolab_Server_Object::RESULT_SINGLE) { switch ($restrict) { case self::RESULT_STRICT: @@ -1101,7 +1103,7 @@ class Horde_Kolab_Server_Object * @throws Horde_Kolab_Server_Exception */ static public function basicUidForSearch($server, $criteria, - $restrict = Horde_Kolab_Server::RESULT_SINGLE) + $restrict = Horde_Kolab_Server_Object::RESULT_SINGLE) { $params = array('attributes' => self::ATTRIBUTE_UID); $filter = $server->searchQuery($criteria); @@ -1123,7 +1125,7 @@ class Horde_Kolab_Server_Object * @throws Horde_Kolab_Server_Exception */ static public function attrsForSearch($server, $criteria, $attrs, - $restrict = Horde_Kolab_Server::RESULT_SINGLE) + $restrict = Horde_Kolab_Server_Object::RESULT_SINGLE) { $params = array('attributes' => $attrs); $filter = $server->searchQuery($criteria); diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Object/Kolabgroupofnames.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Object/Kolabgroupofnames.php index 1fd13d465..8604e8922 100644 --- a/framework/Kolab_Server/lib/Horde/Kolab/Server/Object/Kolabgroupofnames.php +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Object/Kolabgroupofnames.php @@ -89,7 +89,7 @@ class Horde_Kolab_Server_Object_Kolabgroupofnames extends Horde_Kolab_Server_Obj { switch ($attr) { case self::ATTRIBUTE_VISIBILITY: - //FIXME: This needs structural knowledge and should be in a + //@todo This needs structural knowledge and should be in a //structural class. return strpos($this->uid, 'cn=internal') === false; default: diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Objects.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Objects.php new file mode 100644 index 000000000..92aa7ce66 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Objects.php @@ -0,0 +1,112 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Interface for a server object list. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +interface Horde_Kolab_Server_Objects +{ + /** + * Add a Kolab object. + * + * @param array $info The object to store. + * + * @return Kolab_Object The newly created Kolab object. + * + * @throws Horde_Kolab_Server_Exception If the type of the object to add has + * been left undefined or the object + * already exists. + */ + public function add(array $info); + + /** + * Fetch a Kolab object. + * + * This method will not retrieve any data from the server + * immediately. Instead it will simply generate a new instance for the + * desired object. + * + * The server data will only be accessed once you start reading the object + * data. + * + * This method can also be used in order to fetch non-existing objects that + * will be saved later. This is however not recommended and you should + * rather use the add($info) method for that. + * + * If you do not provide the object type the server will try to determine it + * automatically based on the uid. As this requires reading data from the + * server it is recommended to specify the object type whenever it is known. + * + * If you do not specify a uid the object corresponding to the user bound to + * the server will be returned. + * + * @param string $uid The UID of the object to fetch. + * @param string $type The type of the object to fetch. + * + * @return Kolab_Object The corresponding Kolab object. + * + * @throws Horde_Kolab_Server_Exception + */ + public function fetch($uid = null, $type = null); + + /** + * List all objects of a specific type + * + * @param string $type The type of the objects to be listed + * @param array $params Additional parameters. + * + * @return array An array of Kolab objects. + * + * @throws Horde_Kolab_Server_Exception + */ + public function listObjects($type, $params = null); + + /** + * Generate a hash representation for a list of objects. + * + * The approach taken here is somewhat slow as the server data gets fetched + * into objects first which are then converted to hashes again. Since a + * server search will usually deliver the result as a hash the intermediate + * object conversion is inefficient. + * + * But as the object classes are able to treat the attributes returned from + * the server with custom parsing, this is currently the preferred + * method. Especially for large result sets it would be better if this + * method would call a static object class function that operate on the + * result array returned from the server without using objects. + * + * @param string $type The type of the objects to be listed + * @param array $params Additional parameters. + * + * @return array An array of Kolab objects. + * + * @throws Horde_Kolab_Server_Exception + * + * @todo The LDAP driver needs a more efficient version of this call as it + * is not required to generate objects before returning data as a + * hash. It can be derived directly from the LDAP result. + */ + public function listHash($type, $params = null); + +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Objects/Base.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Objects/Base.php new file mode 100644 index 000000000..63636e547 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Objects/Base.php @@ -0,0 +1,243 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * This class provides methods to deal with Kolab objects stored in + * the Kolab object db. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Objects_Base implements Horde_Kolab_Server_Objects +{ + /** + * A link to the server handler. + * + * @var Horde_Kolab_Server + */ + protected $server; + + /** + * Set the server reference for this object. + * + * @param Horde_Kolab_Server &$server A link to the server handler. + */ + public function setServer($server) + { + $this->server = $server; + } + + /** + * Fetch a Kolab object. + * + * This method will not retrieve any data from the server + * immediately. Instead it will simply generate a new instance for the + * desired object. + * + * The server data will only be accessed once you start reading the object + * data. + * + * This method can also be used in order to fetch non-existing objects that + * will be saved later. This is however not recommended and you should + * rather use the add($info) method for that. + * + * If you do not provide the object type the server will try to determine it + * automatically based on the uid. As this requires reading data from the + * server it is recommended to specify the object type whenever it is known. + * + * If you do not specify a uid the object corresponding to the user bound to + * the server will be returned. + * + * @param string $uid The UID of the object to fetch. + * @param string $type The type of the object to fetch. + * + * @return Kolab_Object The corresponding Kolab object. + * + * @throws Horde_Kolab_Server_Exception + */ + public function fetch($uid = null, $type = null) + { + if (!isset($uid)) { + $uid = $this->uid; + } + if (empty($type)) { + $type = $this->determineType($uid); + } + + $object = &Horde_Kolab_Server_Object::factory($type, $uid, $this); + return $object; + } + + /** + * Add a Kolab object. + * + * @param array $info The object to store. + * + * @return Kolab_Object The newly created Kolab object. + * + * @throws Horde_Kolab_Server_Exception If the type of the object to add has + * been left undefined or the object + * already exists. + */ + public function add(array $info) + { + if (!isset($info['type'])) { + throw new Horde_Kolab_Server_Exception( + 'The type of a new object must be specified!'); + } + + $type = $info['type']; + unset($info['type']); + $object = &Horde_Kolab_Server_Object::factory($type, null, $this, $info); + if ($object->exists()) { + throw new Horde_Kolab_Server_Exception( + sprintf(_("The object with the uid \"%s\" does already exist!"), + $object->get(Horde_Kolab_Server_Object::ATTRIBUTE_UID))); + } + $object->save(); + return $object; + } + + /** + * Generate a hash representation for a list of objects. + * + * The approach taken here is somewhat slow as the server data gets fetched + * into objects first which are then converted to hashes again. Since a + * server search will usually deliver the result as a hash the intermediate + * object conversion is inefficient. + * + * But as the object classes are able to treat the attributes returned from + * the server with custom parsing, this is currently the preferred + * method. Especially for large result sets it would be better if this + * method would call a static object class function that operate on the + * result array returned from the server without using objects. + * + * @param string $type The type of the objects to be listed + * @param array $params Additional parameters. + * + * @return array An array of Kolab objects. + * + * @throws Horde_Kolab_Server_Exception + * + * @todo The LDAP driver needs a more efficient version of this call as it + * is not required to generate objects before returning data as a + * hash. It can be derived directly from the LDAP result. + */ + public function listHash($type, $params = null) + { + $list = $this->listObjects($type, $params); + + if (isset($params['attributes'])) { + $attributes = $params['attributes']; + } else { + $attributes = null; + } + + $hash = array(); + foreach ($list as $uid => $entry) { + $hash[$uid] = $entry->toHash($attributes); + } + + return $hash; + } + + + /** + * List all objects of a specific type. + * + * @param string $type The type of the objects to be listed + * @param array $params Additional parameters. + * + * @return array An array of Kolab objects. + * + * @throws Horde_Kolab_Server_Exception + * + * @todo Sorting + * @todo Is this LDAP specific? + */ + public function listObjects($type, $params = null) + { + if (empty($params['base_dn'])) { + $base = $this->_base_dn; + } else { + $base = $params['base_dn']; + } + + $result = Horde_Kolab_Server_Object::loadClass($type); + $vars = get_class_vars($type); + $criteria = call_user_func(array($type, 'getFilter')); + $filter = $this->searchQuery($criteria); + $sort = $vars['sort_by']; + + if (isset($params['sort'])) { + $sort = $params['sort']; + } + + $options = array('scope' => 'sub'); + if (isset($params['attributes'])) { + $options['attributes'] = $params['attributes']; + } else { + $options['attributes'] = $this->getAttributes($type); + } + + $data = $this->search($filter, $options, $base); + if (empty($data)) { + return array(); + } + + if ($sort) { + /* FIXME */ + /* $data = $result->as_sorted_struct(); */ + /*$this->sort($result, $sort); */ + } + + if (isset($params['from'])) { + $from = $params['from']; + } else { + $from = -1; + } + + if (isset($params['to'])) { + $sort = $params['to']; + } else { + $to = -1; + } + + if (!empty($vars['required_group'])) { + $required_group = new Horde_Kolab_Server_Object_Kolabgroupofnames($this, + null, + $vars['required_group']); + } + + $objects = array(); + foreach ($data as $uid => $entry) { + if (!empty($vars['required_group'])) { + if (!$required_group->exists() || !$required_group->isMember($uid)) { + continue; + } + } + $objects[$uid] = &Horde_Kolab_Server_Object::factory($type, $uid, + $this, $entry); + } + return $objects; + } + +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Query.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query.php new file mode 100644 index 000000000..706e2ebd1 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query.php @@ -0,0 +1,126 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Interface for server queries. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +interface Horde_Kolab_Server_Query +{ + /** + * Return the query as a string. + * + * @return string The query in string format. + */ + public function __toString(); + + /** + * Convert the equals element to query format. + * + * @param Horde_Kolab_Server_Query_Element_Single $single The element to convert. + * + * @return mixed The query element in query format. + */ + public function convertEquals(Horde_Kolab_Server_Query_Element_Equals $equals); + + /** + * Convert the begins element to query format. + * + * @param Horde_Kolab_Server_Query_Element_Single $single The element to convert. + * + * @return mixed The query element in query format. + */ + public function convertBegins(Horde_Kolab_Server_Query_Element_Begins $begins); + + /** + * Convert the ends element to query format. + * + * @param Horde_Kolab_Server_Query_Element_Single $single The element to convert. + * + * @return mixed The query element in query format. + */ + public function convertEnds(Horde_Kolab_Server_Query_Element_Ends $ends); + + /** + * Convert the contains element to query format. + * + * @param Horde_Kolab_Server_Query_Element_Single $single The element to convert. + * + * @return mixed The query element in query format. + */ + public function convertContains(Horde_Kolab_Server_Query_Element_Contains $contains); + + /** + * Convert the less element to query format. + * + * @param Horde_Kolab_Server_Query_Element_Single $single The element to convert. + * + * @return mixed The query element in query format. + */ + public function convertLess(Horde_Kolab_Server_Query_Element_Less $less); + + /** + * Convert the greater element to query format. + * + * @param Horde_Kolab_Server_Query_Element_Single $single The element to convert. + * + * @return mixed The query element in query format. + */ + public function convertGreater(Horde_Kolab_Server_Query_Element_Greater $greater); + + /** + * Convert the approx element to query format. + * + * @param Horde_Kolab_Server_Query_Element_Single $single The element to convert. + * + * @return mixed The query element in query format. + */ + public function convertApprox(Horde_Kolab_Server_Query_Element_Approx $approx); + + /** + * Convert the not element to query format. + * + * @param Horde_Kolab_Server_Query_Element_Group $group The element to convert. + * + * @return mixed The query element in query format. + */ + public function convertNot(Horde_Kolab_Server_Query_Element_Not $not); + + /** + * Convert the and element to query format. + * + * @param Horde_Kolab_Server_Query_Element_Group $group The element to convert. + * + * @return mixed The query element in query format. + */ + public function convertAnd(Horde_Kolab_Server_Query_Element_And $and); + + /** + * Convert the or element to query format. + * + * @param Horde_Kolab_Server_Query_Element_Group $group The element to convert. + * + * @return mixed The query element in query format. + */ + public function convertOr(Horde_Kolab_Server_Query_Element_Group $or); +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element.php new file mode 100644 index 000000000..3071c6a96 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element.php @@ -0,0 +1,58 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Interface for server query elements. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +interface Horde_Kolab_Server_Query_Element +{ + /** + * Return the query element name. + * + * @return string The name of the query element. + */ + public function getName(); + + /** + * Return the value of this element. + * + * @return mixed The query value. + */ + public function getValue(); + + /** + * Return the elements of this group. + * + * @return mixed The group elements. + */ + public function getElements(); + + /** + * Convert this element to a query element. + * + * @return mixedd The element as query. + */ + public function convert(Horde_Kolab_Server_Query $writer); + +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/And.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/And.php new file mode 100644 index 000000000..abe52bacd --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/And.php @@ -0,0 +1,40 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * An element grouping by and. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Query_Element_And +extends Horde_Kolab_Server_Query_Element_Group +{ + /** + * Convert this element to a query element. + * + * @return mixed The element as query. + */ + public function convert(Horde_Kolab_Server_Query $writer) + { + return $writer->convertAnd($this); + } +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Approx.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Approx.php new file mode 100644 index 000000000..486ce564c --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Approx.php @@ -0,0 +1,40 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * An element expressing an 'approx' match. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Query_Element_Approx +extends Horde_Kolab_Server_Query_Element_Single +{ + /** + * Convert this element to a query element. + * + * @return mixed The element as query. + */ + public function convert(Horde_Kolab_Server_Query $writer) + { + return $writer->convertApprox($this); + } +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Begins.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Begins.php new file mode 100644 index 000000000..3686bc373 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Begins.php @@ -0,0 +1,40 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * An element expressing an 'begins' match. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Query_Element_Begins +extends Horde_Kolab_Server_Query_Element_Single +{ + /** + * Convert this element to a query element. + * + * @return mixed The element as query. + */ + public function convert(Horde_Kolab_Server_Query $writer) + { + return $writer->convertBegins($this); + } +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Contains.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Contains.php new file mode 100644 index 000000000..224d187f6 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Contains.php @@ -0,0 +1,40 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * An element expressing an 'contains' match. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Query_Element_Contains +extends Horde_Kolab_Server_Query_Element_Single +{ + /** + * Convert this element to a query element. + * + * @return mixed The element as query. + */ + public function convert(Horde_Kolab_Server_Query $writer) + { + return $writer->convertContains($this); + } +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Ends.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Ends.php new file mode 100644 index 000000000..742f9ba68 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Ends.php @@ -0,0 +1,40 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * An element expressing an 'ends' match. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Query_Element_Ends +extends Horde_Kolab_Server_Query_Element_Single +{ + /** + * Convert this element to a query element. + * + * @return mixed The element as query. + */ + public function convert(Horde_Kolab_Server_Query $writer) + { + return $writer->convertEnds($this); + } +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Equals.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Equals.php new file mode 100644 index 000000000..c8164ae67 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Equals.php @@ -0,0 +1,40 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * An element expressing an 'equals' match. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Query_Element_Equals +extends Horde_Kolab_Server_Query_Element_Single +{ + /** + * Convert this element to a query element. + * + * @return mixed The element as query. + */ + public function convert(Horde_Kolab_Server_Query $writer) + { + return $writer->convertEquals($this); + } +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Greater.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Greater.php new file mode 100644 index 000000000..a7f843cbd --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Greater.php @@ -0,0 +1,40 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * An element expressing an 'greater' match. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Query_Element_Greater +extends Horde_Kolab_Server_Query_Element_Single +{ + /** + * Convert this element to a query element. + * + * @return mixed The element as query. + */ + public function convert(Horde_Kolab_Server_Query $writer) + { + return $writer->convertGreater($this); + } +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Group.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Group.php new file mode 100644 index 000000000..d861d1a61 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Group.php @@ -0,0 +1,81 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * A grouped query element. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +abstract class Horde_Kolab_Server_Query_Element_Group +implements Horde_Kolab_Server_Query_Element +{ + /** + * The group elements. + * + * @var array + */ + protected $_elements; + + /** + * Constructor. + * + * @param array $elements The group elements. + */ + public function __construct(array $elements) + { + $this->_elements = $elements; + } + + /** + * Return the query element name. + * + * This should never be called for group elements. + * + * @return string The name of the query element. + */ + public function getName() + { + throw new Exception('Not supported!'); + } + + /** + * Return the value of this element. + * + * This should never be called for group elements. + * + * @return mixed The query value. + */ + public function getValue() + { + throw new Exception('Not supported!'); + } + + /** + * Return the elements of this group. + * + * @return mixed The group elements. + */ + public function getElements() + { + return $this->_elements; + } +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Less.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Less.php new file mode 100644 index 000000000..00df41fb2 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Less.php @@ -0,0 +1,40 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * An element expressing an 'less' match. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Query_Element_Less +extends Horde_Kolab_Server_Query_Element_Single +{ + /** + * Convert this element to a query element. + * + * @return mixed The element as query. + */ + public function convert(Horde_Kolab_Server_Query $writer) + { + return $writer->convertLess($this); + } +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Mapped.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Mapped.php new file mode 100644 index 000000000..2cd6123f8 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Mapped.php @@ -0,0 +1,104 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * A mapped query element. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Query_Element_Mapped +implements Horde_Kolab_Server_Query_Element +{ + /** + * Delegated element. + * + * @var Horde_Kolab_Server_Query_Element + */ + private $_element; + + /** + * Name mapper. + * + * @var Horde_Kolab_Server_Mapped + */ + private $_mapper; + + /** + * Constructor. + * + * @param Horde_Kolab_Server_Query_Element $element The mapped element. + * @param Horde_Kolab_Server_Mapped $mapper The mapping handler. + */ + public function __construct( + Horde_Kolab_Server_Query_Element $element, + Horde_Kolab_Server_Mapped $mapper + ) { + $this->_element = $element; + $this->_mapper = $mapper; + } + + /** + * Return the query element name. + * + * @return string The name of the query element. + */ + public function getName() + { + return $this->_mapper->mapField($this->_element->getName()); + } + + /** + * Return the value of this element. + * + * @return mixed The query value. + */ + public function getValue() + { + return $this->_element->getValue(); + } + + /** + * Return the elements of this group. + * + * @return mixed The group elements. + */ + public function getElements() + { + $elements = array(); + foreach ($this->_element->getElements() as $element) { + $elements[] = new Horde_Kolab_Server_Query_Element_Mapped( + $element, $this->_mapper + ); + } + return $elements; + } + + /** + * Convert this element to a string. + * + * @return string The query string of the element. + */ + public function convert(Horde_Kolab_Server_Query $writer) + { + return $this->_element->convert($writer); + } +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Not.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Not.php new file mode 100644 index 000000000..2f7340de5 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Not.php @@ -0,0 +1,49 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * A negating element. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Query_Element_Not +extends Horde_Kolab_Server_Query_Element_Group +{ + /** + * Constructor. + * + * @param array $elements The group elements. + */ + public function __construct(Horde_Kolab_Server_Query_Element $element) { + parent::__construct(array($element)); + } + + /** + * Convert this element to a query element. + * + * @return mixed The element as query. + */ + public function convert(Horde_Kolab_Server_Query $writer) + { + return $writer->convertNot($this); + } +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Or.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Or.php new file mode 100644 index 000000000..6e89b2892 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Or.php @@ -0,0 +1,40 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * An element grouping by or. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Query_Element_Or +extends Horde_Kolab_Server_Query_Element_Group +{ + /** + * Convert this element to a query element. + * + * @return mixed The element as query. + */ + public function convert(Horde_Kolab_Server_Query $writer) + { + return $writer->convertOr($this); + } +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Single.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Single.php new file mode 100644 index 000000000..59b6cc576 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Element/Single.php @@ -0,0 +1,88 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * A single query element. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +abstract class Horde_Kolab_Server_Query_Element_Single +implements Horde_Kolab_Server_Query_Element +{ + /** + * The element name. + * + * @var string + */ + protected $_name; + + /** + * The comparison value. + * + * @var mixed + */ + protected $_value; + + /** + * Constructor. + * + * @param string $name The element name. + * @param mixed $value The comparison value. + */ + public function __construct($name, $value) + { + $this->_name = $name; + $this->_value = $value; + } + + /** + * Return the query element name. + * + * @return string The name of the query element. + */ + public function getName() + { + return $this->_name; + } + + /** + * Return the value of this element. + * + * @return mixed The query value. + */ + public function getValue() + { + return $this->_value; + } + + /** + * Return the elements of this group. + * + * This should never be called for single elements. + * + * @return mixed The group elements. + */ + public function getElements() + { + throw new Exception('Not supported!'); + } +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Ldap.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Ldap.php new file mode 100644 index 000000000..e90f995ec --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Query/Ldap.php @@ -0,0 +1,268 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Handler for LDAP server queries. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Query_Ldap implements Horde_Kolab_Server_Query +{ + /** + * The query criteria. + * + * @var Horde_Kolab_Server_Query_Element + */ + private $_criteria; + + /** + * Constructor. + * + * @param array $criteria The query criteria. + */ + public function __construct(Horde_Kolab_Server_Query_Element $criteria) + { + $this->_criteria = $criteria; + } + + /** + * Return the query as a string. + * + * @return string The query in string format. + * + * @throws Horde_Kolab_Server_Exception If the query is malformed. + */ + public function __toString() + { + $filter = $this->_criteria->convert($this); + return $filter->asString(); + } + + /** + * Convert the equals element to query format. + * + * @param Horde_Kolab_Server_Query_Element_Equals $equals The element to convert. + * + * @return mixed The query element in query format. + * + * @throws Horde_Kolab_Server_Exception If the query is malformed. + */ + public function convertEquals(Horde_Kolab_Server_Query_Element_Equals $equals) + { + return $this->_convertSingle($equals, 'equals'); + } + + /** + * Convert the begins element to query format. + * + * @param Horde_Kolab_Server_Query_Element_Begins $begins The element to convert. + * + * @return mixed The query element in query format. + * + * @throws Horde_Kolab_Server_Exception If the query is malformed. + */ + public function convertBegins(Horde_Kolab_Server_Query_Element_Begins $begins) + { + return $this->_convertSingle($begins, 'begins'); + } + + /** + * Convert the ends element to query format. + * + * @param Horde_Kolab_Server_Query_Element_Ends $ends The element to convert. + * + * @return mixed The query element in query format. + * + * @throws Horde_Kolab_Server_Exception If the query is malformed. + */ + public function convertEnds(Horde_Kolab_Server_Query_Element_Ends $ends) + { + return $this->_convertSingle($ends, 'ends'); + } + + /** + * Convert the contains element to query format. + * + * @param Horde_Kolab_Server_Query_Element_Contains $contains The element to convert. + * + * @return mixed The query element in query format. + * + * @throws Horde_Kolab_Server_Exception If the query is malformed. + */ + public function convertContains(Horde_Kolab_Server_Query_Element_Contains $contains) + { + return $this->_convertSingle($contains, 'contains'); + } + + /** + * Convert the less element to query format. + * + * @param Horde_Kolab_Server_Query_Element_Less $less The element to convert. + * + * @return mixed The query element in query format. + * + * @throws Horde_Kolab_Server_Exception If the query is malformed. + */ + public function convertLess(Horde_Kolab_Server_Query_Element_Less $less) + { + return $this->_convertSingle($less, 'less'); + } + + /** + * Convert the greater element to query format. + * + * @param Horde_Kolab_Server_Query_Element_Grater $grater The element to convert. + * + * @return mixed The query element in query format. + * + * @throws Horde_Kolab_Server_Exception If the query is malformed. + */ + public function convertGreater(Horde_Kolab_Server_Query_Element_Greater $greater) + { + return $this->_convertSingle($greater, 'greater'); + } + + /** + * Convert the approx element to query format. + * + * @param Horde_Kolab_Server_Query_Element_Approx $approx The element to convert. + * + * @return mixed The query element in query format. + * + * @throws Horde_Kolab_Server_Exception If the query is malformed. + */ + public function convertApprox(Horde_Kolab_Server_Query_Element_Approx $approx) + { + return $this->_convertSingle($approx, 'approx'); + } + + /** + * Convert the single element to query format. + * + * @param Horde_Kolab_Server_Query_Element_Single $single The element to convert. + * @param string $operator The element operation. + * + * @return mixed The query element in query format. + * + * @throws Horde_Kolab_Server_Exception If the query is malformed. + */ + private function _convertSingle( + Horde_Kolab_Server_Query_Element_Single $single, + $operator + ) { + $result = Net_LDAP2_Filter::create( + $single->getName(), $operator, $single->getValue() + ); + $this->_handleError($result); + return $result; + } + + /** + * Convert the not element to query format. + * + * @param Horde_Kolab_Server_Query_Element_Group $group The element to convert. + * + * @return mixed The query element in query format. + * + * @throws Horde_Kolab_Server_Exception If the query is malformed. + */ + public function convertNot(Horde_Kolab_Server_Query_Element_Not $not) + { + $elements = $not->getElements(); + $result = Net_LDAP2_Filter::combine('!', $elements[0]->convert($this)); + $this->_handleError($result); + return $result; + } + + /** + * Convert the and element to query format. + * + * @param Horde_Kolab_Server_Query_Element_Group $group The element to convert. + * + * @return mixed The query element in query format. + * + * @throws Horde_Kolab_Server_Exception If the query is malformed. + */ + public function convertAnd(Horde_Kolab_Server_Query_Element_And $and) + { + return $this->_convertGroup($and, '&'); + } + + /** + * Convert the or element to query format. + * + * @param Horde_Kolab_Server_Query_Element_Group $group The element to convert. + * + * @return mixed The query element in query format. + * + * @throws Horde_Kolab_Server_Exception If the query is malformed. + */ + public function convertOr(Horde_Kolab_Server_Query_Element_Group $or) + { + return $this->_convertGroup($or, '|'); + } + + /** + * Convert the group element to query format. + * + * @param Horde_Kolab_Server_Query_Element_Group $group The element to convert. + * @param string $operator The element operation. + * + * @return mixed The query element in query format. + * + * @throws Horde_Kolab_Server_Exception If the query is malformed. + */ + public function _convertGroup( + Horde_Kolab_Server_Query_Element_Group $group, + $operator + ) { + $filters = array(); + foreach ($group->getElements() as $element) { + $filters[] = $element->convert($this); + } + $result = Net_LDAP2_Filter::combine($operator, $filters); + $this->_handleError($result); + return $result; + } + + /** + * Check for a PEAR Error and convert it to an exception if necessary. + * + * @param mixed $result The result to be tested. + * @param code $code The error code to use in case the result is an error. + * + * @return NULL. + * + * @throws Horde_Kolab_Server_Exception If the connection failed. + * + * @throws Horde_Kolab_Server_Exception If the query is malformed. + */ + private function _handleError( + $result, + $code = Horde_Kolab_Server_Exception::INVALID_QUERY + ) { + if (is_a($result, 'PEAR_Error')) { + throw new Horde_Kolab_Server_Exception($result, $code); + } + } + +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Result.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Result.php new file mode 100644 index 000000000..bf365fdce --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Result.php @@ -0,0 +1,50 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Interface for query results. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +interface Horde_Kolab_Server_Result +{ + /** + * The number of result entries. + * + * @return int The number of elements. + */ + public function count(); + + /** + * Test if the last search exceeded the size limit. + * + * @return boolean True if the last search exceeded the size limit. + */ + public function sizeLimitExceeded(); + + /** + * Return the result as an array. + * + * @return array The resulting array. + */ + public function asArray(); +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Result/Ldap.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Result/Ldap.php new file mode 100644 index 000000000..273a0c0ff --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Result/Ldap.php @@ -0,0 +1,76 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Handler for LDAP query results. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Result_Ldap implements Horde_Kolab_Server_Result +{ + /** + * The search result. + * + * @var Net_LDAP2_Search + */ + private $_search; + + /** + * Constructor. + * + * @param Net_LDAP2_Search $search The LDAP search result. + */ + public function __construct(Net_LDAP2_Search $search) + { + $this->_search = $search; + } + + /** + * The number of result entries. + * + * @return int The number of elements. + */ + public function count() + { + return $this->_search->count(); + } + + /** + * Test if the last search exceeded the size limit. + * + * @return boolean True if the last search exceeded the size limit. + */ + public function sizeLimitExceeded() + { + return $this->_search->sizeLimitExceeded(); + } + + /** + * Return the result as an array. + * + * @return array The resulting array. + */ + public function asArray() + { + return $this->_search->as_struct(); + } +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Schema.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Schema.php new file mode 100644 index 000000000..07792a217 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Schema.php @@ -0,0 +1,62 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Interface for the structural handler of a Kolab database. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +interface Horde_Kolab_Server_Schema +{ + /** + * Return the schema for the given objectClass. + * + * @param string $objectclass Fetch the schema for this objectClass. + * + * @return array The schema for the given objectClass. + * + * @throws Horde_Kolab_Server_Exception If retrieval of the schema failed. + */ + public function getObjectclassSchema($objectclass); + + /** + * Return the schema for the given attribute. + * + * @param string $attribute Fetch the schema for this attribute. + * + * @return array The schema for the given attribute. + * + * @throws Horde_Kolab_Server_Exception If retrieval of the schema failed. + */ + public function getAttributeSchema($attribute); + + /** + * Return the attributes supported by the given object class. + * + * @param string $class Determine the attributes for this class. + * + * @return array The supported attributes. + * + * @throws Horde_Kolab_Server_Exception If the schema analysis fails. + */ + public function &getAttributes($class); +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Schema/Base.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Schema/Base.php new file mode 100644 index 000000000..9ed27a7f4 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Schema/Base.php @@ -0,0 +1,273 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * This class provides methods to deal with Kolab objects stored in + * the Kolab object db. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Schema_Base implements Horde_Kolab_Server_Schema +{ + /** Maximum accepted level for the object class hierarchy */ + const MAX_HIERARCHY = 100; + + /** + * A cache for object attribute definitions. + * + * @var array + */ + protected $attributes; + + /** + * A link to the server handler. + * + * @var Horde_Kolab_Server + */ + protected $server; + + /** + * Set the server reference for this object. + * + * @param Horde_Kolab_Server &$server A link to the server handler. + */ + public function setServer($server) + { + $this->server = $server; + } + + /** + * Return the schema for the given objectClass. + * + * @param string $objectclass Fetch the schema for this objectClass. + * + * @return array The schema for the given objectClass. + * + * @throws Horde_Kolab_Server_Exception If retrieval of the schema failed. + */ + public function getObjectclassSchema($objectclass) + { + if (!empty($this->_config['schema_support'])) { + $schema = $this->_getSchema(); + $info = $schema->get('objectclass', $objectclass); + $this->_handleError($info, Horde_Kolab_Server_Exception::SYSTEM); + return $info; + } + return parent::getObjectclassSchema($objectclass); + } + + /** + * Return the schema for the given attribute. + * + * @param string $attribute Fetch the schema for this attribute. + * + * @return array The schema for the given attribute. + * + * @throws Horde_Kolab_Server_Exception If retrieval of the schema failed. + */ + public function getAttributeSchema($attribute) + { + if (!empty($this->_config['schema_support'])) { + $schema = $this->_getSchema(); + $info = $schema->get('attribute', $attribute); + $this->_handleError($info, Horde_Kolab_Server_Exception::SYSTEM); + return $info; + } + return parent::getAttributeSchema($attribute); + } + + /** + * Return the attributes supported by the given object class. + * + * @param string $class Determine the attributes for this class. + * + * @return array The supported attributes. + * + * @throws Horde_Kolab_Server_Exception If the schema analysis fails. + */ + public function &getAttributes($class) + { + if (!isset($this->attributes)) { + if (isset($this->cache)) { + register_shutdown_function(array($this, 'shutdown')); + } + } + if (empty($this->attributes[$class])) { + + if (isset($this->cache)) { + $this->attributes[$class] = @unserialize($cache->get('attributes_' . $class, + $this->params['cache_lifetime'])); + } + + if (empty($this->attributes[$class])) { + + $childclass = $class; + $classes = array(); + $level = 0; + while ($childclass != 'Horde_Kolab_Server_Object' + && $level < self::MAX_HIERARCHY) { + $classes[] = $childclass; + $childclass = get_parent_class($childclass); + $level++; + } + + /** Finally add the basic object class */ + $classes[] = $childclass; + + if ($level == self::MAX_HIERARCHY) { + if (isset($this->logger)) { + $logger->err(sprintf('The maximal level of the object hierarchy has been exceeded for class \"%s\"!', + $class)); + } + } + + /** + * Collect attributes from bottom to top. + */ + $classes = array_reverse($classes); + + $types = array('defined', 'required', 'derived', 'collapsed', + 'defaults', 'locked', 'object_classes'); + foreach ($types as $type) { + $$type = array(); + } + + foreach ($classes as $childclass) { + $vars = get_class_vars($childclass); + if (isset($vars['init_attributes'])) { + foreach ($types as $type) { + /** + * If the user wishes to adhere to the schema + * information from the server we will skip the + * attributes defined within the object class here. + */ + if (!empty($this->params['schema_override']) + && in_array($type, 'defined', 'required')) { + continue; + } + if (isset($vars['init_attributes'][$type])) { + $$type = array_merge($$type, + $vars['init_attributes'][$type]); + } + } + } + } + + $attrs = array(); + + foreach ($object_classes as $object_class) { + $info = $this->getObjectclassSchema($object_class); + if (isset($info['may'])) { + $defined = array_merge($defined, $info['may']); + } + if (isset($info['must'])) { + $defined = array_merge($defined, $info['must']); + $required = array_merge($required, $info['must']); + } + foreach ($defined as $attribute) { + try { + $attrs[$attribute] = $this->getAttributeSchema($attribute); + } catch (Horde_Kolab_Server_Exception $e) { + /** + * If the server considers the attribute to be + * invalid we mark it. + */ + $attrs[$attribute] = array('invalid' => true); + } + } + foreach ($required as $attribute) { + $attrs[$attribute]['required'] = true; + } + foreach ($locked as $attribute) { + $attrs[$attribute]['locked'] = true; + } + foreach ($defaults as $attribute => $default) { + $attrs[$attribute]['default'] = $default; + } + $attrs[Horde_Kolab_Server_Object::ATTRIBUTE_OC]['default'] = $object_classes; + } + foreach ($derived as $key => $attributes) { + $supported = true; + if (isset($attributes['base'])) { + foreach ($attributes['base'] as $attribute) { + /** + * Usually derived attribute are determined on basis + * of one or more attributes. If any of these is not + * supported the derived attribute should not be + * included into the set of supported attributes. + */ + if (!isset($attrs[$attribute])) { + unset($derived[$attribute]); + $supported = false; + break; + } + } + } + if ($supported) { + $attrs[$key] = $attributes; + } + } + $check_collapsed = $collapsed; + foreach ($check_collapsed as $key => $attributes) { + if (isset($attributes['base'])) { + foreach ($attributes['base'] as $attribute) { + /** + * Usually collapsed attribute are determined on basis + * of one or more attributes. If any of these is not + * supported the collapsed attribute should not be + * included into the set of supported attributes. + */ + if (!isset($attrs[$attribute])) { + unset($collapsed[$attribute]); + } + } + } + } + $this->attributes[$class] = array($attrs, + array( + 'derived' => array_keys($derived), + 'collapsed' => $collapsed, + 'locked' => $locked, + 'required' => $required)); + } + } + return $this->attributes[$class]; + } + + /** + * Stores the attribute definitions in the cache. + * + * @return Horde_Kolab_Server The concrete Horde_Kolab_Server reference. + */ + public function shutdown() + { + if (isset($this->attributes)) { + if (isset($this->cache)) { + foreach ($this->attributes as $key => $value) { + $this->cache->set('attributes_' . $key, @serialize($value)); + } + } + } + } + + +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Search.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Search.php new file mode 100644 index 000000000..6f72f7bf0 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Search.php @@ -0,0 +1,48 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Defines the interface of the search handler for a Kolab Server. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +interface Horde_Kolab_Server_Search +{ + /** + * Returns the set of search operations supported by this server type. + * + * @return array An array of supported search operations. + */ + public function getSearchOperations(); + + /** + * Capture undefined calls. + * + * @param string $method The name of the called method. + * @param array $args Arguments of the call. + * + * @return NULL. + * + * @throws Horde_Kolab_Server_Exception + */ + public function __call($method, $args); +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Search/Base.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Search/Base.php new file mode 100644 index 000000000..caf111f67 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Search/Base.php @@ -0,0 +1,103 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * This class provides methods to deal with Kolab objects stored in + * the Kolab object db. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Search_Base implements Horde_Kolab_Server_Search +{ + /** + * A link to the server handler. + * + * @var Horde_Kolab_Server + */ + protected $server; + + /** + * Set the server reference for this object. + * + * @param Horde_Kolab_Server &$server A link to the server handler. + */ + public function setServer($server) + { + $this->server = $server; + } + + /** + * The search methods offered by the object defined for this server. + * + * @var array + */ + protected $searches; + + /*__construct + /** Initialize the search operations supported by this server. * + $this->searches = $this->getSearchOperations(); + */ + + /** + * Returns the set of search operations supported by this server type. + * + * @return array An array of supported search operations. + */ + public function getSearchOperations() + { + $server_searches = array(); + foreach ($this->getSupportedObjects() as $sobj) { + if (in_array('getSearchOperations', get_class_methods($sobj))) { + $searches = call_user_func(array($sobj, 'getSearchOperations')); + foreach ($searches as $search) { + $server_searches[$search] = array('class' => $sobj); + } + } + } + return $server_searches; + } + + /** + * Capture undefined calls and assume they refer to a search operation. + * + * @param string $method The name of the called method. + * @param array $args Arguments of the call. + * + * @return NULL. + * + * @throws Horde_Kolab_Server_Exception + */ + public function __call($method, $args) + { + if (in_array($method, array_keys($this->searches))) { + array_unshift($args, $this); + if (isset($this->searches[$method])) { + return call_user_func_array(array($this->searches[$method]['class'], + $method), $args); + } + } + throw new Horde_Kolab_Server_Exception( + sprintf("The server type \"%s\" does not support method \"%s\"!", + get_class($this), $method)); + } + +} \ No newline at end of file diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Standard.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Standard.php new file mode 100644 index 000000000..d4e94370e --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Standard.php @@ -0,0 +1,47 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * This class provides methods to deal with objects stored in + * a standard LDAP db. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Standard extends Horde_Kolab_Server_Ldap +{ + /** + * Finds all object data below a parent matching a given set of criteria. + * + * @param array $criteria The criteria for the search. + * @param string $parent The parent to search below. + * @param array $params Additional search parameters. + * + * @return Horde_Kolab_Server_Result The result object. + * + * @throws Horde_Kolab_Server_Exception + */ + public function findBelow(array $criteria, $parent, array $params = array()) + { + $query = new Horde_Kolab_Server_Query_Ldap($criteria); + return $this->_search((string) $query, $params, $parent); + } +} diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Structure.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Structure.php index 17c6fb917..68f854046 100644 --- a/framework/Kolab_Server/lib/Horde/Kolab/Server/Structure.php +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Structure.php @@ -12,7 +12,8 @@ */ /** - * An abstract class definiing methods to deal with an object tree structure. + * The interface definition for the handlers dealing with the Kolab Server + * object tree structure. * * Copyright 2009 The Horde Project (http://www.horde.org/) * @@ -25,48 +26,14 @@ * @license http://www.fsf.org/copyleft/lgpl.html LGPL * @link http://pear.horde.org/index.php?package=Kolab_Server */ -abstract class Horde_Kolab_Server_Structure +interface Horde_Kolab_Server_Structure { /** - * A link to the server handler. - * - * @var Horde_Kolab_Server - */ - protected $server; - - /** - * Structure parameters. - * - * @var array - */ - protected $params = array(); - - /** - * Construct a new Horde_Kolab_Server_Structure object. - * - * @param array $params Parameter array. - */ - public function __construct($params = array()) - { - $this->params = $params; - } - - /** - * Set the server reference for this object. - * - * @param Horde_Kolab_Server &$server A link to the server handler. - */ - public function setServer($server) - { - $this->server = $server; - } - - /** * Returns the set of objects supported by this structure. * * @return array An array of supported objects. */ - abstract public function getSupportedObjects(); + public function getSupportedObjects(); /** * Determine the type of an object by its tree position and other @@ -78,7 +45,7 @@ abstract class Horde_Kolab_Server_Structure * * @throws Horde_Kolab_Server_Exception If the object type is unknown. */ - abstract public function determineType($uid); + public function determineType($uid); /** * Generates a UID for the given information. @@ -91,23 +58,5 @@ abstract class Horde_Kolab_Server_Structure * * @throws Horde_Kolab_Server_Exception If the given type is unknown. */ - abstract public function generateServerUid($type, $id, $info); - - /** - * Quote an UID part. - * - * @param string $id The UID part. - * - * @return string The quoted part. - */ - abstract public function quoteForUid($id); - - /** - * Quote an filter part. - * - * @param string $part The filter part. - * - * @return string The quoted part. - */ - abstract public function quoteForFilter($part); + public function generateServerUid($type, $id, $info); } diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Structure/Base.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Structure/Base.php new file mode 100644 index 000000000..bf58f7406 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Structure/Base.php @@ -0,0 +1,139 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * An abstract class definiing methods to deal with an object tree structure. + * + * Copyright 2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +abstract class Horde_Kolab_Server_Structure_Base implements Horde_Kolab_Server_Structure +{ + /** + * A link to the server handler. + * + * @var Horde_Kolab_Server + */ + protected $server; + + /** + * Set the server reference for this object. + * + * @param Horde_Kolab_Server &$server A link to the server handler. + */ + public function setServer($server) + { + $this->server = $server; + } + + /** + * Returns the set of objects supported by this structure. + * + * @return array An array of supported objects. + */ + public function getSupportedObjects() + { + } + + /** + * Determine the type of an object by its tree position and other + * parameters. + * + * @param string $uid The UID of the object to examine. + * + * @return string The class name of the corresponding object type. + * + * @throws Horde_Kolab_Server_Exception If the object type is unknown. + */ + public function determineType($uid) + { + } + + /** + * Generates a UID for the given information. + * + * @param string $type The class name of the object to create. + * @param string $id The id of the object. + * @param array $info Any additional information about the object to create. + * + * @return string The UID. + * + * @throws Horde_Kolab_Server_Exception If the given type is unknown. + */ + public function generateServerUid($type, $id, $info) + { + } + + /** + * Get the LDAP object classes for the given DN. + * + * This is meant to be a shortcut for the structure handler. It should be + * used when determining the object type. + * + * @param string $uid DN of the object. + * + * @return array An array of object classes. + * + * @throws Horde_Kolab_Server_Exception If the object has no + * object classes. + */ + public function getObjectClasses($uid) + { + $object = $this->read($uid, array(Horde_Kolab_Server_Object::ATTRIBUTE_OC)); + if (!isset($object[Horde_Kolab_Server_Object::ATTRIBUTE_OC])) { + throw new Horde_Kolab_Server_Exception( + sprintf( + "The object %s has no %s attribute!", + $uid, Horde_Kolab_Server_Object::ATTRIBUTE_OC + ), + Horde_Kolab_Server_Exception::SYSTEM + ); + } + $result = array_map( + 'strtolower', + $object[Horde_Kolab_Server_Object::ATTRIBUTE_OC] + ); + return $result; + } + + /** + * Connect to the server. Use this method if the user name you can provide + * does not match a DN. In this case it will be required to map this user + * name first. + * + * @param string $user The user name. + * @param string $pass The password. + * + * @return NULL. + * + * @throws Horde_Kolab_Server_Exception If the connection failed. + */ + protected function _connect($user = null, $pass = null) + { + /** Bind anonymously first. */ + $this->connectUid(); + $guid = $this->structure->getGuidForUser($user); + $this->connectUid($guid, $pass); + return $this->structure->getUserForUser($user); + } + + +} diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Structure/Ldap.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Structure/Ldap.php index 7c0d6c366..382815ffc 100644 --- a/framework/Kolab_Server/lib/Horde/Kolab/Server/Structure/Ldap.php +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Structure/Ldap.php @@ -25,7 +25,7 @@ * @license http://www.fsf.org/copyleft/lgpl.html LGPL * @link http://pear.horde.org/index.php?package=Kolab_Server */ -class Horde_Kolab_Server_Structure_Ldap extends Horde_Kolab_Server_Structure +class Horde_Kolab_Server_Structure_Ldap extends Horde_Kolab_Server_Structure_Base { /** * Returns the set of objects supported by this structure. @@ -90,29 +90,4 @@ class Horde_Kolab_Server_Structure_Ldap extends Horde_Kolab_Server_Structure return sprintf('%s,%s', $id, $this->server->getBaseUid()); } - /** - * Quote an UID part. - * - * @param string $id The UID part. - * - * @return string The UID part. - */ - public function quoteForUid($id) - { - $id = Net_LDAP2_Util::escape_dn_value($id); - return $id[0]; - } - - /** - * Quote an filter part. - * - * @param string $part The filter part. - * - * @return string The quoted part. - */ - public function quoteForFilter($part) - { - $part = Net_LDAP2_Util::escape_filter_value($part); - return $part[0]; - } } diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Test.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Test.php index c04e43722..461ccc17f 100644 --- a/framework/Kolab_Server/lib/Horde/Kolab/Server/Test.php +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Test.php @@ -85,14 +85,17 @@ class Horde_Kolab_Server_Test extends Horde_Kolab_Server_Ldap private $_current_index; /** - * Construct a new Horde_Kolab_Server object. + * Set configuration parameters. * - * @param array $params Parameter array. + * @param array $params The parameters. + * + * @return NULL */ - public function __construct(Horde_Kolab_Server_Structure $structure, - $params = array()) + public function setParams(array $params) { - $this->load(); + //@todo Load when connecting + //$this->load(); + if (isset($params['data'])) { $this->data = $params['data']; } else { @@ -101,8 +104,6 @@ class Horde_Kolab_Server_Test extends Horde_Kolab_Server_Ldap } } - parent::__construct($structure, $params); - if (isset($this->params['admin']) && isset($this->params['admin']['type'])) { $type = $this->params['admin']['type']; @@ -114,18 +115,25 @@ class Horde_Kolab_Server_Test extends Horde_Kolab_Server_Ldap } } - $this->store(); + //@todo Load when connecting + //$this->store(); + + parent::setParams($params); } /** - * Connect to the server. + * Connect to the LDAP server. + * + * @param string $uid The unique id of the user. + * @param string $pass The password. * * @return NULL. * * @throws Horde_Kolab_Server_Exception If the connection failed. */ - protected function connect() + protected function _connectUid($uid = null, $pass = null) { + //@todo } /** @@ -135,6 +143,7 @@ class Horde_Kolab_Server_Test extends Horde_Kolab_Server_Ldap */ protected function load() { + //@todo: remove the global if (isset($GLOBALS['KOLAB_SERVER_TEST_DATA'])) { $this->data = $GLOBALS['KOLAB_SERVER_TEST_DATA']; } else { @@ -483,7 +492,7 @@ class Horde_Kolab_Server_Test extends Horde_Kolab_Server_Ldap * * @throws Horde_Kolab_Server_Exception If the object does not exist. */ - public function read($dn, $attrs = null) + public function read($uid, array $attrs = array()) { if (!$this->bound) { $result = $this->bind(); @@ -522,9 +531,9 @@ class Horde_Kolab_Server_Test extends Horde_Kolab_Server_Ldap * @param array $data The attributes of the object to be added/replaced. * @param boolean $exists Does the object already exist on the server? * - * @return boolean True if saving succeeded. + * @return NULL */ - public function save($uid, $data, $exists = false) + public function save($uid, array $data, $exists = false) { if (!$this->bound) { $result = $this->bind(); @@ -597,8 +606,8 @@ class Horde_Kolab_Server_Test extends Horde_Kolab_Server_Ldap $this->store(); if (isset($this->logger)) { - $logger->debug(sprintf('The object \"%s\" has been successfully saved!', - $uid)); + $this->logger->debug(sprintf('The object \"%s\" has been successfully saved!', + $uid)); } } @@ -628,7 +637,7 @@ class Horde_Kolab_Server_Test extends Horde_Kolab_Server_Ldap * * @param string $uid The UID of the object to be deleted. * - * @return boolean True if saving succeeded. + * @return NULL * * @throws Horde_Kolab_Server_Exception */ @@ -642,10 +651,9 @@ class Horde_Kolab_Server_Test extends Horde_Kolab_Server_Ldap } $this->store(); if (isset($this->logger)) { - $logger->debug(sprintf('The object \"%s\" has been successfully deleted!', - $uid)); + $this->logger->debug(sprintf('The object \"%s\" has been successfully deleted!', + $uid)); } - return true; } /** @@ -654,7 +662,7 @@ class Horde_Kolab_Server_Test extends Horde_Kolab_Server_Ldap * @param string $uid The UID of the object to be renamed. * @param string $new The new UID of the object. * - * @return boolean True if renaming succeeded. + * @return NULL * * @throws Horde_Kolab_Server_Exception */ @@ -666,10 +674,9 @@ class Horde_Kolab_Server_Test extends Horde_Kolab_Server_Ldap } $this->store(); if (isset($this->logger)) { - $logger->debug(sprintf('The object \"%s\" has been successfully renamed to \"%s\"!', - $uid, $new)); + $this->logger->debug(sprintf('The object \"%s\" has been successfully renamed to \"%s\"!', + $uid, $new)); } - return true; } /** diff --git a/framework/Kolab_Server/package.xml b/framework/Kolab_Server/package.xml index 848b24d61..7f25d3b8c 100644 --- a/framework/Kolab_Server/package.xml +++ b/framework/Kolab_Server/package.xml @@ -61,11 +61,17 @@ http://pear.php.net/dtd/package-2.0.xsd"> + + + + + + - + @@ -88,8 +94,45 @@ http://pear.php.net/dtd/package-2.0.xsd"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -104,7 +147,13 @@ http://pear.php.net/dtd/package-2.0.xsd"> - + + + + + + + @@ -118,6 +167,9 @@ http://pear.php.net/dtd/package-2.0.xsd"> + + + @@ -136,34 +188,18 @@ http://pear.php.net/dtd/package-2.0.xsd"> 1.4.0b1 - Net_LDAP2 - pear.php.net - - - Autoloader - pear.horde.org - - - Horde_Framework + Exception pear.horde.org - Horde_LDAP - pear.horde.org - - - Horde_Cache - pear.horde.org - - Date pear.horde.org - PHPUnit - pear.phpunit.de + Net_LDAP2 + pear.php.net ldap @@ -173,11 +209,15 @@ http://pear.php.net/dtd/package-2.0.xsd"> + + + + - + @@ -196,7 +236,32 @@ http://pear.php.net/dtd/package-2.0.xsd"> + + + + + + + + + + + + + + + + + + + + + + + + + @@ -204,6 +269,8 @@ http://pear.php.net/dtd/package-2.0.xsd"> + + @@ -217,6 +284,7 @@ http://pear.php.net/dtd/package-2.0.xsd"> + diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/AdminTest.php b/framework/Kolab_Server/test/Horde/Kolab/Server/AdminTest.php index c22c42003..e77ef4e00 100644 --- a/framework/Kolab_Server/test/Horde/Kolab/Server/AdminTest.php +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/AdminTest.php @@ -40,6 +40,8 @@ class Horde_Kolab_Server_AdminTest extends Horde_Kolab_Server_Scenario */ protected function setUp() { + parent::setUp(); + $this->server = $this->getKolabMockServer(); } diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/Autoload.php b/framework/Kolab_Server/test/Horde/Kolab/Server/Autoload.php index 3b29921aa..edb1ce807 100644 --- a/framework/Kolab_Server/test/Horde/Kolab/Server/Autoload.php +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/Autoload.php @@ -11,23 +11,24 @@ * @link http://pear.horde.org/index.php?package=Kolab_Server */ -if (!defined('HORE_KOLAB_SERVER_TESTS')) { - /** - * The Autoloader allows us to omit "require/include" statements. - */ - require_once 'Horde/Autoloader.php'; +/** + * The Autoloader allows us to omit "require/include" statements. + */ +require_once 'Horde/Autoloader.php'; + +if (!defined('HORDE_KOLAB_SERVER_TESTS')) { $test_dir = '@test_dir@/Kolab_Server'; - if (substr($test_dir, 0, 1) == '@') { + if (strpos($test_dir, '@test_dir') === 0) { /** * Assume we are working in development mode and this package resides in * 'framework'. */ - define('HORE_KOLAB_SERVER_TESTS', dirname(__FILE__) . '/../../..'); + define('HORDE_KOLAB_SERVER_TESTS', dirname(__FILE__) . '/../../..'); } else { - define('HORE_KOLAB_SERVER_TESTS', $test_dir); + define('HORDE_KOLAB_SERVER_TESTS', $test_dir); } - Horde_Autoloader::addClassPath(HORE_KOLAB_SERVER_TESTS); + Horde_Autoloader::addClassPath(HORDE_KOLAB_SERVER_TESTS); } \ No newline at end of file diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/Connection/SimpleldapTest.php b/framework/Kolab_Server/test/Horde/Kolab/Server/Connection/SimpleldapTest.php new file mode 100644 index 000000000..cff61dc29 --- /dev/null +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/Connection/SimpleldapTest.php @@ -0,0 +1,72 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Prepare the test setup. + */ +require_once dirname(__FILE__) . '/../Autoload.php'; + +/** + * Test the handler for a simple LDAP setup without read-only slaves. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Connection_SimpleldapTest extends PHPUnit_Framework_TestCase +{ + public function setUp() + { + if (!extension_loaded('ldap') && !@dl('ldap.' . PHP_SHLIB_SUFFIX)) { + $this->markTestSuiteSkipped('Ldap extension is missing!'); + }; + + if (!class_exists('Net_LDAP2')) { + $this->markTestSuiteSkipped('PEAR package Net_LDAP2 is not installed!'); + } + } + + public function testMethodConstructHasParameterNetldap2Connection() + { + $ldap = $this->getMock('Net_LDAP2'); + $conn = new Horde_Kolab_Server_Connection_Simpleldap($ldap); + } + + public function testMethodConstructHasPostconditionThatTheGivenServerWasStored() + { + $ldap = $this->getMock('Net_LDAP2'); + $conn = new Horde_Kolab_Server_Connection_Simpleldap($ldap); + $this->assertSame($ldap, $conn->getRead()); + } + + public function testMethodGetreadHasResultNetldap2TheHandledConnection() + { + $ldap = $this->getMock('Net_LDAP2'); + $conn = new Horde_Kolab_Server_Connection_Simpleldap($ldap); + $this->assertType('Net_LDAP2', $conn->getRead()); + } + + public function testMethodGetwriteHasResultNetldap2TheHandledConnection() + { + $ldap = $this->getMock('Net_LDAP2'); + $conn = new Horde_Kolab_Server_Connection_Simpleldap($ldap); + $this->assertSame($conn->getWrite(), $conn->getRead()); + } +} diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/Connection/SplittedldapTest.php b/framework/Kolab_Server/test/Horde/Kolab/Server/Connection/SplittedldapTest.php new file mode 100644 index 000000000..e5901316f --- /dev/null +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/Connection/SplittedldapTest.php @@ -0,0 +1,78 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Prepare the test setup. + */ +require_once dirname(__FILE__) . '/../Autoload.php'; + +/** + * Test the handler for a LDAP master/slave setup. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Connection_SplittedTest extends PHPUnit_Framework_TestCase +{ + public function setUp() + { + if (!extension_loaded('ldap') && !@dl('ldap.' . PHP_SHLIB_SUFFIX)) { + $this->markTestSuiteSkipped('Ldap extension is missing!'); + }; + + if (!class_exists('Net_LDAP2')) { + $this->markTestSuiteSkipped('PEAR package Net_LDAP2 is not installed!'); + } + } + + public function testMethodConstructHasParameterNetldap2ReadConnectionAndParameterNetldap2WriteConnection() + { + $ldap_read = $this->getMock('Net_LDAP2'); + $ldap_write = $this->getMock('Net_LDAP2'); + $conn = new Horde_Kolab_Server_Connection_Splittedldap($ldap_read, $ldap_write); + } + + public function testMethodConstructHasPostconditionThatTheGivenServersWereStored() + { + $ldap_read = $this->getMock('Net_LDAP2'); + $ldap_write = $this->getMock('Net_LDAP2'); + $conn = new Horde_Kolab_Server_Connection_Splittedldap($ldap_read, $ldap_write); + $this->assertSame($ldap_read, $conn->getRead()); + $this->assertSame($ldap_write, $conn->getWrite()); + } + + public function testMethodGetreadHasResultNetldap2TheHandledConnection() + { + $ldap_read = $this->getMock('Net_LDAP2'); + $ldap_write = $this->getMock('Net_LDAP2'); + $conn = new Horde_Kolab_Server_Connection_Splittedldap($ldap_read, $ldap_write); + $this->assertType('Net_LDAP2', $conn->getRead()); + $this->assertType('Net_LDAP2', $conn->getWrite()); + } + + public function testMethodGetwriteHasResultNetldap2TheHandledConnection() + { + $ldap_read = $this->getMock('Net_LDAP2'); + $ldap_write = $this->getMock('Net_LDAP2'); + $conn = new Horde_Kolab_Server_Connection_Splittedldap($ldap_read, $ldap_write); + $this->assertFalse($conn->getWrite() === $conn->getRead()); + } +} diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/GroupTest.php b/framework/Kolab_Server/test/Horde/Kolab/Server/GroupTest.php index c69a8f53d..36af340d0 100644 --- a/framework/Kolab_Server/test/Horde/Kolab/Server/GroupTest.php +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/GroupTest.php @@ -40,6 +40,8 @@ class Horde_Kolab_Server_GroupTest extends Horde_Kolab_Server_Scenario */ protected function setUp() { + parent::setUp(); + $this->ldap = $this->getKolabMockServer(); } @@ -121,8 +123,6 @@ class Horde_Kolab_Server_GroupTest extends Horde_Kolab_Server_Scenario */ public function testListingGroups() { - $this->assertEquals(0, count($GLOBALS['KOLAB_SERVER_TEST_DATA'])); - $result = $this->ldap->search( '(&(!(cn=domains))(objectClass=kolabGroupOfNames))', array(), diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/InetorgpersonTest.php b/framework/Kolab_Server/test/Horde/Kolab/Server/InetorgpersonTest.php index d54367725..7ff3debcd 100644 --- a/framework/Kolab_Server/test/Horde/Kolab/Server/InetorgpersonTest.php +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/InetorgpersonTest.php @@ -68,6 +68,8 @@ class Horde_Kolab_Server_InetorgpersonTest extends Horde_Kolab_Server_Scenario */ protected function setUp() { + parent::setUp(); + $this->initializeEnvironments(); $this->servers = $this->getKolabServers(); } diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/KolabgermanbankarrangementTest.php b/framework/Kolab_Server/test/Horde/Kolab/Server/KolabgermanbankarrangementTest.php index 7eff469bc..57bf376b6 100644 --- a/framework/Kolab_Server/test/Horde/Kolab/Server/KolabgermanbankarrangementTest.php +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/KolabgermanbankarrangementTest.php @@ -60,6 +60,8 @@ class Horde_Kolab_Server_KolabgermanbankarrangementTest extends Horde_Kolab_Serv */ protected function setUp() { + parent::setUp(); + $this->initializeEnvironments(); $this->servers = $this->getKolabServers(); } diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/KolabinetorgpersonTest.php b/framework/Kolab_Server/test/Horde/Kolab/Server/KolabinetorgpersonTest.php index 75410d924..3b616d74c 100644 --- a/framework/Kolab_Server/test/Horde/Kolab/Server/KolabinetorgpersonTest.php +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/KolabinetorgpersonTest.php @@ -60,6 +60,8 @@ class Horde_Kolab_Server_KolabinetorgpersonTest extends Horde_Kolab_Server_Scena */ protected function setUp() { + parent::setUp(); + $this->initializeEnvironments(); $this->servers = $this->getKolabServers(); } diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/Kolabpop3accountTest.php b/framework/Kolab_Server/test/Horde/Kolab/Server/Kolabpop3accountTest.php index 157abd080..646f3630c 100644 --- a/framework/Kolab_Server/test/Horde/Kolab/Server/Kolabpop3accountTest.php +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/Kolabpop3accountTest.php @@ -62,6 +62,8 @@ class Horde_Kolab_Server_Kolabpop3accountTest extends Horde_Kolab_Server_Scenari */ protected function setUp() { + parent::setUp(); + $this->initializeEnvironments(); $this->servers = $this->getKolabServers(); } @@ -183,27 +185,23 @@ class Horde_Kolab_Server_Kolabpop3accountTest extends Horde_Kolab_Server_Scenari $account_data = $this->objects[1]; $account_data[Horde_Kolab_Server_Object_Kolabpop3account::ATTRIBUTE_OWNERUID] = $person->getUid(); $account = $server->add($account_data); - $this->assertNoError($account); - $account = $server->fetch($account->getUid()); - $this->assertNoError($account); $this->assertEquals($this->objects[1][Horde_Kolab_Server_Object_Kolabpop3account::ATTRIBUTE_SERVER], $account->get(Horde_Kolab_Server_Object_Kolabpop3account::ATTRIBUTE_SERVER)); $result = $account->save(array(Horde_Kolab_Server_Object_Kolabpop3account::ATTRIBUTE_SERVER => 'pop3s.example.com')); - $this->assertNoError($result); $account = $server->fetch($account->getUid()); - $this->assertNoError($account); - $this->assertEquals($account->get(Horde_Kolab_Server_Object_Kolabpop3account::ATTRIBUTE_SERVER), - 'pop3s.example.com'); + $this->assertContains( + 'pop3s.example.com', + $account->get(Horde_Kolab_Server_Object_Kolabpop3account::ATTRIBUTE_SERVER, false) + ); $this->assertContains('frank@example.com', $account->getUid()); $result = $server->delete($account->getUid()); - $this->assertNoError($result); } } } diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/LdapBase.php b/framework/Kolab_Server/test/Horde/Kolab/Server/LdapBase.php new file mode 100644 index 000000000..1af198444 --- /dev/null +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/LdapBase.php @@ -0,0 +1,45 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Prepare the test setup. + */ +require_once dirname(__FILE__) . '/Autoload.php'; + +/** + * Skip LDAP based tests if we don't have ldap or Net_LDAP2. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_LdapBase extends PHPUnit_Framework_TestCase +{ + public function setUp() + { + if (!extension_loaded('ldap') && !@dl('ldap.' . PHP_SHLIB_SUFFIX)) { + $this->markTestSuiteSkipped('Ldap extension is missing!'); + }; + + if (!class_exists('Net_LDAP2')) { + $this->markTestSuiteSkipped('PEAR package Net_LDAP2 is not installed!'); + } + } +} \ No newline at end of file diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/ObjectTest.php b/framework/Kolab_Server/test/Horde/Kolab/Server/ObjectTest.php index 0b830e9b2..4ac9bcea0 100644 --- a/framework/Kolab_Server/test/Horde/Kolab/Server/ObjectTest.php +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/ObjectTest.php @@ -42,6 +42,8 @@ class Horde_Kolab_Server_ObjectTest extends Horde_Kolab_Server_Scenario */ protected function setUp() { + parent::setUp(); + $this->_dummydb = new DummyDB(); } diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/OrgPersonTest.php b/framework/Kolab_Server/test/Horde/Kolab/Server/OrgPersonTest.php index 667ccb188..c720ce067 100644 --- a/framework/Kolab_Server/test/Horde/Kolab/Server/OrgPersonTest.php +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/OrgPersonTest.php @@ -60,6 +60,8 @@ class Horde_Kolab_Server_OrgPersonTest extends Horde_Kolab_Server_Scenario */ protected function setUp() { + parent::setUp(); + $this->initializeEnvironments(); $this->servers = $this->getKolabServers(); } diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/PersonTest.php b/framework/Kolab_Server/test/Horde/Kolab/Server/PersonTest.php index 90016e36c..de1b0b644 100644 --- a/framework/Kolab_Server/test/Horde/Kolab/Server/PersonTest.php +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/PersonTest.php @@ -114,6 +114,8 @@ class Horde_Kolab_Server_PersonTest extends Horde_Kolab_Server_Scenario */ protected function setUp() { + parent::setUp(); + $this->initializeEnvironments(); $this->servers = $this->getKolabServers(); } diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/Query/ElementTest.php b/framework/Kolab_Server/test/Horde/Kolab/Server/Query/ElementTest.php new file mode 100644 index 000000000..01f45783f --- /dev/null +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/Query/ElementTest.php @@ -0,0 +1,212 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Require our basic test case definition + */ +require_once dirname(__FILE__) . '/../Autoload.php'; + +/** + * Test the LDAP query elements. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Query_ElementTest extends PHPUnit_Framework_TestCase +{ + public function setUp() + { + $this->writer = $this->getMock( + 'Horde_Kolab_Server_Query_Ldap', array(), array(), '', false + ); + } + + public function testClassAndMethodConvertHasResultMixedTheConvertedElement() + { + $this->writer->expects($this->exactly(1)) + ->method('convertAnd') + ->will($this->returnValue('converted')); + $and = new Horde_Kolab_Server_Query_Element_And(array()); + $this->assertEquals('converted', $and->convert($this->writer)); + } + + public function testClassApproxMethodConvertHasResultMixedTheConvertedElement() + { + $this->writer->expects($this->exactly(1)) + ->method('convertApprox') + ->will($this->returnValue('converted')); + $approx = new Horde_Kolab_Server_Query_Element_Approx('', ''); + $this->assertEquals('converted', $approx->convert($this->writer)); + } + + public function testClassBeginsMethodConvertHasResultMixedTheConvertedElement() + { + $this->writer->expects($this->exactly(1)) + ->method('convertBegins') + ->will($this->returnValue('converted')); + $begins = new Horde_Kolab_Server_Query_Element_Begins('', ''); + $this->assertEquals('converted', $begins->convert($this->writer)); + } + + public function testClassContainsMethodConvertHasResultMixedTheConvertedElement() + { + $this->writer->expects($this->exactly(1)) + ->method('convertContains') + ->will($this->returnValue('converted')); + $contains = new Horde_Kolab_Server_Query_Element_Contains('', ''); + $this->assertEquals('converted', $contains->convert($this->writer)); + } + + public function testClassEndsMethodConvertHasResultMixedTheConvertedElement() + { + $this->writer->expects($this->exactly(1)) + ->method('convertEnds') + ->will($this->returnValue('converted')); + $ends = new Horde_Kolab_Server_Query_Element_Ends('', ''); + $this->assertEquals('converted', $ends->convert($this->writer)); + } + + public function testClassEqualsMethodConvertHasResultMixedTheConvertedElement() + { + $this->writer->expects($this->exactly(1)) + ->method('convertEquals') + ->will($this->returnValue('converted')); + $Equals = new Horde_Kolab_Server_Query_Element_Equals('', ''); + $this->assertEquals('converted', $Equals->convert($this->writer)); + } + + public function testClassGreaterMethodConvertHasResultMixedTheConvertedElement() + { + $this->writer->expects($this->exactly(1)) + ->method('convertGreater') + ->will($this->returnValue('converted')); + $Greater = new Horde_Kolab_Server_Query_Element_Greater('', ''); + $this->assertEquals('converted', $Greater->convert($this->writer)); + } + + public function testClassLessMethodConvertHasResultMixedTheConvertedElement() + { + $this->writer->expects($this->exactly(1)) + ->method('convertLess') + ->will($this->returnValue('converted')); + $less = new Horde_Kolab_Server_Query_Element_Less('', ''); + $this->assertEquals('converted', $less->convert($this->writer)); + } + + public function testClassNotMethodConstructHasPostconditionThatTheElementWasSavedAsArray() + { + $less = new Horde_Kolab_Server_Query_Element_Less('', ''); + $not = new Horde_Kolab_Server_Query_Element_Not($less); + $this->assertType('array', $not->getElements()); + } + + public function testClassNotMethodConvertHasResultMixedTheConvertedElement() + { + $this->writer->expects($this->exactly(1)) + ->method('convertNot') + ->will($this->returnValue('converted')); + $less = new Horde_Kolab_Server_Query_Element_Less('', ''); + $not = new Horde_Kolab_Server_Query_Element_Not($less); + $this->assertEquals('converted', $not->convert($this->writer)); + } + + public function testClassOrMethodConvertHasResultMixedTheConvertedElement() + { + $this->writer->expects($this->exactly(1)) + ->method('convertOr') + ->will($this->returnValue('converted')); + $or = new Horde_Kolab_Server_Query_Element_Or(array()); + $this->assertEquals('converted', $or->convert($this->writer)); + } + + public function testClassGroupMethodConstructHasParameterArrayElements() + { + $or = new Horde_Kolab_Server_Query_Element_Or(array()); + } + + public function testClassGroupMethodConstructHasPostconditionThatTheElementsWereSaved() + { + $or = new Horde_Kolab_Server_Query_Element_Or(array()); + $this->assertEquals(array(), $or->getElements()); + } + + /** + * @expectedException Exception + */ + public function testClassGroupMethodGetnameThrowsException() + { + $or = new Horde_Kolab_Server_Query_Element_Or(array()); + $or->getName(); + } + + /** + * @expectedException Exception + */ + public function testClassGroupMethodGetvalueThrowsException() + { + $or = new Horde_Kolab_Server_Query_Element_Or(array()); + $or->getValue(); + } + + public function testClassGroupMethodGetelementsHasResultArrayTheGroupElements() + { + $or = new Horde_Kolab_Server_Query_Element_Or(array()); + $this->assertEquals(array(), $or->getElements()); + } + + public function testClassSingleMethodConstructHasParameterStringName() + { + $equals = new Horde_Kolab_Server_Query_Element_Equals('name', ''); + } + + public function testClassSingleMethodConstructHasParameterStringValue() + { + $equals = new Horde_Kolab_Server_Query_Element_Equals('', 'value'); + } + + public function testClassSingleMethodConstructHasPostconditionThatNameAndValueWereSaved() + { + $equals = new Horde_Kolab_Server_Query_Element_Equals('name', 'value'); + $this->assertEquals('name', $equals->getName()); + $this->assertEquals('value', $equals->getValue()); + } + + public function testClassSingleMethodGetnameHasResultStringTheName() + { + $equals = new Horde_Kolab_Server_Query_Element_Equals('name', ''); + $this->assertEquals('name', $equals->getName()); + } + + public function testClassSingleMethodGetvalueHasResultStringTheValue() + { + $equals = new Horde_Kolab_Server_Query_Element_Equals('', 'value'); + $this->assertEquals('value', $equals->getValue()); + } + + /** + * @expectedException Exception + */ + public function testClassSingleMethodGetelementsThrowsException() + { + $equals = new Horde_Kolab_Server_Query_Element_Equals('', ''); + $equals->getElements(); + } +} diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/Query/LdapTest.php b/framework/Kolab_Server/test/Horde/Kolab/Server/Query/LdapTest.php new file mode 100644 index 000000000..85e44baae --- /dev/null +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/Query/LdapTest.php @@ -0,0 +1,181 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Require our basic test case definition + */ +require_once dirname(__FILE__) . '/../LdapBase.php'; + +/** + * Test the LDAP query handler. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Query_LdapTest extends Horde_Kolab_Server_LdapBase +{ + + public function testMethodConstructHasParameterQueryelementTheQueryCriteria() + { + $equals = new Horde_Kolab_Server_Query_Element_Equals('equals', 'equals'); + $query = new Horde_Kolab_Server_Query_Ldap($equals); + } + + public function testMethodConstructHasPostconditionThatTheQueryCriteriaWereSaved() + { + $equals = new Horde_Kolab_Server_Query_Element_Equals('equals', 'equals'); + $query = new Horde_Kolab_Server_Query_Ldap($equals); + $this->assertEquals( + '(equals=equals)', + (string) $query + ); + } + + public function testMethodTostringHasResultStringTheQuery() + { + $equals = new Horde_Kolab_Server_Query_Element_Equals('equals', 'equals'); + $contains = new Horde_Kolab_Server_Query_Element_Equals('contains', 'contains'); + $or = new Horde_Kolab_Server_Query_Element_Or(array($equals, $contains)); + $query = new Horde_Kolab_Server_Query_Ldap($or); + $this->assertEquals( + '(|(equals=equals)(contains=contains))', + (string) $query + ); + } + + public function testMethodConvertequealsHasResultNetldapfilter() + { + $equals = new Horde_Kolab_Server_Query_Element_Equals('equals', 'equals'); + $query = new Horde_Kolab_Server_Query_Ldap($equals); + $this->assertEquals( + '(equals=equals)', + $query->convertEquals($equals)->asString() + ); + } + + public function testMethodConvertbeginsHasResultNetldapfilter() + { + $begins = new Horde_Kolab_Server_Query_Element_Begins('begins', 'begins'); + $query = new Horde_Kolab_Server_Query_Ldap($begins); + $this->assertEquals( + '(begins=begins*)', + $query->convertBegins($begins)->asString() + ); + } + + public function testMethodConvertendsHasResultNetldapfilter() + { + $ends = new Horde_Kolab_Server_Query_Element_Ends('ends', 'ends'); + $query = new Horde_Kolab_Server_Query_Ldap($ends); + $this->assertEquals( + '(ends=*ends)', + $query->convertEnds($ends)->asString() + ); + } + + public function testMethodConvertcontainsHasResultNetldapfilter() + { + $contains = new Horde_Kolab_Server_Query_Element_Contains('contains', 'contains'); + $query = new Horde_Kolab_Server_Query_Ldap($contains); + $this->assertEquals( + '(contains=*contains*)', + $query->convertContains($contains)->asString() + ); + } + + public function testMethodConvertlessHasResultNetldapfilter() + { + $less = new Horde_Kolab_Server_Query_Element_Less('less', 'less'); + $query = new Horde_Kolab_Server_Query_Ldap($less); + $this->assertEquals( + '(lessconvertLess($less)->asString() + ); + } + + public function testMethodConvertgreaterHasResultNetldapfilter() + { + $greater = new Horde_Kolab_Server_Query_Element_Greater('greater', 'greater'); + $query = new Horde_Kolab_Server_Query_Ldap($greater); + $this->assertEquals( + '(greater>greater)', + $query->convertGreater($greater)->asString() + ); + } + + public function testMethodConvertapproxHasResultNetldapfilter() + { + $approx = new Horde_Kolab_Server_Query_Element_Approx('approx', 'approx'); + $query = new Horde_Kolab_Server_Query_Ldap($approx); + $this->assertEquals( + '(approx~=approx)', + $query->convertApprox($approx)->asString() + ); + } + + public function testMethodConvertnotHasResultNetldapfilter() + { + $equals = new Horde_Kolab_Server_Query_Element_Equals('equals', 'equals'); + $not = new Horde_Kolab_Server_Query_Element_Not($equals); + $query = new Horde_Kolab_Server_Query_Ldap($not); + $this->assertEquals( + '(!(equals=equals))', + $query->convertNot($not)->asString() + ); + } + + public function testMethodConvertandHasResultNetldapfilter() + { + $equals = new Horde_Kolab_Server_Query_Element_Equals('equals', 'equals'); + $contains = new Horde_Kolab_Server_Query_Element_Equals('contains', 'contains'); + $and = new Horde_Kolab_Server_Query_Element_And(array($equals, $contains)); + $query = new Horde_Kolab_Server_Query_Ldap($and); + $this->assertEquals( + '(&(equals=equals)(contains=contains))', + $query->convertAnd($and)->asString() + ); + } + + public function testMethodConvertorHasResultNetldapfilter() + { + $equals = new Horde_Kolab_Server_Query_Element_Equals('equals', 'equals'); + $contains = new Horde_Kolab_Server_Query_Element_Equals('contains', 'contains'); + $or = new Horde_Kolab_Server_Query_Element_Or(array($equals, $contains)); + $query = new Horde_Kolab_Server_Query_Ldap($or); + $this->assertEquals( + '(|(equals=equals)(contains=contains))', + $query->convertOr($or)->asString() + ); + } + + public function testMethodConvertorThrowsExceptionIfLessThanTwoElementsWereProvided() + { + $equals = new Horde_Kolab_Server_Query_Element_Equals('equals', 'equals'); + $or = new Horde_Kolab_Server_Query_Element_Or(array($equals)); + $query = new Horde_Kolab_Server_Query_Ldap($or); + try { + $query->convertOr($or)->asString(); + $this->fail('No exception!'); + } catch (Horde_Kolab_Server_Exception $e) { + $this->assertEquals(Horde_Kolab_Server_Exception::INVALID_QUERY, $e->getCode()); + } + } +} diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/Result/LdapTest.php b/framework/Kolab_Server/test/Horde/Kolab/Server/Result/LdapTest.php new file mode 100644 index 000000000..4da773a7b --- /dev/null +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/Result/LdapTest.php @@ -0,0 +1,90 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Prepare the test setup. + */ +require_once dirname(__FILE__) . '/../Autoload.php'; + +/** + * Test the LDAP result handler. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Result_LdapTest extends PHPUnit_Framework_TestCase +{ + public function setUp() + { + if (!extension_loaded('ldap') && !@dl('ldap.' . PHP_SHLIB_SUFFIX)) { + $this->markTestSuiteSkipped('Ldap extension is missing!'); + }; + + if (!class_exists('Net_LDAP2')) { + $this->markTestSuiteSkipped('PEAR package Net_LDAP2 is not installed!'); + } + } + + public function testMethodConstructHasParameterNetldap2searchSearchResult() + { + $search = $this->getMock( + 'Net_LDAP2_Search', array(), array(), '', false + ); + $result = new Horde_Kolab_Server_Result_Ldap($search); + } + + + public function testMethodCountHasResultIntTheNumberOfElementsFound() + { + $search = $this->getMock( + 'Net_LDAP2_Search', array('count'), array(), '', false + ); + $search->expects($this->exactly(1)) + ->method('count') + ->will($this->returnValue(1)); + $result = new Horde_Kolab_Server_Result_Ldap($search); + $this->assertEquals(1, $result->count()); + } + + public function testMethodSizelimitexceededHasResultBooleanIndicatingIfTheSearchSizeLimitWasHit() + { + $search = $this->getMock( + 'Net_LDAP2_Search', array('sizeLimitExceeded'), array(), '', false + ); + $search->expects($this->exactly(1)) + ->method('sizeLimitExceeded') + ->will($this->returnValue(true)); + $result = new Horde_Kolab_Server_Result_Ldap($search); + $this->assertTrue($result->sizeLimitExceeded()); + } + + public function testMethodAsarrayHasResultArrayWithTheSearchResults() + { + $search = $this->getMock( + 'Net_LDAP2_Search', array('as_struct'), array(), '', false + ); + $search->expects($this->exactly(1)) + ->method('as_struct') + ->will($this->returnValue(array('a' => 'a'))); + $result = new Horde_Kolab_Server_Result_Ldap($search); + $this->assertEquals(array('a' => 'a'), $result->asArray()); + } +} diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/Scenario.php b/framework/Kolab_Server/test/Horde/Kolab/Server/Scenario.php index f2f62b033..b8c8df11c 100644 --- a/framework/Kolab_Server/test/Horde/Kolab/Server/Scenario.php +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/Scenario.php @@ -65,12 +65,6 @@ class Horde_Kolab_Server_Scenario extends PHPUnit_Extensions_Story_TestCase } break; case 'several Kolab servers': - foreach ($this->getEnvironments() as $environment) { - $this->prepareInjector($environment); - $this->prepareKolabServerConfiguration($environment); - $this->prepareKolabServer($environment); - } - break; case 'the test environments': $this->initializeEnvironments(); break; @@ -338,6 +332,23 @@ class Horde_Kolab_Server_Scenario extends PHPUnit_Extensions_Story_TestCase } /** + * Prepare the log handler for the given environment. + * + * @param string $environment The name of the environment. + * + * @return NULL + */ + public function prepareLogger($environment) + { + $logger = new Horde_Log_Logger(); + $handler = new Horde_Log_Handler_Mock(); + $logger->addHandler($handler); + + $this->world['injector'][$environment]->setInstance('Horde_Log_Logger', + $logger); + } + + /** * Prepare the server configuration for the given environment. * * @param string $environment The name of the environment. @@ -401,6 +412,7 @@ class Horde_Kolab_Server_Scenario extends PHPUnit_Extensions_Story_TestCase public function initializeEnvironment($environment) { $this->prepareInjector($environment); + $this->prepareLogger($environment); $this->prepareKolabServerConfiguration($environment); $this->prepareKolabServer($environment); } @@ -1045,11 +1057,21 @@ class Horde_Kolab_Server_Scenario extends PHPUnit_Extensions_Story_TestCase } /** + * Setup function. + * + * @return NULL. + */ + protected function setUp() + { + $this->added = array(); + } + + /** * Cleanup function. * * @return NULL. */ - public function tearDown() + protected function tearDown() { if (isset($this->added)) { $added = array_reverse($this->added); diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/Server/FactoryTest.php b/framework/Kolab_Server/test/Horde/Kolab/Server/Server/FactoryTest.php new file mode 100644 index 000000000..4289a9eee --- /dev/null +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/Server/FactoryTest.php @@ -0,0 +1,120 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Prepare the test setup. + */ +require_once dirname(__FILE__) . '/../Autoload.php'; + +/** + * Test the server factory interface. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Server_FactoryTest extends Horde_Kolab_Server_Scenario +{ + public function testMethodSetupHasPostconditionThatAObjectHandlerOfTypeBaseIsBoundToObjects() + { + $injector = new Horde_Injector(new Horde_Injector_TopLevel()); + Horde_Kolab_Server_Factory::setup(array(), $injector); + $this->assertType( + 'Horde_Kolab_Server_Objects_Base', + $injector->getInstance('Horde_Kolab_Server_Objects') + ); + } + + public function testMethodSetupHasPostconditionThatASchemaHandlerOfTypeBaseIsBoundToSchema() + { + $injector = new Horde_Injector(new Horde_Injector_TopLevel()); + Horde_Kolab_Server_Factory::setup(array(), $injector); + $this->assertType( + 'Horde_Kolab_Server_Schema_Base', + $injector->getInstance('Horde_Kolab_Server_Schema') + ); + } + + public function testMethodSetupHasPostconditionThatASearchHandlerOfTypeBaseIsBoundToSearch() + { + $injector = new Horde_Injector(new Horde_Injector_TopLevel()); + Horde_Kolab_Server_Factory::setup(array(), $injector); + $this->assertType( + 'Horde_Kolab_Server_Search_Base', + $injector->getInstance('Horde_Kolab_Server_Search') + ); + } + + public function testMethodSetupHasPostconditionThatAStructureOfTypeBaseIsBoundToStructure() + { + $injector = new Horde_Injector(new Horde_Injector_TopLevel()); + Horde_Kolab_Server_Factory::setup(array(), $injector); + $this->assertType( + 'Horde_Kolab_Server_Structure_Kolab', + $injector->getInstance('Horde_Kolab_Server_Structure') + ); + } + + public function testMethodSetupHasPostconditionThatAStructureHandlerOfTypeLdapIsBoundToStructureIfConfiguredThatWay() + { + $injector = new Horde_Injector(new Horde_Injector_TopLevel()); + Horde_Kolab_Server_Factory::setup( + array('structure' => array('driver' => 'ldap')), + $injector + ); + $this->assertType( + 'Horde_Kolab_Server_Structure_Ldap', + $injector->getInstance('Horde_Kolab_Server_Structure') + ); + } + + public function testMethodSetupHasPostconditionThatAServerOfTypeLdapIsBoundToServer() + { + $injector = new Horde_Injector(new Horde_Injector_TopLevel()); + Horde_Kolab_Server_Factory::setup(array(), $injector); + $this->assertType( + 'Horde_Kolab_Server_Ldap', + $injector->getInstance('Horde_Kolab_Server') + ); + } + + public function testMethodSetupHasPostconditionThatAServerOfTypeLdapIsBoundToServerIfConfiguredThatWay() + { + $injector = new Horde_Injector(new Horde_Injector_TopLevel()); + Horde_Kolab_Server_Factory::setup( + array('driver' => 'file', 'params' => array('file' => '/tmp/nix')), + $injector + ); + $this->assertType( + 'Horde_Kolab_Server_File', + $injector->getInstance('Horde_Kolab_Server') + ); + } + + public function testMethodSingletonReturnsTheSameInstanceWithTheSameParameters() + { + Horde_Kolab_Server_Factory::singleton(); + } + + public function testMethodSingletonReturnsDifferentInstancesWithDifferentParameters() + { + Horde_Kolab_Server_Factory::singleton(); + } +} \ No newline at end of file diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/Server/InterfaceTest.php b/framework/Kolab_Server/test/Horde/Kolab/Server/Server/InterfaceTest.php new file mode 100644 index 000000000..c8fe1649a --- /dev/null +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/Server/InterfaceTest.php @@ -0,0 +1,36 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Prepare the test setup. + */ +require_once dirname(__FILE__) . '/../Autoload.php'; + +/** + * Test the server interface. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Server_InterfaceTest extends Horde_Kolab_Server_Scenario +{ + +} \ No newline at end of file diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/Server/LdapTest.php b/framework/Kolab_Server/test/Horde/Kolab/Server/Server/LdapTest.php new file mode 100644 index 000000000..c4e070ccb --- /dev/null +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/Server/LdapTest.php @@ -0,0 +1,363 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Require our basic test case definition + */ +require_once dirname(__FILE__) . '/../LdapBase.php'; + +/** + * Test the LDAP backend. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Server_LdapTest extends Horde_Kolab_Server_LdapBase +{ + public function setUp() + { + parent::setUp(); + + $this->logger = new Horde_Log_Handler_Mock(); + + $injector = new Horde_Injector(new Horde_Injector_TopLevel()); + Horde_Kolab_Server_Factory::setup( + array('logger' => new Horde_Log_Logger($this->logger)), $injector + ); + $this->server = $injector->getInstance('Horde_Kolab_Server'); + } + + public function testMethodConnectuidHasPostconditionThatTheUidIsSetIfTheConnectionWasSuccessful() + { + $ldap = $this->getMock('Net_LDAP2', array('bind')); + $ldap->expects($this->exactly(1)) + ->method('bind') + ->will($this->returnValue(true)); + $this->server->setLdap($ldap); + $this->server->connectUid('test', 'test'); + $this->assertEquals('test', $this->server->uid); + } + + public function testMethodConnectuidThrowsExceptionIfTheConnectionFailed() + { + $ldap = $this->getMock('Net_LDAP2', array('bind')); + $ldap->expects($this->exactly(1)) + ->method('bind') + ->will($this->returnValue(PEAR::raiseError('Bind failed!'))); + $this->server->setLdap($ldap); + try { + $this->server->connectUid('test', 'test'); + $this->fail('No exception!'); + } catch (Exception $e) { + $this->assertEquals('Bind failed!', $e->getMessage()); + $this->assertEquals(Horde_Kolab_Server_Exception::BIND_FAILED, $e->getCode()); + } + } + + public function testMethodSearchHasPostconditionThatItIsPossibleToTestTheLastResultForAnExceededSearchSizeLimit() + { + $ldap = $this->getMock('Net_LDAP2', array('search')); + $ldap->expects($this->exactly(1)) + ->method('search') + ->will($this->returnValue(new Search_Mock(array(array('dn' => 'test')), true))); + $this->server->setLdap($ldap); + $this->server->search('filter'); + $this->assertTrue($this->server->sizeLimitExceeded()); + } + + public function testMethodSearchReturnsArraySearchResult() + { + $ldap = $this->getMock('Net_LDAP2', array('search')); + $ldap->expects($this->exactly(1)) + ->method('search') + ->will($this->returnValue(new Search_Mock(array(array('dn' => 'test'))))); + $this->server->setLdap($ldap); + $this->assertEquals(array(array('dn' => 'test')), $this->server->search('filter')); + } + + public function testMethodSearchReturnsArrayMappedSearchResultIfMappingIsActivated() + { + $ldap = $this->getMock('Net_LDAP2', array('search')); + $ldap->expects($this->exactly(1)) + ->method('search') + ->will($this->returnValue(new Search_Mock(array(array('dn2' => 'test'))))); + $this->server->setLdap($ldap); + $this->server->setParams(array('map' => array('dn' => 'dn2'))); + $this->assertEquals( + array(array('dn' => 'test')), + $this->server->search( + 'filter', + array('attributes' => array('dn')) + ) + ); + } + + public function testMethodSearchThrowsExceptionIfTheSearchFailed() + { + $ldap = $this->getMock('Net_LDAP2', array('search')); + $ldap->expects($this->exactly(1)) + ->method('search') + ->will($this->returnValue(PEAR::raiseError('Search failed!'))); + $this->server->setLdap($ldap); + try { + $this->assertEquals(array('dn' => 'test'), $this->server->search('filter')); + $this->fail('No exception!'); + } catch (Exception $e) { + $this->assertEquals('Search failed!', $e->getMessage()); + $this->assertEquals(Horde_Kolab_Server_Exception::SYSTEM, $e->getCode()); + } + } + + public function testMethodReadReturnsArrayReadResult() + { + $ldap = $this->getMock('Net_LDAP2', array('search')); + $ldap->expects($this->exactly(1)) + ->method('search') + ->will($this->returnValue(new Search_Mock(array(array('dn' => 'test'))))); + $this->server->setLdap($ldap); + $this->assertEquals(array('dn' => 'test'), $this->server->read('test')); + } + + public function testMethodReadThrowsExceptionIfTheObjectWasNotFound() + { + $ldap = $this->getMock('Net_LDAP2', array('search')); + $ldap->expects($this->exactly(1)) + ->method('search') + ->will($this->returnValue(new Search_Mock(array()))); + $this->server->setLdap($ldap); + try { + $this->assertEquals(array(), $this->server->read('test', array('dn'))); + $this->fail('No exception!'); + } catch (Exception $e) { + $this->assertEquals('Empty result!', $e->getMessage()); + $this->assertEquals(Horde_Kolab_Server_Exception::EMPTY_RESULT, $e->getCode()); + } + } + + public function testMethodSaveHasPostconditionThatTheEntryWasSaved() + { + $ldap = $this->getMock('Net_LDAP2', array('add')); + $ldap->expects($this->exactly(1)) + ->method('add') + ->with(new PHPUnit_Framework_Constraint_IsInstanceOf('Net_LDAP2_Entry')); + $this->server->setLdap($ldap); + $this->server->save('test', array('add' => array('dn' => 'test'))); + } + + public function testMethodSaveThrowsExceptionIfDataToSaveIsNoArray() + { + $ldap = $this->getMock('Net_LDAP2', array('add')); + $this->server->setLdap($ldap); + try { + $this->server->save('test', array('add' => 'hello')); + $this->fail('No exception!'); + } catch (Exception $e) { + $this->assertEquals('Unable to create fresh entry: Parameter $attrs needs to be an array!', $e->getMessage()); + $this->assertEquals(Horde_Kolab_Server_Exception::SYSTEM, $e->getCode()); + } + + } + + public function testMethodSaveThrowsExceptionIfSavingDataFailed() + { + $ldap = $this->getMock('Net_LDAP2', array('add')); + $ldap->expects($this->exactly(1)) + ->method('add') + ->will($this->returnValue(PEAR::raiseError('Saving failed!'))); + $this->server->setLdap($ldap); + try { + $this->server->save('test', array('add' => array('dn' => 'test'))); + $this->fail('No exception!'); + } catch (Exception $e) { + $this->assertEquals('Saving failed!', $e->getMessage()); + $this->assertEquals(Horde_Kolab_Server_Exception::SYSTEM, $e->getCode()); + } + } + + public function testMethodDeleteHasPostconditionThatTheEntryWasDeleted() + { + $ldap = $this->getMock('Net_LDAP2', array('delete')); + $ldap->expects($this->exactly(1)) + ->method('delete') + ->with('test'); + $this->server->setLdap($ldap); + $this->server->delete('test'); + } + + public function testMethodDeleteThrowsExceptionIfDeletingDataFailed() + { + $ldap = $this->getMock('Net_LDAP2', array('delete')); + $ldap->expects($this->exactly(1)) + ->method('delete') + ->will($this->returnValue(PEAR::raiseError('Deleting failed!'))); + $this->server->setLdap($ldap); + try { + $this->server->delete('test'); + $this->fail('No exception!'); + } catch (Exception $e) { + $this->assertEquals('Deleting failed!', $e->getMessage()); + $this->assertEquals(Horde_Kolab_Server_Exception::SYSTEM, $e->getCode()); + } + } + + public function testMethodRenameHasPostconditionThatTheEntryWasRenamed() + { + $ldap = $this->getMock('Net_LDAP2', array('move')); + $ldap->expects($this->exactly(1)) + ->method('move') + ->with('test', 'new'); + $this->server->setLdap($ldap); + $this->server->rename('test', 'new'); + } + + public function testMethodRenameThrowsExceptionIfRenamingDataFailed() + { + $ldap = $this->getMock('Net_LDAP2', array('move')); + $ldap->expects($this->exactly(1)) + ->method('move') + ->will($this->returnValue(PEAR::raiseError('Renaming failed!'))); + $this->server->setLdap($ldap); + try { + $this->server->rename('test', 'new'); + $this->fail('No exception!'); + } catch (Exception $e) { + $this->assertEquals('Renaming failed!', $e->getMessage()); + $this->assertEquals(Horde_Kolab_Server_Exception::SYSTEM, $e->getCode()); + } + } + + public function testMethodGetobjectclassesHasResultArrayWithLowerCaseObjectclassNames() + { + $ldap = $this->getMock('Net_LDAP2', array('search')); + $ldap->expects($this->exactly(1)) + ->method('search') + ->will($this->returnValue(new Search_Mock(array(array(Horde_Kolab_Server_Object::ATTRIBUTE_OC => array('test', 'PERSON', 'Last')))))); + $this->server->setLdap($ldap); + $this->assertEquals( + array('test', 'person', 'last'), + $this->server->getObjectClasses('test') + ); + } + + public function testMethodGetobjectclassesThrowsExceptionIfTheObjectHasNoAttributeObjectclass() + { + $ldap = $this->getMock('Net_LDAP2', array('search')); + $ldap->expects($this->exactly(1)) + ->method('search') + ->will($this->returnValue(new Search_Mock(array(array('dummy' => array('test', 'PERSON', 'Last')))))); + $this->server->setLdap($ldap); + try { + $this->server->getObjectClasses('test'); + $this->fail('No exception!'); + } catch (Exception $e) { + $this->assertEquals('The object test has no objectClass attribute!', $e->getMessage()); + $this->assertEquals(Horde_Kolab_Server_Exception::SYSTEM, $e->getCode()); + } + } + + public function testMethodGetschemaReturnsArrayWithADescriptionOfAllObjectClasses() + { + $ldap = $this->getMock('Net_LDAP2', array('schema')); + $ldap->expects($this->exactly(1)) + ->method('schema') + ->will($this->returnValue(array('schema' => 'dummy'))); + $this->server->setLdap($ldap); + $this->assertEquals( + array('schema' => 'dummy'), + $this->server->getSchema() + ); + } + + public function testMethodGetschemaThrowsExceptionIfTheSchemaRetrievalFailed() + { + $ldap = $this->getMock('Net_LDAP2', array('schema')); + $ldap->expects($this->exactly(1)) + ->method('schema') + ->will($this->returnValue(PEAR::raiseError('Schema failed!'))); + $this->server->setLdap($ldap); + try { + $this->server->getSchema(); + $this->fail('No exception!'); + } catch (Exception $e) { + $this->assertEquals('Schema failed!', $e->getMessage()); + $this->assertEquals(Horde_Kolab_Server_Exception::SYSTEM, $e->getCode()); + } + } + + /** + * Test handling of object classes. + * + * @return NULL + */ +/* public function testGetObjectClasses() */ +/* { */ +/* $ldap = $this->getMock('Horde_Kolab_Server_ldap', array('read')); */ +/* $ldap->expects($this->any()) */ +/* ->method('read') */ +/* ->will($this->returnValue(array ( */ +/* 'objectClass' => */ +/* array ( */ +/* 'count' => 4, */ +/* 0 => 'top', */ +/* 1 => 'inetOrgPerson', */ +/* 2 => 'kolabInetOrgPerson', */ +/* 3 => 'hordePerson', */ +/* ), */ +/* 0 => 'objectClass', */ +/* 'count' => 1))); */ + +/* $classes = $ldap->getObjectClasses('cn=Gunnar Wrobel,dc=example,dc=org'); */ +/* if ($classes instanceOf PEAR_Error) { */ +/* $this->assertEquals('', $classes->getMessage()); */ +/* } */ +/* $this->assertContains('top', $classes); */ +/* $this->assertContains('kolabinetorgperson', $classes); */ +/* $this->assertContains('hordeperson', $classes); */ + +/* $ldap = $this->getMock('Horde_Kolab_Server_ldap', array('read')); */ +/* $ldap->expects($this->any()) */ +/* ->method('read') */ +/* ->will($this->returnValue(PEAR::raiseError('LDAP Error: No such object: cn=DOES NOT EXIST,dc=example,dc=org: No such object'))); */ + +/* $classes = $ldap->getObjectClasses('cn=DOES NOT EXIST,dc=example,dc=org'); */ +/* $this->assertEquals('LDAP Error: No such object: cn=DOES NOT EXIST,dc=example,dc=org: No such object', */ +/* $classes->message); */ +/* } */ + +} + + +class Search_Mock +{ + public function __construct($result, $limit = false) + { + $this->result = $result; + $this->limit = $limit; + } + public function as_struct() + { + return $this->result; + } + public function sizeLimitExceeded() + { + return $this->limit; + } +} \ No newline at end of file diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/Server/LoggedTest.php b/framework/Kolab_Server/test/Horde/Kolab/Server/Server/LoggedTest.php new file mode 100644 index 000000000..1957bb2a6 --- /dev/null +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/Server/LoggedTest.php @@ -0,0 +1,167 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Require our basic test case definition + */ +require_once dirname(__FILE__) . '/../LdapBase.php'; + +/** + * Test the LDAP backend. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Server_LoggedTest extends Horde_Kolab_Server_LdapBase +{ + public function setUp() + { + parent::setUp(); + + $this->logger = new Horde_Log_Handler_Mock(); + $this->server = $this->getMock('Horde_Kolab_Server'); + $this->logged = new Horde_Kolab_Server_Logged( + $this->server, + new Horde_Log_Logger($this->logger) + ); + } + + public function testMethodConnectguidDelegatesToServer() + { + $this->server->expects($this->exactly(1)) + ->method('connectGuid') + ->with('user', 'pass'); + $this->logged->connectGuid('user', 'pass'); + } + + public function testMethodReadDelegatesToServer() + { + $this->server->expects($this->exactly(1)) + ->method('read') + ->with('guid'); + $this->logged->read('guid'); + } + + public function testMethodReadattributesDelegatesToServer() + { + $this->server->expects($this->exactly(1)) + ->method('readAttributes') + ->with('guid', array('a')); + $this->logged->readAttributes('guid', array('a')); + } + + public function testMethodFindDelegatesToServer() + { + $query = $this->getMock( + 'Horde_Kolab_Server_Query', array(), array(), '', false + ); + $this->server->expects($this->exactly(1)) + ->method('find') + ->with($query); + $this->logged->find($query); + } + + public function testMethodFindbelowDelegatesToServer() + { + $query = $this->getMock( + 'Horde_Kolab_Server_Query', array(), array(), '', false + ); + $this->server->expects($this->exactly(1)) + ->method('findBelow') + ->with($query, 'none'); + $this->logged->findBelow($query, 'none'); + } + + public function testMethodSaveDelegatesToServer() + { + $this->server->expects($this->exactly(1)) + ->method('save') + ->with('a', array('a' => 'a')); + $this->logged->save('a', array('a' => 'a')); + } + + public function testMethodAddDelegatesToServer() + { + $this->server->expects($this->exactly(1)) + ->method('add') + ->with('a', array('a' => 'a')); + $this->logged->add('a', array('a' => 'a')); + } + + public function testMethodDeleteDelegatesToServer() + { + $this->server->expects($this->exactly(1)) + ->method('delete') + ->with('a'); + $this->logged->delete('a'); + } + + public function testMethodRenameDelegatesToServer() + { + $this->server->expects($this->exactly(1)) + ->method('rename') + ->with('a', 'b'); + $this->logged->rename('a', 'b'); + } + + public function testMethodGetschemaDelegatesToServer() + { + $this->server->expects($this->exactly(1)) + ->method('getSchema'); + $this->logged->getSchema(); + } + + public function testMethodSaveHasPostconditionThatTheEventWasLogged() + { + $this->logged->save('a', array('a' => 'a')); + $this->assertEquals( + $this->logger->events[0]['message'], + 'The object "a" has been successfully saved!' + ); + } + + public function testMethodAddHasPostconditionThatTheEventWasLogged() + { + $this->logged->add('a', array('a' => 'a')); + $this->assertEquals( + $this->logger->events[0]['message'], + 'The object "a" has been successfully added!' + ); + } + + public function testMethodDeleteHasPostconditionThatTheEventWasLogged() + { + $this->logged->delete('a'); + $this->assertEquals( + $this->logger->events[0]['message'], + 'The object "a" has been successfully deleted!' + ); + } + + public function testMethodRenameHasPostconditionThatTheEventWasLogged() + { + $this->logged->rename('a', 'b'); + $this->assertEquals( + $this->logger->events[0]['message'], + 'The object "a" has been successfully renamed to "b"!' + ); + } +} \ No newline at end of file diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/Server/SearchTest.php b/framework/Kolab_Server/test/Horde/Kolab/Server/Server/SearchTest.php new file mode 100644 index 000000000..398029620 --- /dev/null +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/Server/SearchTest.php @@ -0,0 +1,221 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Prepare the test setup. + */ +require_once dirname(__FILE__) . '/../Autoload.php'; + +/** + * Test the search handler. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Server_SearchTest extends PHPUnit_Framework_TestCase +{ + public function setUp() + { + if (!extension_loaded('ldap') && !@dl('ldap.' . PHP_SHLIB_SUFFIX)) { + $this->markTestSuiteSkipped('Ldap extension is missing!'); + }; + + if (!class_exists('Net_LDAP2')) { + $this->markTestSuiteSkipped('PEAR package Net_LDAP2 is not installed!'); + } + + $injector = new Horde_Injector(new Horde_Injector_TopLevel()); + Horde_Kolab_Server_Factory::setup(array(), $injector); + $this->server = $injector->getInstance('Horde_Kolab_Server'); + } + + /** + * Test retrieving a primary mail for a mail or uid. + * + * @return NULL + */ +/* public function testMailForUidOrMail() */ +/* { */ +/* $ldap = $this->getMock('Horde_Kolab_Server_ldap', array('getAttributes', */ +/* 'search', 'count', */ +/* 'firstEntry')); */ +/* $ldap->expects($this->any()) */ +/* ->method('_getAttributes') */ +/* ->will($this->returnValue(array ( */ +/* 'mail' => */ +/* array ( */ +/* 'count' => 1, */ +/* 0 => 'wrobel@example.org', */ +/* ), */ +/* 0 => 'mail', */ +/* 'count' => 1))); */ +/* $ldap->expects($this->any()) */ +/* ->method('_search') */ +/* ->will($this->returnValue('cn=Gunnar Wrobel,dc=example,dc=org')); */ +/* $ldap->expects($this->any()) */ +/* ->method('_count') */ +/* ->will($this->returnValue(1)); */ +/* $ldap->expects($this->any()) */ +/* ->method('_firstEntry') */ +/* ->will($this->returnValue(1)); */ + +/* $mail = $ldap->mailForIdOrMail('wrobel'); */ +/* $this->assertEquals('wrobel@example.org', $mail); */ + +/* $ldap = $this->getMock('Horde_Kolab_Server_ldap', array('_getAttributes', */ +/* '_search', */ +/* '_count', */ +/* '_firstEntry', */ +/* '_errno', */ +/* '_error')); */ +/* $ldap->expects($this->any()) */ +/* ->method('_getAttributes') */ +/* ->will($this->returnValue(false)); */ +/* $ldap->expects($this->any()) */ +/* ->method('_search') */ +/* ->will($this->returnValue('cn=Gunnar Wrobel,dc=example,dc=org')); */ +/* $ldap->expects($this->any()) */ +/* ->method('_count') */ +/* ->will($this->returnValue(1)); */ +/* $ldap->expects($this->any()) */ +/* ->method('_firstEntry') */ +/* ->will($this->returnValue(1)); */ +/* $ldap->expects($this->any()) */ +/* ->method('_errno') */ +/* ->will($this->returnValue(1)); */ +/* $ldap->expects($this->any()) */ +/* ->method('_error') */ +/* ->will($this->returnValue('cn=DOES NOT EXIST,dc=example,dc=org: No such object')); */ + +/* $mail = $ldap->mailForIdOrMail('wrobel'); */ +/* $this->assertEquals('Retrieving attributes failed. Error was: cn=DOES NOT EXIST,dc=example,dc=org: No such object', */ +/* $mail->message); */ + +/* $ldap = $this->getMock('Horde_Kolab_Server_ldap', array('_getAttributes', */ +/* '_search', */ +/* '_count')); */ +/* $ldap->expects($this->any()) */ +/* ->method('_getAttributes') */ +/* ->will($this->returnValue(false)); */ +/* $ldap->expects($this->any()) */ +/* ->method('_search') */ +/* ->will($this->returnValue('cn=Gunnar Wrobel,dc=example,dc=org')); */ +/* $ldap->expects($this->any()) */ +/* ->method('_count') */ +/* ->will($this->returnValue(4)); */ + +/* $mail = $ldap->mailForIdOrMail('wrobel'); */ +/* $this->assertEquals('Found 4 results when expecting only one!', */ +/* $mail->message); */ +/* } */ + +/* /\** */ +/* * Test retrieving a DN for a mail or uid. */ +/* * */ +/* * @return NULL */ +/* *\/ */ +/* public function testDnForUidOrMail() */ +/* { */ +/* $ldap = $this->getMock('Horde_Kolab_Server_ldap', array('_getDn', */ +/* '_search', '_count', */ +/* '_firstEntry')); */ +/* $ldap->expects($this->any()) */ +/* ->method('_getDn') */ +/* ->will($this->returnValue('cn=Gunnar Wrobel,dc=example,dc=org')); */ +/* $ldap->expects($this->any()) */ +/* ->method('_search') */ +/* ->will($this->returnValue('cn=Gunnar Wrobel,dc=example,dc=org')); */ +/* $ldap->expects($this->any()) */ +/* ->method('_count') */ +/* ->will($this->returnValue(1)); */ +/* $ldap->expects($this->any()) */ +/* ->method('_firstEntry') */ +/* ->will($this->returnValue(1)); */ + +/* $dn = $ldap->uidForIdOrMail('wrobel'); */ +/* $this->assertEquals('cn=Gunnar Wrobel,dc=example,dc=org', $dn); */ + +/* $ldap = $this->getMock('Horde_Kolab_Server_ldap', array('_getDn', */ +/* '_search', */ +/* '_count', */ +/* '_firstEntry', */ +/* '_errno', */ +/* '_error')); */ +/* $ldap->expects($this->any()) */ +/* ->method('_getDn') */ +/* ->will($this->returnValue(false)); */ +/* $ldap->expects($this->any()) */ +/* ->method('_search') */ +/* ->will($this->returnValue('cn=Gunnar Wrobel,dc=example,dc=org')); */ +/* $ldap->expects($this->any()) */ +/* ->method('_count') */ +/* ->will($this->returnValue(1)); */ +/* $ldap->expects($this->any()) */ +/* ->method('_firstEntry') */ +/* ->will($this->returnValue(1)); */ +/* $ldap->expects($this->any()) */ +/* ->method('_errno') */ +/* ->will($this->returnValue(1)); */ +/* $ldap->expects($this->any()) */ +/* ->method('_error') */ +/* ->will($this->returnValue('cn=DOES NOT EXIST,dc=example,dc=org: No such object')); */ + +/* $dn = $ldap->uidForIdOrMail('wrobel'); */ +/* $this->assertEquals('Retrieving DN failed. Error was: cn=DOES NOT EXIST,dc=example,dc=org: No such object', */ +/* $dn->message); */ + +/* $ldap = $this->getMock('Horde_Kolab_Server_ldap', array('_getDn', */ +/* '_search', */ +/* '_count')); */ +/* $ldap->expects($this->any()) */ +/* ->method('_getDn') */ +/* ->will($this->returnValue(false)); */ +/* $ldap->expects($this->any()) */ +/* ->method('_search') */ +/* ->will($this->returnValue('cn=Gunnar Wrobel,dc=example,dc=org')); */ +/* $ldap->expects($this->any()) */ +/* ->method('_count') */ +/* ->will($this->returnValue(4)); */ + +/* $dn = $ldap->uidForIdOrMail('wrobel'); */ +/* $this->assertEquals('Found 4 results when expecting only one!', */ +/* $dn->message); */ +/* } */ + +} + + +class Search_Mock +{ + public function __construct($result, $limit = false) + { + $this->result = $result; + $this->limit = $limit; + } + public function as_struct() + { + return $this->result; + } + public function sizeLimitExceeded() + { + return $this->limit; + } +} \ No newline at end of file diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/Server/ServerTest.php b/framework/Kolab_Server/test/Horde/Kolab/Server/Server/ServerTest.php new file mode 100644 index 000000000..b879a14fc --- /dev/null +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/Server/ServerTest.php @@ -0,0 +1,329 @@ + + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Prepare the test setup. + */ +require_once dirname(__FILE__) . '/../Autoload.php'; + +/** + * Tests for the main server class. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Server_ServerTest extends PHPUnit_Framework_TestCase +{ + /** + * Provide a mock server. + * + * @return Horde_Kolab_Server The mock server. + */ + protected function getMockServer() + { + $injector = new Horde_Injector(new Horde_Injector_TopLevel()); + $config = new stdClass; + $config->driver = 'none'; + $injector->setInstance('Horde_Kolab_Server_Config', $config); + $injector->bindFactory('Horde_Kolab_Server_Structure', + 'Horde_Kolab_Server_Factory', + 'getStructure'); + $injector->bindFactory('Horde_Kolab_Server', + 'Horde_Kolab_Server_Factory', + 'getServer'); + return $injector->getInstance('Horde_Kolab_Server'); + } + + /** + * The generating a uid for an object. + * + * @return NULL + */ + public function testGenerateUid() + { + $ks = $this->getMockServer(); + $user = new Horde_Kolab_Server_Object($ks, null, null); + $this->assertEquals(preg_replace('/[0-9a-f]*/', '', $user->get(Horde_Kolab_Server_Object::ATTRIBUTE_UID)), ''); + } + + /** + * Test creating the server object. + * + * @return NULL + */ + public function testCreation() + { + try { + $injector = new Horde_Injector(new Horde_Injector_TopLevel()); + $config = new stdClass; + $config->driver = 'dummy'; + $injector->setInstance('Horde_Kolab_Server_Config', $config); + $injector->bindFactory('Horde_Kolab_Server_Structure', + 'Horde_Kolab_Server_Factory', + 'getStructure'); + $injector->bindFactory('Horde_Kolab_Server', + 'Horde_Kolab_Server_Factory', + 'getServer'); + Horde_Kolab_Server_Factory::getServer($injector); + $this->assertFail('No error!'); + } catch (Horde_Kolab_Server_Exception $e) { + $this->assertEquals('Server type definition "Horde_Kolab_Server_Dummy" missing.', + $e->getMessage()); + } + } + + /** + * The base class provides no abilities for reading data. So it + * should mainly return error. But it should be capable of + * returning a dummy Kolab user object. + * + * @return NULL + */ + public function testFetch() + { + $ks = $this->getMockServer(); + $user = $ks->fetch('test'); + $this->assertEquals('Horde_Kolab_Server_Object_Kolab_User', get_class($user)); + + $ks = $this->getMockServer(); + $user = $ks->fetch(); + $this->assertEquals('Horde_Kolab_Server_Object_Kolab_User', get_class($user)); + } + + /** + * Test listing objects. + * + * @return NULL + */ + public function testList() + { + $ks = $this->getMockServer(); + $hash = $ks->listHash('Horde_Kolab_Server_Object'); + $this->assertEquals($hash, array()); + + $ks = $this->getMockServer(); + $hash = $ks->listHash('Horde_Kolab_Server_Object'); + $this->assertEquals($hash, array()); + } + +} + +/** + * A dummy class to test the original abstract class. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_None extends Horde_Kolab_Server +{ + /** + * Stub for reading object data. + * + * @param string $uid The object to retrieve. + * @param string $attrs Restrict to these attributes. + * + * @return array|PEAR_Error An array of attributes. + */ + public function read($uid, $attrs = null) + { + return false; + } + + /** + * Stub for saving object data. + * + * @param string $uid The object to retrieve. + * @param string $attrs Restrict to these attributes. + * + * @return array|PEAR_Error An array of attributes. + */ + public function save($uid, $data, $exists = false) + { + throw new Horde_Kolab_Server_Exception('Not implemented!'); + } + + /** + * Stub for deleting an object. + * + * @param string $uid The UID of the object to be deleted. + * + * @return boolean True if saving succeeded. + * + * @throws Horde_Kolab_Server_Exception + */ + public function delete($uid) + { + throw new Horde_Kolab_Server_Exception('Not implemented!'); + } + + /** + * Stub for renaming an object. + * + * @param string $uid The UID of the object to be renamed. + * @param string $new The new UID of the object. + * + * @return boolean True if renaming succeeded. + * + * @throws Horde_Kolab_Server_Exception + */ + public function rename($uid, $new) + { + throw new Horde_Kolab_Server_Exception('Not implemented!'); + } + + /** + * Determine the type of a Kolab object. + * + * @param string $uid The UID of the object to examine. + * + * @return string The corresponding Kolab object type. + */ + public function determineType($uid) + { + return 'Horde_Kolab_Server_Object_Kolab_User'; + } + + /** + * List all objects of a specific type + * + * @param string $type The type of the objects to be listed + * @param array $params Additional parameters. + * + * @return array|PEAR_Error An array of Kolab objects. + */ + public function listObjects($type, $params = null) + { + return array(); + } + + /** + * Generates a UID for the given information. + * + * @param string $type The type of the object to create. + * @param string $id The id of the object. + * @param array $info Any additional information about the object to create. + * + * @return string|PEAR_Error The UID. + */ + public function generateServerUid($type, $id, $info) + { + return $id; + } + + /** + * Return the root of the UID values on this server. + * + * @return string The base UID on this server (base DN on ldap). + */ + public function getBaseUid() + { + return ''; + } + + /** + * Identify the UID for the first object found using the specified + * search criteria. + * + * @param array $criteria The search parameters as array. + * @param int $restrict A Horde_Kolab_Server::RESULT_* result restriction. + * + * @return boolean|string|array The UID(s) or false if there was no result. + * + * @throws Horde_Kolab_Server_Exception + */ + public function uidForSearch($criteria, + $restrict = Horde_Kolab_Server::RESULT_SINGLE) + { + /* In the default class we just return false */ + return false; + } + + /** + * Identify the GID for the first group found using the specified + * search criteria + * + * @param array $criteria The search parameters as array. + * @param int $restrict A Horde_Kolab_Server::RESULT_* result restriction. + * + * @return boolean|string|array The GID(s) or false if there was no result. + * + * @throws Horde_Kolab_Server_Exception + */ + public function gidForSearch($criteria, + $restrict = Horde_Kolab_Server::RESULT_SINGLE) + { + /* In the default class we just return false */ + return false; + } + + /** + * Identify attributes for the objects found using a filter. + * + * @param array $criteria The search parameters as array. + * @param array $attrs The attributes to retrieve. + * @param int $restrict A Horde_Kolab_Server::RESULT_* result restriction. + * + * @return array The results. + * + * @throws Horde_Kolab_Server_Exception + */ + public function attrsForSearch($criteria, $attrs, + $restrict = Horde_Kolab_Server::RESULT_SINGLE) + { + /* In the default class we just return an empty array */ + return array(); + } + + /** + * Find object data matching a given set of criteria. + * + * @param array $criteria The criteria for the search. + * @param string $params Additional search parameters. + * + * @return array The result array. + * + * @throws Horde_Kolab_Server_Exception + */ + public function find($criteria, $params = array()) + { + /* In the default class we just return an empty array */ + return array(); + } + + /** + * Returns the set of objects supported by this server. + * + * @return array An array of supported objects. + */ + public function getSupportedObjects() + { + return array('Horde_Kolab_Server_Object'); + } +} diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/Server/TestTest.php b/framework/Kolab_Server/test/Horde/Kolab/Server/Server/TestTest.php new file mode 100644 index 000000000..312352671 --- /dev/null +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/Server/TestTest.php @@ -0,0 +1,626 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Prepare the test setup. + */ +require_once dirname(__FILE__) . '/../Autoload.php'; + +/** + * Test the test backend. + * + * Copyright 2008-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Server_TestTest extends Horde_Kolab_Server_Scenario +{ + + /** The file based mock environment */ + const ENVIRONMENT_FILE = 'file'; + + /** + * The environments we provide to the test. + * + * @var array + */ + protected $_environments = array( + self::ENVIRONMENT_MOCK, + self::ENVIRONMENT_FILE + ); + + /** + * Prepare the server configuration for the given environment. + * + * @param string $environment The name of the environment. + * + * @return NULL + */ + public function prepareKolabServerConfiguration($environment) + { + switch ($environment) { + case self::ENVIRONMENT_FILE: + /** Prepare a Kolab test server */ + $config = new stdClass; + $config->driver = 'file'; + $config->params = array( + 'file' => Horde::getTempFile('fileTest'), + 'basedn' => 'dc=example,dc=org', + 'hashtype' => 'plain' + ); + $this->world['injector'][$environment]->setInstance('Horde_Kolab_Server_Config', $config); + break; + default: + return parent::prepareKolabServerConfiguration($environment); + } + } + + /** + * Set up testing. + * + * @return NULL + */ + protected function setUp() + { + parent::setUp(); + + $this->initializeEnvironments(); + $this->servers = $this->getKolabServers(); + foreach ($this->servers as $server) { + $this->addBasicUsersToServer($server); + } + } + + /** + * Test search base. + * + * @return NULL + */ + public function testSearchBase() + { + foreach ($this->servers as $server) { + $result = $server->search( + '(' . Horde_Kolab_Server_Object::ATTRIBUTE_OC + . '=' . Horde_Kolab_Server_Object::OBJECTCLASS_TOP . ')', + array(Horde_Kolab_Server_Object::ATTRIBUTE_OC)); + $this->assertEquals(13, count($result)); + + $result = $server->search( + '(' . Horde_Kolab_Server_Object::ATTRIBUTE_OC + . '=' . Horde_Kolab_Server_Object::OBJECTCLASS_TOP . ')', + array(Horde_Kolab_Server_Object::ATTRIBUTE_OC), + 'cn=internal,dc=example,dc=org'); + $this->assertEquals(4, count($result)); + } + } + + /** + * Test sorting. + * + * @return NULL + */ + public function testSorting() + { + foreach ($this->servers as $server) { + +/* $result = $server->search('(mail=*)', array('mail')); */ +/* $this->assertEquals(5, count($result)); */ +/* $server->sort($result, 'mail'); */ +/* foreach ($result as $object) { */ +/* if (isset($object['data']['dn'])) { */ +/* switch ($object['data']['dn']) { */ +/* case 'cn=Test Address,cn=external,dc=example,dc=org': */ +/* $this->assertContains('address@example.org', $object['data']['mail']); */ +/* break; */ +/* case '': */ +/* $this->assertContains('address@example.org', $object['data']['mail']); */ +/* break; */ +/* } */ +/* } */ +/* } */ + } + } + + /** + * Test listing objects. + * + * @return NULL + */ + public function testListObjects() + { + foreach ($this->servers as $server) { + $filter = '(&(objectClass=kolabInetOrgPerson)(uid=*)(mail=*)(sn=*))'; + $attributes = array( + Horde_Kolab_Server_Object_Kolabinetorgperson::ATTRIBUTE_SN, + Horde_Kolab_Server_Object_Kolabinetorgperson::ATTRIBUTE_CN, + Horde_Kolab_Server_Object_Kolabinetorgperson::ATTRIBUTE_UID, + Horde_Kolab_Server_Object_Kolabinetorgperson::ATTRIBUTE_MAIL, + Horde_Kolab_Server_Object_Kolabinetorgperson::ATTRIBUTE_DELETED, + ); + + $sort = Horde_Kolab_Server_Object_Kolabinetorgperson::ATTRIBUTE_SN; + $result = $server->search($filter); + $this->assertEquals(2, count($result)); + + $result = $server->listObjects('Horde_Kolab_Server_Object_Kolab_User'); + $this->assertEquals('Horde_Kolab_Server_Object_Kolab_User', get_class(array_shift($result))); + + $result = $server->listObjects('Horde_Kolab_Server_Object_Kolabsharedfolder'); + $this->assertEquals(1, count($result)); + $this->assertEquals('Horde_Kolab_Server_Object_Kolabsharedfolder', get_class(array_shift($result))); + } + } + + /** + * Test handling of object classes. + * + * @return NULL + */ + public function testGetObjectClasses() + { + foreach ($this->servers as $server) { + $classes = $server->getObjectClasses('cn=Gunnar Wrobel,dc=example,dc=org'); + $this->assertContains('top', $classes); + $this->assertContains('kolabinetorgperson', $classes); + + try { + $classes = $server->getObjectClasses('cn=DOES NOT EXIST,dc=example,dc=org'); + } catch (Horde_Kolab_Server_Exception $classes) { + } + $this->assertError($classes, + 'No such object: cn=DOES NOT EXIST,dc=example,dc=org'); + + $classes = $server->getObjectClasses('cn=The Administrator,dc=example,dc=org'); + $this->assertContains('kolabinetorgperson', $classes); + } + } + + /** + * Test handling of object types. + * + * @return NULL + */ + public function testDetermineType() + { + foreach ($this->servers as $server) { + $type = $server->determineType('cn=empty.group@example.org,dc=example,dc=org'); + $this->assertEquals('Horde_Kolab_Server_Object_Kolabgroupofnames', $type); + + $type = $server->determineType('cn=shared@example.org,dc=example,dc=org'); + $this->assertEquals('Horde_Kolab_Server_Object_Kolabsharedfolder', $type); + + $type = $server->determineType('cn=The Administrator,dc=example,dc=org'); + $this->assertEquals('Horde_Kolab_Server_Object_Kolab_Administrator', $type); + + $type = $server->determineType('cn=Main Tainer,dc=example,dc=org'); + $this->assertEquals('Horde_Kolab_Server_Object_Kolab_Maintainer', $type); + + $type = $server->determineType('cn=Domain Maintainer,dc=example,dc=org'); + $this->assertEquals('Horde_Kolab_Server_Object_Kolab_Domainmaintainer', $type); + + $type = $server->determineType('cn=Test Address,cn=external,dc=example,dc=org'); + $this->assertEquals('Horde_Kolab_Server_Object_Kolab_Address', $type); + + $type = $server->determineType('cn=Gunnar Wrobel,dc=example,dc=org'); + $this->assertEquals('Horde_Kolab_Server_Object_Kolab_User', $type); + } + } + + /** + * Test retrieving a primary mail for a mail or id. + * + * @return NULL + */ + public function testMailForIdOrMail() + { + foreach ($this->servers as $server) { + $mail = $server->mailForIdOrMail('wrobel'); + $this->assertEquals('wrobel@example.org', $mail); + + $mail = $server->mailForIdOrMail('wrobel@example.org'); + $this->assertEquals('wrobel@example.org', $mail); + + $mail = $server->mailForIdOrMail('DOES NOT EXIST'); + $this->assertSame(false, $mail); + } + } + + /** + * Test retrieving a UID for a mail or id. + * + * @return NULL + */ + public function testUidForIdOrMail() + { + foreach ($this->servers as $server) { + $uid = $server->uidForIdOrMail('wrobel'); + $this->assertEquals('cn=Gunnar Wrobel,dc=example,dc=org', $uid); + + $uid = $server->uidForIdOrMail('wrobel@example.org'); + $this->assertEquals('cn=Gunnar Wrobel,dc=example,dc=org', $uid); + + $uid = $server->uidForIdOrMail('DOES NOT EXIST'); + $this->assertSame(false, $uid); + } + } + + /** + * Test retrieving a UID for a mail or id. + * + * @return NULL + */ + public function testUidForMailOrIdOrAlias() + { + foreach ($this->servers as $server) { + $uid = $server->uidForIdOrMailOrAlias('g.wrobel@example.org'); + $this->assertEquals('cn=Gunnar Wrobel,dc=example,dc=org', $uid); + + $uid = $server->uidForIdOrMailOrAlias('wrobel@example.org'); + $this->assertEquals('cn=Gunnar Wrobel,dc=example,dc=org', $uid); + + $uid = $server->uidForIdOrMailOrAlias('wrobel'); + $this->assertEquals('cn=Gunnar Wrobel,dc=example,dc=org', $uid); + + $uid = $server->uidForIdOrMailOrAlias('DOES NOT EXIST'); + $this->assertSame(false, $uid); + } + } + + /** + * Test retrieving all addresses for a mail or id. + * + * @return NULL + */ + public function testAddrsForIdOrMail() + { + foreach ($this->servers as $server) { + $addrs = $server->addrsForIdOrMail('wrobel'); + + $testuser = $server->fetch('cn=Test Test,dc=example,dc=org'); + $this->assertContains('wrobel@example.org', + $testuser->get(Horde_Kolab_Server_Object_Kolabinetorgperson::ATTRIBUTE_DELEGATE, false)); + + $this->assertContains('wrobel@example.org', $addrs); + $this->assertContains('test@example.org', $addrs); + $this->assertContains('t.test@example.org', $addrs); + $this->assertContains('g.wrobel@example.org', $addrs); + $this->assertContains('gunnar@example.org', $addrs); + + $addrs = $server->addrsForIdOrMail('test@example.org'); + $this->assertContains('test@example.org', $addrs); + $this->assertContains('t.test@example.org', $addrs); + } + } + + /** + * Test retrieving a UID for a primary mail. + * + * @return NULL + */ + public function testUidForMailAddress() + { + foreach ($this->servers as $server) { + $uid = $server->uidForIdOrMailOrAlias('wrobel@example.org'); + $this->assertEquals('cn=Gunnar Wrobel,dc=example,dc=org', $uid); + + $uid = $server->uidForIdOrMailOrAlias('test@example.org'); + $this->assertEquals('cn=Test Test,dc=example,dc=org', $uid); + + $uid = $server->uidForIdOrMailOrAlias('gunnar@example.org'); + $this->assertEquals('cn=Gunnar Wrobel,dc=example,dc=org', $uid); + + $uid = $server->uidForIdOrMailOrAlias('wrobel'); + $this->assertEquals('cn=Gunnar Wrobel,dc=example,dc=org', $uid); + } + } + + /** + * Test retrieving a UID for an attribute. + * + * @return NULL + */ + public function testUidForAttr() + { + foreach ($this->servers as $server) { + $uid = $server->uidForSearch(array('AND' => array(array('field' => 'alias', + 'op' => '=', + 'test' => 'g.wrobel@example.org')))); + $this->assertEquals('cn=Gunnar Wrobel,dc=example,dc=org', $uid); + } + } + + /** + * Test group membership testing. + * + * @return NULL + */ + public function testMemberOfGroupAddress() + { + foreach ($this->servers as $server) { + $uid = $server->uidForIdOrMailOrAlias('g.wrobel@example.org'); + $member = $server->memberOfGroupAddress($uid, 'group@example.org'); + $this->assertTrue($member); + + $member = $server->memberOfGroupAddress( + $server->uidForIdOrMailOrAlias('test@example.org'), + 'group@example.org'); + $this->assertTrue($member); + + $member = $server->memberOfGroupAddress( + $server->uidForIdOrMailOrAlias('somebody@example.org'), + 'group@example.org'); + $this->assertFalse($member); + } + } + + /** + * Test group fetching. + * + * @return NULL + */ + public function testGetGroups() + { + foreach ($this->servers as $server) { + $filter = '(&(objectClass=kolabGroupOfNames)(member=' + . Net_LDAP2_Util::escape_filter_value('cn=The Administrator,dc=example,dc=org') . '))'; + $result = $server->search($filter, array()); + $this->assertTrue(!empty($result)); + + /* $entry = $server->_firstEntry($result); */ + /* $this->assertTrue(!empty($entry)); */ + + /* $uid = $server->_getDn($entry); */ + /* $this->assertTrue(!empty($uid)); */ + + /* $entry = $server->_nextEntry($entry); */ + /* $this->assertTrue(empty($entry)); */ + + /* $entries = $server->_getDns($result); */ + /* $this->assertTrue(!empty($entries)); */ + + $groups = $server->getGroups('cn=The Administrator,dc=example,dc=org'); + $this->assertTrue(!empty($groups)); + + $groups = $server->getGroups($server->uidForIdOrMailOrAlias('g.wrobel@example.org')); + $this->assertContains('cn=group@example.org,dc=example,dc=org', $groups); + + $groups = $server->getGroupAddresses($server->uidForIdOrMailOrAlias('g.wrobel@example.org')); + $this->assertContains('group@example.org', $groups); + + $groups = $server->getGroups($server->uidForIdOrMailOrAlias('test@example.org')); + $this->assertContains('cn=group@example.org,dc=example,dc=org', $groups); + + $groups = $server->getGroupAddresses($server->uidForIdOrMailOrAlias('test@example.org')); + $this->assertContains('group@example.org', $groups); + + $groups = $server->getGroups('nobody'); + $this->assertTrue(empty($groups)); + } + } + + /** + * Test parsing of LDAP filters. + * + * @return NULL + */ + public function testFilterParse() + { + $db = $this->getKolabMockServer(); + + $a = $db->parse('(a=b)'); + $this->assertEquals(array('att' => 'a', 'log' => '=', 'val' => 'b'), + $a); + + $a = $db->parse('(&(a=b)(c=d))'); + $this->assertEquals(array('op' => '&', 'sub' => array( + array('att' => 'a', 'log' => '=', 'val' => 'b'), + array('att' => 'c', 'log' => '=', 'val' => 'd'), + )), $a); + + $a = $db->parse('(&(a=1)(|(b=2)(c=3)))'); + $this->assertEquals(array('op' => '&', 'sub' => array( + array('att' => 'a', 'log' => '=', 'val' => '1'), + array('op' => '|', 'sub' => + array( + array('att' => 'b', 'log' => '=', 'val' => '2'), + array('att' => 'c', 'log' => '=', 'val' => '3'), + )))), $a); + + $a = $db->parseSub('(!(x=2))(b=1)'); + $this->assertEquals(array(array('op' => '!', 'sub' => + array( + array('att' => 'x', 'log' => '=', 'val' => '2'), + ) + ), + array('att' => 'b', 'log' => '=', 'val' => '1'), + ), $a); + + $a = $db->parse('(&(!(x=2))(b=1))'); + $this->assertEquals(array('op' => '&', 'sub' => array( + array('op' => '!', 'sub' => + array( + array('att' => 'x', 'log' => '=', 'val' => '2'), + ) + ), + array('att' => 'b', 'log' => '=', 'val' => '1'), + )), $a); + + } + + /** + * Test searching in the simulated LDAP data. + * + * @return NULL + */ + public function testSearch() + { + $injector = new Horde_Injector(new Horde_Injector_TopLevel()); + $config = new stdClass; + $config->driver = 'test'; + $config->params = array( + 'data' => + array( + 'cn=a' => array( + 'dn' => 'cn=a', + 'data' => array( + 'a' => '1', + 'b' => '1', + 'c' => '1', + ) + ), + 'cn=b' => array( + 'dn' => 'cn=b', + 'data' => array( + 'a' => '1', + 'b' => '2', + 'c' => '2', + ) + ), + 'cn=c' => array( + 'dn' => 'cn=c', + 'data' => array( + 'a' => '1', + 'b' => '2', + 'c' => '3', + ) + ), + 'cn=d' => array( + 'dn' => 'cn=d', + 'data' => array( + 'a' => '2', + 'b' => '2', + 'c' => '1', + ) + ), + ) + ); + $injector->setInstance('Horde_Kolab_Server_Config', $config); + $injector->bindFactory('Horde_Kolab_Server_Structure', + 'Horde_Kolab_Server_Factory', + 'getStructure'); + $injector->bindFactory('Horde_Kolab_Server', + 'Horde_Kolab_Server_Factory', + 'getServer'); + $db = $injector->getInstance('Horde_Kolab_Server'); + + $a = $db->search('(c=1)'); + $this->assertEquals( + array( + 'cn=a' => array( + 'a' => '1', + 'b' => '1', + 'c' => '1', + 'dn' => 'cn=a', + ), + 'cn=d' => array( + 'a' => '2', + 'b' => '2', + 'c' => '1', + 'dn' => 'cn=d', + ), + ), + $a + ); + + $a = $db->search('(c=3)'); + $this->assertEquals( + array( + 'cn=c' => array( + 'a' => '1', + 'b' => '2', + 'c' => '3', + 'dn' => 'cn=c', + ), + ), + $a + ); + + $a = $db->search('(c=3)', array('attributes' => array('a'))); + $this->assertEquals( + array( + 'cn=c' => array( + 'a' => '1', + 'dn' => 'cn=c', + ), + ), + $a + ); + + $a = $db->search('(&(a=1)(b=2))', array('attributes' => array('a', 'b'))); + $this->assertEquals( + array( + 'cn=b' => array( + 'a' => '1', + 'b' => '2', + 'dn' => 'cn=b', + ), + 'cn=c' => array( + 'a' => '1', + 'b' => '2', + 'dn' => 'cn=c', + ), + ), + $a + ); + + $a = $db->search('(&(b=2))', array('attributes' => array('b'))); + $this->assertEquals( + array( + 'cn=b' => array( + 'b' => '2', + 'dn' => 'cn=b', + ), + 'cn=c' => array( + 'b' => '2', + 'dn' => 'cn=c', + ), + 'cn=d' => array( + 'b' => '2', + 'dn' => 'cn=d', + ), + ), + $a + ); + + $a = $db->search('(!(b=2))', array('attributes' => array('a', 'b'))); + $this->assertEquals( + array( + 'cn=a' => array( + 'a' => '1', + 'b' => '1', + 'dn' => 'cn=a', + ), + ), + $a + ); + + $a = $db->search('(&(!(x=2))(b=1))', array('attributes' => array('b'))); + $this->assertEquals( + array( + 'cn=a' => array( + 'b' => '1', + 'dn' => 'cn=a', + ), + ), + $a + ); + } + +} diff --git a/framework/Kolab_Server/test/Horde/Kolab/Server/UserTest.php b/framework/Kolab_Server/test/Horde/Kolab/Server/UserTest.php index d23c7fd18..cd0e74739 100644 --- a/framework/Kolab_Server/test/Horde/Kolab/Server/UserTest.php +++ b/framework/Kolab_Server/test/Horde/Kolab/Server/UserTest.php @@ -40,6 +40,8 @@ class Horde_Kolab_Server_UserTest extends Horde_Kolab_Server_Scenario */ protected function setUp() { + parent::setUp(); + $this->server = $this->getKolabMockServer(); $users = $this->validUsers(); foreach ($users as $user) { -- 2.11.0