collection.php 5.75 KB
<?php
class Flora_Collection implements Iterator, ArrayAccess, Countable
{
    protected $total;
    protected $items;
    protected $offset;
    protected $count;
    protected $sortField;
    protected $sortAscending;

    public function __construct($data)
    {
        foreach ($data as $k => $v) {
            $this->$k = $v;
        }
    }

    /**
     * @param mixed $id
     * @param string $field
     * @return null|Flora_Model
     */
    public function getById($id, $field = 'id')
    {
        foreach ($this->items as $item) {
            if ($item->$field == $id) {
                return $item;
            }
        }

        return null;
    }

    /**
     * (PHP 5 &gt;= 5.1.0)<br/>
     * Return the current element
     * @link http://php.net/manual/en/iterator.current.php
     * @return mixed Can return any type.
     */
    public function current()
    {
        return current($this->items);
    }

    /**
     * (PHP 5 &gt;= 5.1.0)<br/>
     * Move forward to next element
     * @link http://php.net/manual/en/iterator.next.php
     * @return void Any returned value is ignored.
     */
    public function next()
    {
        next($this->items);
    }

    /**
     * (PHP 5 &gt;= 5.1.0)<br/>
     * Return the key of the current element
     * @link http://php.net/manual/en/iterator.key.php
     * @return scalar scalar on success, integer
     * 0 on failure.
     */
    public function key()
    {
        return key($this->items);
    }

    /**
     * (PHP 5 &gt;= 5.1.0)<br/>
     * Checks if current position is valid
     * @link http://php.net/manual/en/iterator.valid.php
     * @return boolean The return value will be casted to boolean and then evaluated.
     * Returns true on success or false on failure.
     */
    public function valid()
    {
        $key = key($this->items);
        return ($key !== NULL && $key !== FALSE);
    }

    /**
     * (PHP 5 &gt;= 5.1.0)<br/>
     * Rewind the Iterator to the first element
     * @link http://php.net/manual/en/iterator.rewind.php
     * @return void Any returned value is ignored.
     */
    public function rewind()
    {
        reset($this->items);
    }

    /**
     * Returns items count which was fetched
     * @return int
     */
    public function getCount()
    {
        return $this->count;
    }

    /**
     * Returns models array data
     * @return Flora_Model[]
     */
    public function getItems()
    {
        return $this->items;
    }

    /**
     * Total collection items offset gived for fetch
     * @return int
     */
    public function getOffset()
    {
        return $this->offset;
    }

    /**
     * Return total collection items which can be fetched
     * @return int
     */
    public function getTotal()
    {
        return $this->total;
    }

    public function sort($field, $ascending = true)
    {
        if (!preg_match('#^[a-z0-9_\-]#i', $field)) {
            return $this;
        }

        $this->sortAscending = (bool)$ascending;
        $this->sortField = $field;

        uasort($this->items, array($this, "sorter"));

        if (!$ascending) {
            $this->items = array_reverse($this->items, true);
        }

        return $this;
    }

    public function getPager($perPage = 20)
    {
        return new Flora_Collection_Pager($this, $perPage);
    }

    private function sorter($a, $b)
    {
        $a = $a->{$this->sortField};
        $b = $b->{$this->sortField};

        if (is_numeric($a) && is_numeric($b)) {
            if ($a == $b) {
                return 0;
            }
            return ($a < $b) ? -1 : 1;
        } else {
            return strcmp($a, $b);
        }
    }

    public function slice($offset, $length = null)
    {
        $return = array_slice($this->getItems(), $offset, $length);
        return new Flora_Collection(array(
            'items' => $return,
            'total' => count($return),
            'count' => count($return),
        ));
    }

    /**
     * (PHP 5 &gt;= 5.1.0)<br/>
     * Whether a offset exists
     * @link http://php.net/manual/en/arrayaccess.offsetexists.php
     * @param mixed $offset <p>
     * An offset to check for.
     * </p>
     * @return boolean Returns true on success or false on failure.
     * </p>
     * <p>
     * The return value will be casted to boolean if non-boolean was returned.
     */
    public function offsetExists($offset)
    {
        return isset($this->items[$offset]);
    }

    /**
     * (PHP 5 &gt;= 5.1.0)<br/>
     * Offset to retrieve
     * @link http://php.net/manual/en/arrayaccess.offsetget.php
     * @param mixed $offset <p>
     * The offset to retrieve.
     * </p>
     * @return mixed Can return all value types.
     */
    public function offsetGet($offset)
    {
        return $this->items[$offset];
    }

    /**
     * (PHP 5 &gt;= 5.1.0)<br/>
     * Offset to set
     * @link http://php.net/manual/en/arrayaccess.offsetset.php
     * @param mixed $offset <p>
     * The offset to assign the value to.
     * </p>
     * @param mixed $value <p>
     * The value to set.
     * </p>
     * @return void
     */
    public function offsetSet($offset, $value)
    {
        $this->items[$offset] = $value;
    }

    /**
     * (PHP 5 &gt;= 5.1.0)<br/>
     * Offset to unset
     * @link http://php.net/manual/en/arrayaccess.offsetunset.php
     * @param mixed $offset <p>
     * The offset to unset.
     * </p>
     * @return void
     */
    public function offsetUnset($offset)
    {
        unset($this->items[$offset]);
    }

    /**
     * (PHP 5 &gt;= 5.1.0)<br/>
     * Count elements of an object
     * @link http://php.net/manual/en/countable.count.php
     * @return int The custom count as an integer.
     * </p>
     * <p>
     * The return value is cast to an integer.
     */
    public function count()
    {
        return count($this->items);
    }
}