Location: PHPKode > projects > Maintainable PHP Framework > vendor/Mad/Model/Collection.php
<?php
/**
 * @category   Mad
 * @package    Mad_Model
 * @copyright  (c) 2007-2009 Maintainable Software, LLC
 * @license    http://opensource.org/licenses/bsd-license.php BSD
 */

/**
 * When a using a {@link Mad_Model_Base} wrapper around a result set of objects, we return
 * multiple models as a Mad_Model_Collection object which behaves just as if it were an array.
 *
 * The advantage of using this object instead of an actual array is that we don't need
 * to iterate through the entire result set to use only a subset of the results. This
 * allows us to only access the elements of the result set as needed.
 *
 * @category   Mad
 * @package    Mad_Model
 * @copyright  (c) 2007-2009 Maintainable Software, LLC
 * @license    http://opensource.org/licenses/bsd-license.php BSD
 */
class Mad_Model_Collection implements ArrayAccess, Iterator, Countable
{
    /**
     * The {@link Mad_Model_Base} class used to instantiate new objects
     * @var object
     */
    protected $_model;


    /**
     * As we access each row, we cache them in an array for later access.
     * @var array
     */
    protected $_collection  = array();

    /**
     * The position in the iterator over the objects.
     * @var int
     */
    protected $_position = 0;


    /*##########################################################################
    # Construct/Destruct
    ##########################################################################*/

    /**
     * Construct a Mad_Model_Collection from a model instance and the collection of objects which
     * is wither a QueryResult object or array of model objects.
     *
     * @param   object  $model
     * @param   object  $collection
     */
    public function __construct(Mad_Model_Base $model, $collection=null)
    {
        // object types in this collection
        $this->_model = $model;

        // Iterate over query result
        if (!current($collection) instanceof Mad_Model_Base) {
            $this->_initResults($model, $collection);

        // Use existing array
        } else {
            $this->_collection = $collection;
        }
    }

    /**
     * Loop thru and print out classname and primary key of objects
     * @return  string
     */
    public function __toString()
    {
        if (!$first = current($this->_collection)) { return 'Empty Collection'; }

        $str = get_class($first)." Collection\n";
        foreach ($this as $item) {
            $items[] = get_class($item). ': '.$item->id;
        }
        return $str . (isset($items) ? "\n  ".implode("\n  ", $items) : '');
    }


    /*##########################################################################
    # Accessors
    ##########################################################################*/
    
    public function getCollection()
    {
        return $this->_collection;
    }

    /**                
     * Serialize the collection to XML.
     */
    public function toXml($options = array()) 
    {
        if (!isset($options['root'])) {
            $options['root'] = Mad_Support_Inflector::pluralize(get_class($this->_model));
        }

        $conversion = new Mad_Support_ArrayConversion;
        return $conversion->toXml($this, $options);
    }

    /*##########################################################################
    # Countable Interface
    ##########################################################################*/

    /**
     * Count elements in the array. This has to force load all the object into memory
     * to get the count.
     *
     * <code>
     *  <?php
     *  ...
     *  $folders->count()
     *  ...
     *
     *  // This will work with php5.1
     *  count($folders);
     *  ...
     *  ?>
     * </code>
     * @return  int
     */
    public function count()
    {
        return count($this->_collection);
    }


    /*##########################################################################
    # Iterator Interface
    ##########################################################################*/

    /**
     * Get the current object from the collection
     *
     * <code>
     *  <?php
     *  ...
     *  current($folders);
     *  ...
     *  ?>
     * </code>
     * @return  Mad_Model_Base
     */
    public function current()
    {
        return $this->offsetGet($this->_position);
    }

    /**
     * Get the current position in the Collection
     *
     * <code>
     *  <?php
     *  ...
     *  key($folders);
     *  ...
     *  ?>
     * </code>
     *
     * @return  int
     */
    public function key()
    {
        return $this->_position;
    }

    /**
     * Get the next element on the Collection
     *
     * <code>
     *  <?php
     *  ...
     *  next($folders);
     *  ...
     *  ?>
     * </code>
     *
     * @return  Mad_Model_Base
     */
    public function next()
    {
        $this->_position++;
        return $this->current();
    }

    /**
     * Rewind collection to first element
     *
     * <code>
     *  <?php
     *  ...
     *  rewind($folders);
     *  ...
     *  ?>
     * </code>
     *
     */
    public function rewind()
    {
        $this->_position = 0;
        return $this->current();
    }

    /**
     * Check if the current element exists
     * @return  boolean
     */
    public function valid()
    {
        return $this->offsetExists($this->_position);
    }


    /*##########################################################################
    # ArrayAccess Interface
    ##########################################################################*/

    /**
     * Check if the given offset exists
     * 
     * @param   int     $offset
     * @return  boolean
     */
    public function offsetExists($offset)
    {
        return isset($this->_collection[$offset]);
    }

    /**
     * Return the element for the given offset.
     *
     * <code>
     *  <?php
     *  ...
     *  $folder2 = $folders[1];
     *  ...
     *  ?>
     * </code>
     *
     * @param   int     $offset
     * @return  Mad_Model_Base
     */
    public function offsetGet($offset)
    {
        if ($this->offsetExists($offset)) {
            return $this->_collection[$offset];
        }
    }

    /**
     * Collection is readonly, so this is not allowed (method required by interface)
     * 
     * @param   int     $offset
     * @param   mixed   $value
     */
    public function offsetSet($offset, $value) 
    {
        // Can only add Models to the collection
        if ($value instanceof Mad_Model_Base) {
            $this->_collection[] = $value;
        }        
    }

    /**
     * Collection is readonly, so this is not allowed (method required by interface)
     * 
     * @param   int     $offset
     */
    public function offsetUnset($offset) {}

    /**
     * Iterate over each object in this collection, either accessing
     * a property or calling a method, and return all of the
     * results in an array.
     *
     * The first argument ($property) is interpreted as a property name.  
     * However, if the first argument ends with "()" then it will be
     * interpreted as a method and varargs be passed to that method.
     *
     * @param  string  $property        Property to access on each member
     * @return array                    Results collected
     */
    public function collect($property) {
        $values = array();

        if (substr($property, -2, 2) == '()') {
            // method call
            $method = rtrim($property, '()');
            $args = func_get_args();
            array_shift($args);

            foreach ($this as $member) { 
                $callback = array($member, $method);
                $values[] = call_user_func_array($callback, $args);
            }
        } else {
            // property access
            foreach ($this as $member) {
                $values[] = $member->$property;
            }
        }
    
        return $values;
    }

    /**
     * Initialize result set into object collection
     * 
     * @param   object  $model
     * @param   array   $results
     */
    protected function _initResults(Mad_Model_Base $model, $results)
    {
        while ($row = current($results)) {
            $this->_collection[] = $model->instantiate($row);
            next($results);
        }

    }
}
Return current item: Maintainable PHP Framework