From 837e74da4a3e883165af67e03194d6ebc7ec935b Mon Sep 17 00:00:00 2001 From: guilhermeblanco Date: Mon, 10 Aug 2009 21:36:57 +0000 Subject: [PATCH] [2.0] Added more missing docblocks. Implemented a double-inclusion listener prevention in EventManager --- lib/Doctrine/Common/ClassLoader.php | 41 ++++++--- .../Common/Collections/ArrayCollection.php | 36 ++++++-- .../Common/Collections/Collection.php | 32 ++++++- lib/Doctrine/Common/DoctrineException.php | 91 ++++++++++++++++--- lib/Doctrine/Common/EventArgs.php | 19 ++-- lib/Doctrine/Common/EventManager.php | 45 +++++---- lib/Doctrine/Common/EventSubscriber.php | 17 +++- lib/Doctrine/Common/Lexer.php | 37 ++++---- lib/Doctrine/Common/NotifyPropertyChanged.php | 9 +- .../Common/PropertyChangedListener.php | 13 ++- lib/Doctrine/Common/Util/Debug.php | 22 ++++- 11 files changed, 273 insertions(+), 89 deletions(-) diff --git a/lib/Doctrine/Common/ClassLoader.php b/lib/Doctrine/Common/ClassLoader.php index 48c02e7a5..5db195976 100644 --- a/lib/Doctrine/Common/ClassLoader.php +++ b/lib/Doctrine/Common/ClassLoader.php @@ -46,14 +46,29 @@ namespace Doctrine\Common; */ class ClassLoader { - private - $_namespaceSeparator = '\\', - $_fileExtension = '.php', - $_checkFileExists = false, - $_basePaths = array(); + /** + * @var string Namespace separator + */ + private $_namespaceSeparator = '\\'; + + /** + * @var string File extension used for classes + */ + private $_fileExtension = '.php'; + + /** + * @var boolean Flag to inspect if file exists in codebase before include it + */ + private $_checkFileExists = false; + + /** + * @var array Hashmap of base paths that Autoloader will look into + */ + private $_basePaths = array(); /** * Constructor registers the autoloader automatically + * */ public function __construct() { @@ -118,19 +133,17 @@ class ClassLoader } $prefix = substr($className, 0, strpos($className, $this->_namespaceSeparator)); - $class = ''; - - if (isset($this->_basePaths[$prefix])) { - $class .= $this->_basePaths[$prefix] . DIRECTORY_SEPARATOR; - } - - $class .= str_replace($this->_namespaceSeparator, DIRECTORY_SEPARATOR, $className) - . $this->_fileExtension; + + // If we have a custom path for namespace, use it + $class = ((isset($this->_basePaths[$prefix])) ? $this->_basePaths[$prefix] . DIRECTORY_SEPARATOR : '') + . str_replace($this->_namespaceSeparator, DIRECTORY_SEPARATOR, $className) . $this->_fileExtension; + // Assure file exists in codebase before require if flag is active if ($this->_checkFileExists) { - if (!$fh = @fopen($class, 'r', true)) { + if (($fh = @fopen($class, 'r', true)) === false) { return false; } + @fclose($fh); } diff --git a/lib/Doctrine/Common/Collections/ArrayCollection.php b/lib/Doctrine/Common/Collections/ArrayCollection.php index abf3fbc65..58ebab175 100644 --- a/lib/Doctrine/Common/Collections/ArrayCollection.php +++ b/lib/Doctrine/Common/Collections/ArrayCollection.php @@ -27,8 +27,13 @@ use \Closure, \ArrayIterator; * An ArrayCollection is a Collection implementation that uses a regular PHP array * internally. * - * @author Roman S. Borschel - * @since 2.0 + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision: 3938 $ + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel */ class ArrayCollection implements Collection { @@ -94,6 +99,8 @@ class ArrayCollection implements Collection /** * Moves the internal iterator position to the next element. + * + * @return mixed */ public function next() { @@ -102,6 +109,8 @@ class ArrayCollection implements Collection /** * Gets the element of the collection at the current internal iterator position. + * + * @return mixed */ public function current() { @@ -119,8 +128,10 @@ class ArrayCollection implements Collection if (isset($this->_elements[$key])) { $removed = $this->_elements[$key]; unset($this->_elements[$key]); + return $removed; } + return null; } @@ -133,17 +144,20 @@ class ArrayCollection implements Collection public function removeElement($element) { $key = array_search($element, $this->_elements, true); + if ($key !== false) { $removed = $this->_elements[$key]; unset($this->_elements[$key]); + return $removed; } + return null; } - /* ArrayAccess implementation */ - /** + * ArrayAccess implementation of offsetExists() + * * @see containsKey() */ public function offsetExists($offset) @@ -152,6 +166,8 @@ class ArrayCollection implements Collection } /** + * ArrayAccess implementation of offsetGet() + * * @see get() */ public function offsetGet($offset) @@ -160,6 +176,8 @@ class ArrayCollection implements Collection } /** + * ArrayAccess implementation of offsetGet() + * * @see add() * @see set() */ @@ -172,6 +190,8 @@ class ArrayCollection implements Collection } /** + * ArrayAccess implementation of offsetUnset() + * * @see remove() */ public function offsetUnset($offset) @@ -179,8 +199,6 @@ class ArrayCollection implements Collection return $this->remove($offset); } - /* END ArrayAccess implementation */ - /** * Checks whether the collection contains a specific key/index. * @@ -273,7 +291,7 @@ class ArrayCollection implements Collection * * Implementation of the Countable interface. * - * @return integer The number of elements in the collection. + * @return integer The number of elements in the collection. */ public function count() { @@ -333,6 +351,7 @@ class ArrayCollection implements Collection * a new collection with the elements returned by the function. * * @param Closure $func + * @return Collection */ public function map(Closure $func) { @@ -365,6 +384,7 @@ class ArrayCollection implements Collection return false; } } + return true; } @@ -392,6 +412,7 @@ class ArrayCollection implements Collection /** * Returns a string representation of this object. + * */ public function __toString() { @@ -400,6 +421,7 @@ class ArrayCollection implements Collection /** * Clears the collection. + * */ public function clear() { diff --git a/lib/Doctrine/Common/Collections/Collection.php b/lib/Doctrine/Common/Collections/Collection.php index b2e42c0b7..44218fc8a 100644 --- a/lib/Doctrine/Common/Collections/Collection.php +++ b/lib/Doctrine/Common/Collections/Collection.php @@ -1,4 +1,23 @@ . + */ namespace Doctrine\Common\Collections; @@ -20,8 +39,13 @@ namespace Doctrine\Common\Collections; * position unless you explicitly positioned it before. Prefer iteration with * external iterators. * - * @author Roman Borschel - * @since 2.0 + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision: 3938 $ + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel */ interface Collection extends \Countable, \IteratorAggregate, \ArrayAccess { @@ -35,6 +59,7 @@ interface Collection extends \Countable, \IteratorAggregate, \ArrayAccess /** * Clears the collection. + * */ function clear(); @@ -136,16 +161,19 @@ interface Collection extends \Countable, \IteratorAggregate, \ArrayAccess /** * Gets the key/index of the element at the current iterator position. + * */ function key(); /** * Gets the element of the collection at the current iterator position. + * */ function current(); /** * Moves the internal iterator position to the next element. + * */ function next(); } \ No newline at end of file diff --git a/lib/Doctrine/Common/DoctrineException.php b/lib/Doctrine/Common/DoctrineException.php index b8ca3bac6..ccb4697b2 100644 --- a/lib/Doctrine/Common/DoctrineException.php +++ b/lib/Doctrine/Common/DoctrineException.php @@ -1,48 +1,115 @@ . + */ + namespace Doctrine\Common; +/** + * Base Exception class of Doctrine + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision: 3938 $ + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ class DoctrineException extends \Exception { + /** + * @var array Lazy initialized array of error messages + * @static + */ private static $_messages = array(); + /** + * Initializes a new DoctrineException. + * + * @param string $message + * @param Exception $cause Optional Exception + */ public function __construct($message = "", \Exception $cause = null) { - parent::__construct($message, 0, $cause); + $code = ($cause instanceof Exception) ? $cause->getCode() : 0; + + parent::__construct($message, $code, $cause); } + /** + * Throws a DoctrineException reporting not implemented method in a given class + * + * @static + * @param string $method Method name + * @param string $class Class name + * @throws DoctrineException + */ public static function notImplemented($method, $class) { return new self("The method '$method' is not implemented in class '$class'."); } - public static function __callStatic($method, $arguments) + /** + * Implementation of __callStatic magic method. + * + * Received a method name and arguments. It lookups a $_messages HashMap + * for matching Class#Method key and executes the returned string value + * translating the placeholders with arguments passed. + * + * @static + * @param string $method Method name + * @param array $arguments Optional arguments to be translated in placeholders + * @throws DoctrineException + */ + public static function __callStatic($method, $arguments = array()) { $class = get_called_class(); $messageKey = substr($class, strrpos($class, '\\') + 1) . "#$method"; $end = end($arguments); $innerException = null; + if ($end instanceof \Exception) { $innerException = $end; unset($arguments[count($arguments) - 1]); } - if ($message = self::getExceptionMessage($messageKey)) { + if (($message = self::getExceptionMessage($messageKey)) !== false) { $message = sprintf($message, $arguments); } else { - $message = strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', $method)); - $message = ucfirst(str_replace('_', ' ', $message)); - $args = array(); - foreach ($arguments as $argument) { - $args[] = var_export($argument, true); - } - $message .= ' (' . implode(', ', $args) . ')'; + $dumper = function ($value) { return var_export($value, true); }; + $message = strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', $method)); + $message = ucfirst(str_replace('_', ' ', $message)) + . ' (' . implode(', ', array_map($dumper, $arguments)) . ')'; } return new $class($message, $innerException); } + /** + * Retrieves error string given a message key for lookup + * + * @static + * @param string $messageKey + * @return string|false Returns the error string if found; FALSE otherwise + */ public static function getExceptionMessage($messageKey) { if ( ! self::$_messages) { @@ -56,9 +123,11 @@ class DoctrineException extends \Exception "The query contains more than one result." ); } + if (isset(self::$_messages[$messageKey])) { return self::$_messages[$messageKey]; } + return false; } } \ No newline at end of file diff --git a/lib/Doctrine/Common/EventArgs.php b/lib/Doctrine/Common/EventArgs.php index 505f4b1dd..122892a87 100644 --- a/lib/Doctrine/Common/EventArgs.php +++ b/lib/Doctrine/Common/EventArgs.php @@ -28,20 +28,26 @@ namespace Doctrine\Common; * information to an event handler when an event is raised. The single empty EventArgs * instance can be obtained through {@link getEmptyInstance()}. * - * @author Konsta Vesterinen - * @author Roman Borschel - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link www.doctrine-project.org - * @since 2.0 - * @version $Revision$ + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision: 3938 $ + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel */ class EventArgs { + /** + * @var EventArgs Single instance of EventArgs + * @static + */ private static $_emptyEventArgsInstance; /** * Gets the single, empty EventArgs instance. * + * @static * @return EventArgs */ public static function getEmptyInstance() @@ -49,6 +55,7 @@ class EventArgs if ( ! self::$_emptyEventArgsInstance) { self::$_emptyEventArgsInstance = new EventArgs; } + return self::$_emptyEventArgsInstance; } } diff --git a/lib/Doctrine/Common/EventManager.php b/lib/Doctrine/Common/EventManager.php index 47a5d0fe8..fa98cf2d1 100644 --- a/lib/Doctrine/Common/EventManager.php +++ b/lib/Doctrine/Common/EventManager.php @@ -28,9 +28,13 @@ use Doctrine\Common\Events\Event; * Listeners are registered on the manager and events are dispatched through the * manager. * - * @author Roman Borschel - * @author Guilherme Blanco - * @since 2.0 + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision: 3938 $ + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel */ class EventManager { @@ -45,8 +49,8 @@ class EventManager /** * Dispatches an event to all registered listeners. * - * @param string $eventName The name of the event to dispatch. The name of the event is - * the name of the method that is invoked on listeners. + * @param string $eventName The name of the event to dispatch. The name of the event is + * the name of the method that is invoked on listeners. * @param EventArgs $eventArgs The event arguments to pass to the event handlers/listeners. * If not supplied, the single empty EventArgs instance is used. * @return boolean @@ -55,6 +59,7 @@ class EventManager { if (isset($this->_listeners[$eventName])) { $eventArgs = $eventArgs === null ? EventArgs::getEmptyInstance() : $eventArgs; + foreach ($this->_listeners[$eventName] as $listener) { $listener->$eventName($eventArgs); } @@ -64,8 +69,8 @@ class EventManager /** * Gets the listeners of a specific event or all listeners. * - * @param string $event The name of the event. - * @return The event listeners for the specified event, or all event listeners. + * @param string $event The name of the event. + * @return array The event listeners for the specified event, or all event listeners. */ public function getListeners($event = null) { @@ -86,14 +91,18 @@ class EventManager /** * Adds an event listener that listens on the specified events. * - * @param string|array $events The event(s) to listen on. - * @param object $listener The listener object. + * @param string|array $events The event(s) to listen on. + * @param object $listener The listener object. */ public function addEventListener($events, $listener) { - // TODO: maybe check for duplicate registrations? - foreach ((array)$events as $event) { - $this->_listeners[$event][] = $listener; + // Picks the hash code related to that listener + $hash = spl_object_hash($listener); + + foreach ((array) $events as $event) { + // Overrides listener if a previous one was associated already + // Prevents duplicate listeners on same event (same instance only) + $this->_listeners[$event][$hash] = $listener; } } @@ -105,9 +114,13 @@ class EventManager */ public function removeEventListener($events, $listener) { - foreach ((array)$events as $event) { - if (($key = array_search($listener, $this->_listeners[$event], true)) !== false) { - unset($this->_listeners[$event][$key]); + // Picks the hash code related to that listener + $hash = spl_object_hash($listener); + + foreach ((array) $events as $event) { + // Check if actually have this listener associated + if (isset($this->_listeners[$event][$hash])) { + unset($this->_listeners[$event][$hash]); } } } @@ -116,7 +129,7 @@ class EventManager * Adds an EventSubscriber. The subscriber is asked for all the events he is * interested in and added as a listener for these events. * - * @param Doctrine\Common\EventSubscriber $subscriber The subscriber. + * @param Doctrine\Common\EventSubscriber $subscriber The subscriber. */ public function addEventSubscriber(EventSubscriber $subscriber) { diff --git a/lib/Doctrine/Common/EventSubscriber.php b/lib/Doctrine/Common/EventSubscriber.php index 5bbfdfbc4..d095af094 100644 --- a/lib/Doctrine/Common/EventSubscriber.php +++ b/lib/Doctrine/Common/EventSubscriber.php @@ -27,13 +27,20 @@ namespace Doctrine\Common; * getSubscribedEvents() and registers the subscriber as a listener for all * returned events. * - * @author Roman Borschel - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link www.phpdoctrine.org - * @since 2.0 - * @version $Revision: 4653 $ + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision: 3938 $ + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel */ interface EventSubscriber { + /** + * Returns an array of events that this subscriber listens + * + * @return array + */ public function getSubscribedEvents(); } diff --git a/lib/Doctrine/Common/Lexer.php b/lib/Doctrine/Common/Lexer.php index abf4fc3b0..2c01dac95 100644 --- a/lib/Doctrine/Common/Lexer.php +++ b/lib/Doctrine/Common/Lexer.php @@ -35,19 +35,17 @@ namespace Doctrine\Common; abstract class Lexer { /** - * Array of scanned tokens. - * - * @var array + * @var array Array of scanned tokens */ private $_tokens = array(); /** - * @todo Doc + * @var integer Current lexer position in input string */ private $_position = 0; /** - * @todo Doc + * @var integer Current peek of current lexer position */ private $_peek = 0; @@ -129,15 +127,12 @@ abstract class Lexer */ public function moveNext() { - $this->token = $this->lookahead; $this->_peek = 0; - if (isset($this->_tokens[$this->_position])) { - $this->lookahead = $this->_tokens[$this->_position++]; - return true; - } else { - $this->lookahead = null; - return false; - } + $this->token = $this->lookahead; + $this->lookahead = (isset($this->_tokens[$this->_position])) + ? $this->_tokens[$this->_position++] : null; + + return $this->lookahead !== null; } /** @@ -153,13 +148,15 @@ abstract class Lexer } /** - * @todo Doc + * Checks if given value is identical to the given token + * + * @param mixed $value + * @param integer $token + * @return boolean */ public function isA($value, $token) { - $type = $this->_getType($value); - - return $type === $token; + return $this->_getType($value) === $token; } /** @@ -206,11 +203,9 @@ abstract class Lexer $matches = preg_split($regex, $input, -1, $flags); foreach ($matches as $match) { - $value = $match[0]; - $type = $this->_getType($value); $this->_tokens[] = array( - 'value' => $value, - 'type' => $type, + 'value' => $match[0], + 'type' => $this->_getType($match[0]), 'position' => $match[1] ); } diff --git a/lib/Doctrine/Common/NotifyPropertyChanged.php b/lib/Doctrine/Common/NotifyPropertyChanged.php index 84abfa8ea..93e504aec 100644 --- a/lib/Doctrine/Common/NotifyPropertyChanged.php +++ b/lib/Doctrine/Common/NotifyPropertyChanged.php @@ -25,8 +25,13 @@ namespace Doctrine\Common; * Contract for classes that provide the service of notifying listeners of * changes to their properties. * - * @author Roman Borschel - * @since 2.0 + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision: 3938 $ + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel */ interface NotifyPropertyChanged { diff --git a/lib/Doctrine/Common/PropertyChangedListener.php b/lib/Doctrine/Common/PropertyChangedListener.php index de83ce48a..ec6bed89f 100644 --- a/lib/Doctrine/Common/PropertyChangedListener.php +++ b/lib/Doctrine/Common/PropertyChangedListener.php @@ -25,11 +25,20 @@ namespace Doctrine\Common; * Contract for classes that are potential listeners of a NotifyPropertyChanged * implementor. * - * @author Roman Borschel - * @since 2.0 + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision: 3938 $ + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel */ interface PropertyChangedListener { + /** + * @todo Document this function + * + */ function propertyChanged($sender, $propertyName, $oldValue, $newValue); } diff --git a/lib/Doctrine/Common/Util/Debug.php b/lib/Doctrine/Common/Util/Debug.php index 32ba0cecb..3491f1d3d 100644 --- a/lib/Doctrine/Common/Util/Debug.php +++ b/lib/Doctrine/Common/Util/Debug.php @@ -23,30 +23,46 @@ namespace Doctrine\Common\Util; /** * Static class containing most used debug methods. - * @author Giorgio Sironi - * @since 2.0 + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision: 3938 $ + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Giorgio Sironi */ final class Debug { + /** + * Private constructor (prevents from instantiation) + * + */ private function __construct() {} /** * Prints a dump of the public, protected and private properties of $var. * To print a meaningful dump, whose depth is limited, requires xdebug * php extension. + * + * @static * @link http://xdebug.org/ * @param mixed $var - * @param integer $maxDepth maximum nesting level for object properties + * @param integer $maxDepth Maximum nesting level for object properties */ public static function dump($var, $maxDepth = 2) { ini_set('html_errors', 'On'); ini_set('xdebug.var_display_max_depth', $maxDepth); + ob_start(); var_dump($var); $dump = ob_get_contents(); ob_end_clean(); + echo strip_tags(html_entity_decode($dump)); + ini_set('html_errors', 'Off'); } }