<?php
/**
 * Implementation of the base domain model class.
 *
 * @package koubel homepage
 * @author Miroslav Kubelik (koubel@seznam.cz)
 * @copyright Copyright (c) 2007-2009 Miroslav Kubelik
 * @license http://opensource.org/licenses/bsd-license.php new BSD license
 */

/**
 * The base class for all domain models in a MVC pattern sense.
 *
 * @package koubel homepage
 * @author Miroslav Kubelik (koubel@seznam.cz)
 * @copyright Copyright (c) 2007-2009 Miroslav Kubelik
 * @license http://opensource.org/licenses/bsd-license.php new BSD license
 */ 
abstract class Model
{
    /**
     * Dao for our module
     * @var Dao
     */     
    private $_dao;

    /**
     * Sets Dao.
     * @var Dao $dao if is null, dao leaves uninitialized 
     */     
    public function __construct(Dao $dao=null)
    {
        if (!is_null($dao)) $this->setDao($dao);
    }

    /**
     * Sets dao for the current model.
     */  
    public function setDao(Dao $dao)
    {
        $this->_dao=$dao;
    }

    /**
     * Sets dao object, which is default for the specific model class.
     * Sets {@link $_dao} 
     */ 
    abstract protected function _setDefaultDao();

    /**
     * Gets dao.
     * @return Dao
     * @throws RuntimeException when dao isn't succesfully initialized   
     */ 
    public function getDao()
    {
        if (!isset($this->_dao)) $this->_setDefaultDao();
        if ($this->_dao instanceof Dao) return $this->_dao;
        else throw new RuntimeException("Dao for the model ".get_class($this)
            ."ins't correctly initialized");
    }

    /**
     * Sets model properties from the one row, which is returned from the 
     * {@link Model::$_dao}.
     * @param array $row associative array with properties for current model,
     * indexes for this array are transformed if neccessary
     */
    protected function _setFromDaoRow($row)
    {
        $this->_inflectDaoRowIndexes($row);
        $this->_setPropFromArray($row);
    }

    /**
     * Sets properties from associative array
     * @param array $arr associative array with keys as the property name and a value
     * as the property value. It is in mostly cases adjusted by @link Model::_inflectDaoRowIndexes()}
     * method.
     */
    abstract protected function _setPropFromArray(&$arr);

    /**
     * Adjust some indexes in the $arr parameter for a mapping into model properties.
     * @param array $arr associative array with keys as the property name and a value
     * as the property value.
     */
    abstract protected function _inflectDaoRowIndexes(&$arr);

    /**
     * Gets found items. 
     * The result is made from the result of the search object as $search parameter. 
     * @param Search $search search object with the search result. Object must
     * be initialized before this method call, we only call method for the result.
     * @return array set of Model objects     
     */
    public function getFound(Search $search)
    {
        $rows = $search->searchItems();
        return $this->_getSet($rows);
    }

    /**
     * Transform the resultSet from the Dao into the array of models objects, this
     * is model resultSet. 
     * @param Traversable dao result set, it can be simple associative
     *  array  
     * @return array array of current model objects      
     */
    protected function _getSet($daoRowSet)
    {
        $resultArr=array();

        foreach($daoRowSet as $row) {
            if ($row instanceof Zend_Db_Table_Row_Abstract) $row=$row->toArray();
            $this->_inflectDaoRowIndexes($row);
            $className=get_class($this);
            $item=new $className($this->getDao());
            $item->_setPropFromArray($row);
            $resultArr[]=$item;
        }

        return $resultArr;
    }

    /**
     * Gets number of model items in the data source.
     * @return int   
     */
    public function getCount()
    {
        return $this->getDao()->getCount();
    }
}
