* @license PHP License * @package WB * @subpackage db */ WBClass::load('WBDatasource_SQLCommon' , 'WBDatasource_TableMicroCache' ); /** * Datasource views * * @version 0.4.0 * @package WB * @subpackage db */ class WBDatasource_View extends WBDatasource_SQLCommon { /** * database connection * @var WBDatasource_SQL */ protected $db; /** * microcache * @var WBDatasource_TableMicroCache */ private $mc; /** * datasource item renderer * @var WBDatasource_Renderer */ private $renderer; /** * datasource decorators * @var array WBDatasource_Decorator */ private $decorators = array(); /** * datasource filler * @var array WBDatasource_Filler */ private $filler = array(); /** * configuration loader * @var WBConfig */ protected $config; /** * Fill placeholders with vars * @var array */ protected $vars = array(); /** * List of translatable columns * @var array */ private $translatable = array(); /** * constructor * * The parameter will be loaded from config.xml, section "db", you may * overwrite the list of tables. This will cause to load the table list * from a different file. * * Parameter: * - "tablelist": config file which contains the list of known tables. * * This class utilizes @link WBDatasource_SQL this implies that you may * use all constructor parameter of this class, as well. * * @param array $parameter */ public function __construct($parameter = array()) { parent::__construct($parameter); $this->db = WBClass::create('WBDatasource_SQL', $parameter); $this->loadTables($parameter); $this->config = WBClass::create('WBConfig'); $this->mc = WBClass::create('WBDatasource_TableMicroCache', array('name' => $this->db->getId())); } /** * Set variables to use in datasource * * @param array $vars */ public function addVars($vars) { $this->vars = array_merge($this->vars, $vars); } /** * set renderer object * * @param $renderer */ public function setRenderer(WBDatasource_Renderer $renderer) { $this->renderer = $renderer; } /** * render datasource * * @param string $ds datasource name */ public function render($datasource) { if (!$this->renderer) { WBClass::load('WBException_Call'); throw new WBException_Call('Call setRenderer() first', 1, __CLASS__); } $this->config->load('datasource/' . $datasource); $this->renderer->start($datasource); // get foreign keys to fill preload $foreign = array(); $tables = $this->config->get('view/foreign', array()); foreach ($tables as $t) { $foreign[$t] = $this->getIdentifier($t); } $query = $this->config->get('view/select'); if (!is_array($query)) { $query = array($query); } foreach ($query as $q) { $q = $this->fillPlaceholders($q); $res = $this->db->query($q); } $this->translatable = $this->config->get('view/translatable', array()); $item = $this->fetch($res); $this->startFiller(); $this->startDecorators(); foreach ($this->filler as $filler) { $filler->onStart($item); } foreach ($this->decorators as $dec) { $dec->onStart($item); } while ($item) { // remember id for preloading foreach ($foreign as $table => $key) { $this->mc->setTable($table)->addPreload($item[$key]); } $list = array(); if (empty($this->filler)) { $list = array($item); } else { foreach ($this->filler as $filler) { if (!$filler->mergeItem2List($item, $list)) { break; } } } foreach ($list as $l) { foreach ($this->decorators as $dec) { $dec->decorate($l); } $this->renderer->renderItem($l); } $item = $this->fetch($res); } foreach ($this->filler as $filler) { $filler->onEnd($item); } foreach ($this->decorators as $dec) { $dec->onEnd($item); } $this->renderer->end(); } /** * Fetch data from result set * * @param resource * @return array */ private function fetch($res) { $row = $res->fetch_assoc(); if (empty($row)) { return $row; } if (empty($this->translatable)) { return $row; } foreach ($this->translatable as $t) { $row[$t] = patI18n::gettext($row[$t]); } return $row; } /** * start all configured fillers * * Load fillers and config from datasource config. Instantiate all fillers * configure them and keep them in list * * @see $filler */ private function startFiller() { $config = $this->config->get('view/filler', array()); if (empty($config)) { return; } foreach ($config as $c) { $filler = WBClass::create('WBDatasource_Filler_' . $c['filler']); if (!isset($c['params'])) { $c['params'] = array(); } $filler->configure($c['params']); $this->filler[] = $filler; } } /** * start all configured decorator * * Load decorators and config from datasource config. Instantiate all decorators, * configure them and keep them in list * * @see $decorators */ private function startDecorators() { $config = $this->config->get('view/decorator', array()); if (empty($config)) { return; } foreach ($config as $c) { $dec = WBClass::create('WBDatasource_Decorator_' . $c['decorator']); if (!isset($c['params'])) { $c['params'] = array(); } $dec->configure($c['params']); $this->decorators[] = $dec; } } /** * Fill placeholders in query * * Use $vars to replace placeholders * * @param string $query * @return string */ private function fillPlaceholders($query) { if (empty($this->vars)) { return $query; } $search = array(); $replace = array(); foreach ($this->vars as $k => $v) { if (is_array($v)) { $v = array_map(array($this->db, 'quote'), $v); $v = implode(', ', $v); } else { $v = $this->db->quote($v); } $search[] = '{' . strtoupper($k) . '}'; $replace[] = $v; } return str_replace($search, $replace, $query); } }