Added Countable and SeekableIterator to DatabaseObjectList
authorAlexander Ebert <ebert@woltlab.com>
Fri, 30 Sep 2011 17:35:31 +0000 (19:35 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Fri, 30 Sep 2011 17:35:31 +0000 (19:35 +0200)
DatabaseObjectList uses an enhanced implementation for Iterators, which is slightly different (see key() implementation) to fit our purposes. Additionally two new methods seekTo() and search() are implemented to provide easier object access.

Thanks to @TimWolla for the suggestion of using SPL interfaces. Closes #206

wcfsetup/install/files/lib/data/DatabaseObjectList.class.php
wcfsetup/install/files/lib/data/ITraversableObject.class.php [new file with mode: 0644]

index 11133a6736bd5eb49b0e71a5f5fe413cd8359bb0..7b50f16cde7e32a3f393612c5a4139e2216da710 100644 (file)
@@ -13,7 +13,7 @@ use wcf\system\WCF;
  * @subpackage data
  * @category   Community Framework
  */
-abstract class DatabaseObjectList {
+abstract class DatabaseObjectList implements \Countable, ITraversableObject {
        /**
         * object class name
         * @var string
@@ -74,6 +74,18 @@ abstract class DatabaseObjectList {
         */
        protected $conditionBuilder = null;
        
+       /**
+        * current iterator index
+        * @var integer
+        */
+       protected $index = 0;
+       
+       /**
+        * list of index to object relation
+        * @var array<integer>
+        */
+       protected $indexToObject = null;
+       
        /**
         * Creates a new DatabaseObjectList object.
         */
@@ -148,7 +160,10 @@ abstract class DatabaseObjectList {
                // use table index as array index
                $objects = array();
                foreach($this->objects as $object) {
-                       $objects[$object->{$this->getDatabaseTableIndexName()}] = $object;
+                       $objectID = $object->{$this->getDatabaseTableIndexName()};
+                       $objects[$objectID] = $object;
+                       
+                       $this->indexToObject[] = $objectID;
                }
                $this->objects = $objects;
        }
@@ -206,4 +221,85 @@ abstract class DatabaseObjectList {
        public function getDatabaseTableAlias() {
                return call_user_func(array($this->className, 'getDatabaseTableAlias'));
        }
+       
+       /**
+        * @see \Countable::count()
+        */
+       public function count() {
+               return count($this->objects);
+       }
+       
+       /**
+        * @see \Iterator::current()
+        */
+       public function current() {
+               $objectID = $this->indexToObject[$this->index];
+               return $this->objects[$objectID];
+       }
+       
+       /**
+        * CAUTION: This methods does not return the current iterator index,
+        * rather than the object key which maps to that index.
+        * 
+        * @see \Iterator::key()
+        */
+       public function key() {
+               return $this->indexToObject[$this->index];
+       }
+       
+       /**
+        * @see \Iterator::next()
+        */
+       public function next() {
+               ++$this->index;
+       }
+       
+       /**
+        * @see \Iterator::rewind()
+        */
+       public function rewind() {
+               $this->index = 0;
+       }
+       
+       /**
+        * @see \Iterator::valid()
+        */
+       public function valid() {
+               return isset($this->indexToObject[$this->index]);
+       }
+       
+       /**
+        * @see \SeekableIterator::seek()
+        */
+       public function seek($index) {
+               $this->index = $index;
+               
+               if (!$this->valid()) {
+                       throw new \OutOfBoundsException();
+               }
+       }
+       
+       /**
+        * @see wcf\data\ITraversableObject::seekTo()
+        */
+       public function seekTo($objectID) {
+               $this->index = array_search($objectID, $this->indexToObject);
+               
+               if ($this->index === false) {
+                       throw new SystemException("object id '".$objectID."' is invalid");
+               }
+       }
+       
+       /**
+        * @see wcf\data\ItraversableObject::search()
+        */
+       public function search($objectID) {
+               try {
+                       $this->seekTo($objectID);
+                       return $this->current();
+               }
+               catch (SystemException $e) {
+                       return null;
+               }
+       }
 }
diff --git a/wcfsetup/install/files/lib/data/ITraversableObject.class.php b/wcfsetup/install/files/lib/data/ITraversableObject.class.php
new file mode 100644 (file)
index 0000000..2c905ac
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+namespace wcf\data;
+
+/**
+ * Interface for enhanced iteration support.
+ *
+ * @author     Alexander Ebert
+ * @copyright  2001-2011 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage data
+ * @category   Community Framework
+ */
+interface ITraversableObject extends \SeekableIterator {
+       /**
+        * Sets internal iterator pointer based upon related object id.
+        * 
+        * @param       integer         $objectID
+        */
+       public function seekTo($objectID);
+       
+       /**
+        * Searches a specific object by object id and setting internal
+        * iterator pointer to found item. Returns null if object id is
+        * not found.
+        * 
+        * @param       integer         $objectID
+        * @return      wcf\data\DatabaseObject
+        */
+       public function search($objectID);
+}