From: <gem...@li...> - 2013-01-15 18:02:35
|
Revision: 1101 http://gemstracker.svn.sourceforge.net/gemstracker/?rev=1101&view=rev Author: matijsdejong Date: 2013-01-15 18:02:16 +0000 (Tue, 15 Jan 2013) Log Message: ----------- new ComplianceAction to show an overview of track progress (first version only: layout needs work) new MUtil/Model/ModelTransformerInterface.php with three implementations Modified Paths: -------------- trunk/library/classes/Gems/Menu/MenuAbstract.php trunk/library/classes/Gems/Selector/DateSelectorAbstract.php trunk/library/classes/MUtil/Model/DatabaseModelAbstract.php trunk/library/classes/MUtil/Model/ModelAbstract.php trunk/library/classes/MUtil/Model/ModelTransformerAbstract.php trunk/library/classes/MUtil/Model/SelectModelPaginator.php trunk/library/classes/MUtil/Model/Transform/RequiredRowsTransformer.php trunk/library/configs/db/patches.sql Added Paths: ----------- trunk/library/classes/Gems/Default/ComplianceAction.php trunk/library/classes/Gems/Snippets/Tracker/Compliance/ trunk/library/classes/Gems/Snippets/Tracker/Compliance/ComplianceSearchFormSnippet.php trunk/library/classes/Gems/Snippets/Tracker/Compliance/ComplianceTableSnippet.php trunk/library/classes/MUtil/Model/ModelTransformerInterface.php trunk/library/classes/MUtil/Model/Transform/CrossTabTransformer.php trunk/library/classes/MUtil/Model/Transform/JoinTransformer.php trunk/library/controllers/ComplianceController.php Added: trunk/library/classes/Gems/Default/ComplianceAction.php =================================================================== --- trunk/library/classes/Gems/Default/ComplianceAction.php (rev 0) +++ trunk/library/classes/Gems/Default/ComplianceAction.php 2013-01-15 18:02:16 UTC (rev 1101) @@ -0,0 +1,111 @@ +<?php + +/** + * Copyright (c) 2012, Erasmus MC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Erasmus MC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * @package Gems + * @subpackage Default + * @author Matijs de Jong <mj...@ma...> + * @copyright Copyright (c) 2012 Erasmus MC + * @license New BSD License + * @version $id: ComplianceAction.php 203 2012-01-01t 12:51:32Z matijs $ + */ + +/** + * + * + * @package Gems + * @subpackage Default + * @copyright Copyright (c) 2012 Erasmus MC + * @license New BSD License + * @since Class available since version 1.6 + */ +class Gems_Default_ComplianceAction extends Gems_Controller_ModelSnippetActionAbstract +{ + /** + * The snippets used for the autofilter action. + * + * @var mixed String or array of snippets name + */ + protected $autofilterSnippets = 'Tracker_Compliance_ComplianceTableSnippet'; + + /** + * The snippets used for the index action, before those in autofilter + * + * @var mixed String or array of snippets name + */ + protected $indexStartSnippets = array('Generic_ContentTitleSnippet', 'Tracker_Compliance_ComplianceSearchFormSnippet'); + + /** + * Creates a model for getModel(). Called only for each new $action. + * + * The parameters allow you to easily adapt the model to the current action. The $detailed + * parameter was added, because the most common use of action is a split between detailed + * and summarized actions. + * + * @param boolean $detailed True when the current action is not in $summarizedActions. + * @param string $action The current action. + * @return MUtil_Model_ModelAbstract + */ + public function createModel($detailed, $action) + { + $model = new Gems_Model_JoinModel('resptrack' , 'gems__respondent2track'); + $model->addTable('gems__respondent2org', array( + 'gr2t_id_user' => 'gr2o_id_user', + 'gr2t_id_organization' => 'gr2o_id_organization' + )); + $model->addTable('gems__tracks', array('gr2t_id_track' => 'gtr_id_track')); + + $model->resetOrder(); + $model->set('gr2o_patient_nr', 'label', $this->_('Respondent nr')); + $model->set('gr2t_start_date', 'label', $this->_('Start date'), 'dateFormat', 'dd-MM-yyyy'); + $model->set('gr2t_end_date', 'label', $this->_('End date'), 'dateFormat', 'dd-MM-yyyy'); + + return $model; + } + + /** + * Helper function to get the title for the index action. + * + * @return $string + */ + public function getIndexTitle() + { + return $this->_('Compliance'); + } + + /** + * Helper function to allow generalized statements about the items in the model. + * + * @param int $count + * @return $string + */ + public function getTopic($count = 1) + { + return $this->plural('track', 'tracks', $count); + } +} Modified: trunk/library/classes/Gems/Menu/MenuAbstract.php =================================================================== --- trunk/library/classes/Gems/Menu/MenuAbstract.php 2013-01-14 18:21:45 UTC (rev 1100) +++ trunk/library/classes/Gems/Menu/MenuAbstract.php 2013-01-15 18:02:16 UTC (rev 1101) @@ -322,6 +322,9 @@ { $infoPage = $this->addContainer($label); + $infoPage->addPage($this->_('Compliance'), 'pr.plan.compliance', 'compliance', 'index') + ->addAutofilterAction(); + $plans[] = $infoPage->addPage($this->_('By period'), 'pr.plan.overview', 'overview-plan', 'index'); $plans[] = $infoPage->addPage($this->_('By token'), 'pr.plan.token', 'token-plan', 'index'); $plans[] = $infoPage->addPage($this->_('By respondent'), 'pr.plan.respondent', 'respondent-plan', 'index'); Modified: trunk/library/classes/Gems/Selector/DateSelectorAbstract.php =================================================================== --- trunk/library/classes/Gems/Selector/DateSelectorAbstract.php 2013-01-14 18:21:45 UTC (rev 1100) +++ trunk/library/classes/Gems/Selector/DateSelectorAbstract.php 2013-01-15 18:02:16 UTC (rev 1101) @@ -329,7 +329,7 @@ } else { $this->dateFactorChanges = array_fill_keys(array('D', 'W', 'M', 'Y'), 0); } - // MUtil_Echo::r($requiredRows); + // M qUtil_Echo::track($requiredRows); // MUtil_Echo::rs($start, $end, $where); $select = new Zend_Db_Select($this->db); @@ -346,12 +346,13 @@ // Display by column cannot use formatFunction as it is a simple repeater // $model->set('duration_avg', 'formatFunction', $this->util->getLocalized()->formatNumber); - $tmodel = new MUtil_Model_Transform_RequiredRowsTransformer($model); - $tmodel->setDefaultRow($this->getDefaultRow()); - $tmodel->setRequiredRows($requiredRows); - $tmodel->setKeyItemCount($keyCount); + $transformer = new MUtil_Model_Transform_RequiredRowsTransformer(); + $transformer->setDefaultRow($this->getDefaultRow()); + $transformer->setRequiredRows($requiredRows); + $transformer->setKeyItemCount($keyCount); + $model->addTransformer($transformer); - return $tmodel; + return $model; } protected function getDateDescriptions() Added: trunk/library/classes/Gems/Snippets/Tracker/Compliance/ComplianceSearchFormSnippet.php =================================================================== --- trunk/library/classes/Gems/Snippets/Tracker/Compliance/ComplianceSearchFormSnippet.php (rev 0) +++ trunk/library/classes/Gems/Snippets/Tracker/Compliance/ComplianceSearchFormSnippet.php 2013-01-15 18:02:16 UTC (rev 1101) @@ -0,0 +1,71 @@ +<?php + +/** + * Copyright (c) 2012, Erasmus MC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Erasmus MC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * @package Gems + * @subpackage Tracker + * @author Matijs de Jong <mj...@ma...> + * @copyright Copyright (c) 2012 Erasmus MC + * @license New BSD License + * @version $id: ComplianceSearchFormSnippet.php 203 2012-01-01t 12:51:32Z matijs $ + */ + +/** + * + * + * @package Gems + * @subpackage Tracker + * @copyright Copyright (c) 2012 Erasmus MC + * @license New BSD License + * @since Class available since version 1.5 + */ +class Gems_Snippets_Tracker_Compliance_ComplianceSearchFormSnippet extends Gems_Snippets_AutosearchFormSnippet +{ + /** + * Returns a text element for autosearch. Can be overruled. + * + * The form / html elements to search on. Elements can be grouped by inserting null's between them. + * That creates a distinct group of elements + * + * @param array $data The $form field values (can be usefull, but no need to set them) + * @return array Of Zend_Form_Element's or static tekst to add to the html or null for group breaks. + */ + protected function getAutoSearchElements(array $data) + { + $elements[] = $this->_createSelectElement('gr2t_id_track', + $this->util->getTrackData()->getAllTracks(), + $this->_('(select a track)')); + + $elements[] = $this->_createSelectElement('gr2o_id_organization', + $this->util->getDbLookup()->getOrganizationsWithRespondents(), + $this->_('(all organizations)')); + + return $elements; + } + +} Added: trunk/library/classes/Gems/Snippets/Tracker/Compliance/ComplianceTableSnippet.php =================================================================== --- trunk/library/classes/Gems/Snippets/Tracker/Compliance/ComplianceTableSnippet.php (rev 0) +++ trunk/library/classes/Gems/Snippets/Tracker/Compliance/ComplianceTableSnippet.php 2013-01-15 18:02:16 UTC (rev 1101) @@ -0,0 +1,181 @@ +<?php + +/** + * Copyright (c) 2012, Erasmus MC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Erasmus MC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * @package Gems + * @subpackage Tracker + * @author Matijs de Jong <mj...@ma...> + * @copyright Copyright (c) 2012 Erasmus MC + * @license New BSD License + * @version $id: ComplianceTableSnippet.php 203 2012-01-01t 12:51:32Z matijs $ + */ + +/** + * + * + * @package Gems + * @subpackage Tracker + * @copyright Copyright (c) 2012 Erasmus MC + * @license New BSD License + * @since Class available since version 1.5 + */ +class Gems_Snippets_Tracker_Compliance_ComplianceTableSnippet extends Gems_Snippets_ModelTableSnippetGeneric +{ + /** + * + * @var Zend_Db_Adapter_Abstract + */ + protected $db; + + /** + * + * @var Gems_Loader + */ + protected $loader; + + /** + * Creates the model + * + * @return MUtil_Model_ModelAbstract + */ + protected function createModel() + { + $model = parent::createModel(); + $trackId = $this->getTrackId(); + + if (! $trackId) { + return $model; + } + + $select = $this->db->select(); + $select->from('gems__rounds', array('gro_id_round', 'gro_id_order', 'gro_round_description')) + ->where('gro_id_track = ?', $trackId) + ->order('gro_id_order'); + + $data = $this->db->fetchAll($select); + + if (! $data) { + return $model; + } + + $status = new Zend_Db_Expr(" + CASE + WHEN gto_completion_time IS NOT NULL THEN 'A' + WHEN gto_valid_from IS NULL THEN 'U' + WHEN gto_valid_from > CURRENT_TIMESTAMP THEN 'W' + WHEN gto_valid_until < CURRENT_TIMESTAMP THEN 'M' + ELSE 'O' + END + "); + + // $labels = $model->getCol('label'); + + $select = $this->db->select(); + $select->from('gems__tokens', array('gto_id_respondent_track', 'gto_id_round', 'status' => $status)) + ->joinInner('gems__reception_codes', 'gto_reception_code = grc_id_reception_code', array()) + ->where('grc_success = 1') + ->where('gto_id_track = ?', $trackId) + ->order('gto_id_respondent_track') + ->order('gto_round_order'); + + // MUtil_Echo::track($this->db->fetchAll($select)); + + $newModel = new MUtil_Model_SelectModel($select, 'tok'); + $newModel->setKeys(array('gto_id_respondent_track')); + // $model->addLeftTable('gems__tokens', array('gr2t_id_track' => 'gto_id_track')); + // $model->addLeftTable('gems__reception_codes', array('gto_reception_code' => 'grc_id_reception_code')); + // $model->addFilter(array('grc_success' => 1)); + // $newModel = $model; + + $transformer = new MUtil_Model_Transform_CrossTabTransformer(); + $transformer->setCrosstabFields('gto_id_round', 'status'); + + foreach ($data as $row) { + $name = 'col_' . $row['gro_id_round']; + $transformer->set($name, 'label', $row['gro_id_order'], 'description', $row['gro_round_description']); + // break; + } + + $newModel->addTransformer($transformer); + // MUtil_Echo::track($data); + + $joinTrans = new MUtil_Model_Transform_JoinTransformer(); + $joinTrans->addModel($newModel, array('gr2t_id_respondent_track' => 'gto_id_respondent_track')); + + $model->resetOrder(); + $model->set('gr2o_patient_nr'); + $model->set('gr2t_start_date'); + $model->addTransformer($joinTrans); + return $model; + + return $newModel; + } + + /** + * Returns a show menu item, if access is allowed by privileges + * + * @return Gems_Menu_SubMenuItem + */ + protected function getShowMenuItem() + { + return $this->findMenuItem('track', 'show-track'); + } + + /** + * + * @return int Return the track id if any or null + */ + public function getTrackId() + { + if ($this->requestCache) { + $data = $this->requestCache->getProgramParams(); + if (isset($data['gr2t_id_track'])) { + return $data['gr2t_id_track']; + } + } else { + return $this->request->getParam('gr2t_id_track'); + } + } + + /** + * Overrule to implement snippet specific filtering and sorting. + * + * @param MUtil_Model_ModelAbstract $model + */ + protected function processFilterAndSort(MUtil_Model_ModelAbstract $model) + { + $trackId = $this->getTrackId(); + + if ($trackId) { + parent::processFilterAndSort($model); + } else { + $model->setFilter(array('1=0')); + $this->onEmpty = $this->_('No track selected...'); + } + } +} Modified: trunk/library/classes/MUtil/Model/DatabaseModelAbstract.php =================================================================== --- trunk/library/classes/MUtil/Model/DatabaseModelAbstract.php 2013-01-14 18:21:45 UTC (rev 1100) +++ trunk/library/classes/MUtil/Model/DatabaseModelAbstract.php 2013-01-15 18:02:16 UTC (rev 1101) @@ -166,6 +166,16 @@ } if (null === $value) { $select->where($name . ' IS NULL'); + } elseif (is_array($value)) { + if ($value) { + foreach ($value as $sub) { + $subs[] = $adapter->quote($value); + } + $select->where($name . ' IN (' . implode(', ', $subs) . ')'); + } else { + // Never a result when a value should be one of an empty set. + $select->where('1=0'); + } } else { $select->where($name . ' = ?', $value); } @@ -318,6 +328,23 @@ return $this->_createSelect($filter, $sort)->query(Zend_Db::FETCH_ASSOC)->fetchAll(); } + /** + * Returns an array containing the first requested item. + * + * @param mixed $filter True to use the stored filter, array to specify a different filter + * @param mixed $sort True to use the stored sort, array to specify a different sort + * @return array An array or false + */ + protected function _loadFirst($filter = true, $sort = true) + { + $select = $this->_createSelect($filter, $sort); + $select->limit(1, 0); + + $data = $select->query(Zend_Db::FETCH_ASSOC)->fetch(); + + return $data; + } + protected function _loadTableMetaData(Zend_Db_Table_Abstract $table) { $table_name = $this->_getTableName($table); @@ -703,10 +730,10 @@ public function formatLoadDate($value, $isNew = false, $name = null, array $context = array()) { // If not empty or zend_db_expression and not already a zend date, we - // transform to a Zend_Date using the ISO_8601 format + // transform to a Zend_Date using the ISO_8601 format if (!empty($value) && !($value instanceof Zend_Date) && !($value instanceof Zend_Db_Expr)) { try { - $tmpDate = new MUtil_Date($value, Zend_Date::ISO_8601); + $tmpDate = new MUtil_Date($value, Zend_Date::ISO_8601); } catch (Exception $exc) { // On failure, we use the input value $tmpDate = $value; @@ -895,26 +922,6 @@ } /** - * Returns an array containing the first requested item. - * - * @param mixed $filter True to use the stored filter, array to specify a different filter - * @param mixed $sort True to use the stored sort, array to specify a different sort - * @return array An array or false - */ - public function loadFirst($filter = true, $sort = true) - { - $select = $this->_createSelect($filter, $sort); - $select->limit(1, 0); - - $data = $select->query(Zend_Db::FETCH_ASSOC)->fetch(); - if (is_array($data)) { - $data = $this->_filterDataAfterLoad($data, false); - } - - return $data; - } - - /** * Returns a Zend_Paginator for the items in the model * * @param mixed $filter True to use the stored filter, array to specify a different filter @@ -929,26 +936,6 @@ return new Zend_Paginator($adapter); } - /** - * Helper function for SelectModelPaginator to process - * setOnLoads. - * - * @see MUtil_Model_SelectModelPaginator - * - * @param array $data Nested array - * @return array Nested - */ - public function processAfterLoad(array $data) - { - if ($this->getMeta(parent::LOAD_TRANSFORMER)) { - foreach ($data as $key => $row) { - $data[$key] = $this->_filterDataAfterLoad($row, false); - } - } - - return $data; - } - // abstract public function save(array $newValues); /** Modified: trunk/library/classes/MUtil/Model/ModelAbstract.php =================================================================== --- trunk/library/classes/MUtil/Model/ModelAbstract.php 2013-01-14 18:21:45 UTC (rev 1100) +++ trunk/library/classes/MUtil/Model/ModelAbstract.php 2013-01-15 18:02:16 UTC (rev 1101) @@ -110,12 +110,22 @@ private $_model_used = false; /** + * + * @var array of MUtil_Model_ModelTransformerInterface + */ + private $_transformers = array(); + + /** * The increment for item ordering, default is 10 * * @var int */ public $orderIncrement = 10; + /** + * + * @param string $modelName Hopefully unique model name + */ public function __construct($modelName) { $this->_model_name = $modelName; @@ -267,6 +277,20 @@ */ abstract protected function _load($filter = true, $sort = true); + /** + * Returns a nested array containing the items requested. + * + * @param mixed $filter True to use the stored filter, array to specify a different filter + * @param mixed $sort True to use the stored sort, array to specify a different sort + * @return array Nested array or false + */ + protected function _loadFirst($filter = true, $sort = true) + { + $data = $this->_load($filter, $sort); + + return reset($data); + } + protected function addChanged($add = 1) { $this->_changedCount += $add; @@ -310,6 +334,21 @@ } /** + * Add a model transformer + * + * @param MUtil_Model_ModelTransformerInterface $transformer + * @return MUtil_Model_ModelAbstract (continuation pattern) + */ + public function addTransformer(MUtil_Model_ModelTransformerInterface $transformer) + { + foreach ($transformer->getFieldInfo($this) as $name => $info) { + $this->set($name, $info); + } + $this->_transformers[] = $transformer; + return $this; + } + + /** * Stores the fields that can be used for sorting or filtering in the * sort / filter objects attached to this model. * @@ -864,6 +903,17 @@ } /** + * Get the model transformers + * + * @return array of MUtil_Model_ModelTransformerInterface + */ + public function getTransformers() + { + $this->_transformers[] = $transformer; + return $this; + } + + /** * Splits a wildcard search text into its constituent parts. * * @param string $searchText @@ -1000,10 +1050,8 @@ { $data = $this->_load($filter, $sort); - if (is_array($data) && $this->getMeta(self::LOAD_TRANSFORMER)) { - foreach ($data as $key => $row) { - $data[$key] = $this->_filterDataAfterLoad($row, false); - } + if (is_array($data)) { + $data = $this->processAfterLoad($data); } return $data; @@ -1018,13 +1066,20 @@ */ public function loadFirst($filter = true, $sort = true) { - $data = $this->_load($filter, $sort); - // Return the first row or null. - $data = reset($data); - if (is_array($data) && $this->getMeta(self::LOAD_TRANSFORMER)) { - $data = $this->_filterDataAfterLoad($data, false); + $row = $this->_loadFirst($filter, $sort); + MUtil_Echo::track($row); + + if (! is_array($row)) { + // Return false + return false; } - return $data; + + // Transform the row + $data = $this->processAfterLoad(array($row)); + MUtil_Echo::track($data); + + // Return resulting first row + return reset($data); } /** @@ -1084,6 +1139,29 @@ /** + * Helper function that procesess the raw data after a load. + * + * @see MUtil_Model_SelectModelPaginator + * + * @param array $data Nested array containing rows + * @return array Nested + */ + public function processAfterLoad(array $data) + { + foreach ($this->_transformers as $transformer) { + $data = $transformer->transformLoad($this, $data); + } + + if ($this->getMeta(self::LOAD_TRANSFORMER)) { + foreach ($data as $key => $row) { + $data[$key] = $this->_filterDataAfterLoad($row, false); + } + } + + return $data; + } + + /** * Remove one attribute for a field name in the model. * * Example: @@ -1094,7 +1172,7 @@ * * @param string $name The fieldname * @param string $key The name of the key - * @return $this + * @return MUtil_Model_ModelAbstract (continuation pattern) */ public function remove($name, $key = null) { @@ -1167,13 +1245,13 @@ * </code> * Both set the attribute 'save' to true for 'field_x'. * - * @param string $name The fieldname + * @param string $name The fieldname * @param mixed $arrayOrKey1 A key => value array or the name of the first key, see MUtil_Args::pairs() * @param mixed $value1 The value for $arrayOrKey1 or null when $arrayOrKey1 is an array * @param string $key2 Optional second key when $arrayOrKey1 is a string * @param mixed $value2 Optional second value when $arrayOrKey1 is a string, * an unlimited number of $key values pairs can be given. - * @return $this + * @return \MUtil_Model_ModelAbstract */ public function set($name, $arrayOrKey1 = null, $value1 = null, $key2 = null, $value2 = null) { @@ -1261,7 +1339,7 @@ * @param mixed $value1 The value for $arrayOrKey1 or null when $arrayOrKey1 is an array * @param string $key2 Optional second key when $arrayOrKey1 is a string * @param mixed $value2 Optional second value when $arrayOrKey1 is a string, an unlimited number of $key values pairs can be given. - * @return $this + * @return MUtil_Model_ModelAbstract (continuation pattern) */ public function setCol($arrayOrKey1 = null, $value1 = null, $key2 = null, $value2 = null) { @@ -1353,7 +1431,7 @@ * @param mixed $value1 The value for $arrayOrKey1 or null when $arrayOrKey1 is an array * @param string $key2 Optional second key when $arrayOrKey1 is a string * @param mixed $value2 Optional second value when $arrayOrKey1 is a string, an unlimited number of $key values pairs can be given. - * @return $this + * @return MUtil_Model_ModelAbstract (continuation pattern) */ public function setMulti(array $names, $arrayOrKey1 = null, $value1 = null, $key2 = null, $value2 = null) { @@ -1443,6 +1521,22 @@ return $this->setSaveWhen($name, array(__CLASS__, 'whenNotNull')); } + /** + * set the model transformers + * + * @param array $transformers of MUtil_Model_ModelTransformerInterface + * @return MUtil_Model_ModelAbstract (continuation pattern) + */ + public function setTransformers(array $transformers) + { + $this->_transformers = array(); + foreach ($transformers as $transformer) { + $this->addTransformer($transformer); + } + return $this; + } + + public function setSort($value) { return $this->setMeta('sort', $this->_checkSortValue($value)); Modified: trunk/library/classes/MUtil/Model/ModelTransformerAbstract.php =================================================================== --- trunk/library/classes/MUtil/Model/ModelTransformerAbstract.php 2013-01-14 18:21:45 UTC (rev 1100) +++ trunk/library/classes/MUtil/Model/ModelTransformerAbstract.php 2013-01-15 18:02:16 UTC (rev 1101) @@ -25,208 +25,140 @@ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @package MUtil + * @subpackage Model + * @author Matijs de Jong <mj...@ma...> + * @copyright Copyright (c) 2012 Erasmus MC + * @license New BSD License + * @version $id: ModelTransformerInterface.php 203 2012-01-01t 12:51:32Z matijs $ */ /** - * @author Matijs de Jong - * @since 1.0 - * @version 1.1 - * @package MUtil + * A general transformer that implements all required functions, without + * them doing anything so you can just implement what you need. + * + * @package MUtil * @subpackage Model + * @copyright Copyright (c) 2012 Erasmus MC + * @license New BSD License + * @since Class available since MUtil version 1.2 (in current form) */ -abstract class MUtil_Model_ModelTransformerAbstract extends MUtil_Model_ModelAbstract +abstract class MUtil_Model_ModelTransformerAbstract implements MUtil_Model_ModelTransformerInterface { - protected $sourceModel; - - public function __construct(array $args, array $paramTypes = array()) - { - $paramTypes['sourceModel'] = 'MUtil_Model_ModelAbstract'; - $paramTypes['name'] = 'is_string'; - - $args = MUtil_Ra::args($args, $paramTypes); - - if (isset($args['name'])) { - $name = $args['name']; - unset($args['name']); - } else { - if (isset($args['sourceModel'])) { - $name = $args['sourceModel']->getName(); - } else { - // MUtil_Echo::r($args); - throw new MUtil_Model_ModelException('No $name or $sourceModel parameter specified for ' . get_class($this) . ' constructor.'); - } - } - // MUtil_Echo::r($args, $name); - - parent::__construct($name); - - foreach ($args as $name => $arg) { - $function = 'set' . ucfirst($name); - if (method_exists($this, $function)) { - $this->$function($arg); - } else { - throw new MUtil_Model_ModelException("Unknown argument $name in " . get_class($this) . ' constructor.'); - } - } - } - - protected function _getKeyValue($name, $key) - { - if ($this->sourceModel) { - return $this->sourceModel->_getKeyValue($name, $key); - } - } - /** - * Returns a nested array containing the items requested. * - * @param mixed $filter True to use the stored filter, array to specify a different filter - * @param mixed $sort True to use the stored sort, array to specify a different sort - * @return array Nested array or false + * @var array */ - protected function _load($filter = true, $sort = true) - { - $data = $this->sourceModel->_load($filter, $sort); + protected $_fields = array(); - return $this->transform($data, $filter, $sort); - } - - public function delete($filter = true) - { - throw new Exception('Cannot delete ' . get_class($this) . ' data.'); - } - + /** + * Gets one or more values for a certain field name. + * + * @see MUtil_Model_ModelAbstract->get() + * + * @param string $name Field name + * @param string|array|null $arrayOrKey1 Null or the name of a single attribute or an array of attribute names + * @param string $key2 Optional a second attribute name. + * @return mixed + */ public function get($name, $arrayOrKey1 = null, $key2 = null) { - if ($this->sourceModel) { - $args = func_get_args(); + $args = func_get_args(); + $args = MUtil_Ra::args($args, 1); - call_user_func_array(array($this->sourceModel, 'get'), $args); - } - return $this; - } + switch (count($args)) { + case 0: + if (isset($this->_fields[$name])) { + return $this->_fields[$name]; + } else { + return array(); + } - public function getAlias($name) - { - if ($this->sourceModel) { - return $this->sourceModel->getAlias($name); - } - } + case 1: + $key = $arrayOrKey1; + if (isset($this->_fields[$name][$arrayOrKey1])) { + return $this->_fields[$name][$arrayOrKey1]; + } else { + return null; + } - public function getItemNames() - { - if ($this->sourceModel) { - return $this->sourceModel->getItemNames(); + default: + $results = array(); + foreach ($args as $key) { + if (isset($this->_fields[$name][$arrayOrKey1])) { + $results[$key] = $this->_fields[$name][$arrayOrKey1]; + } + } + return $results; } } - public function getItemsOrdered() + /** + * If the transformer add's fields, these should be returned here. + * Called in $model->AddTransformer(), so the transformer MUST + * know which fields to add by then (optionally using the model + * for that). + * + * @param MUtil_Model_ModelAbstract $model The parent model + * @return array Of filedname => set() values + */ + public function getFieldInfo(MUtil_Model_ModelAbstract $model) { - if ($this->sourceModel) { - return $this->sourceModel->getItemsOrdered(); - } + return $this->_fields; } /** - * Return an identifier the item specified by $forData + * Set one or more attributes for a field names in the model. * - * basically transforms the fieldnames ointo oan IDn => value array + * @see MUtil_Model_ModelAbstract->set() * - * @param mixed $forData Array value to vilter on - * @param array $href Or ArrayObject - * @return array That can by used as href + * @param string $name The fieldname + * @param mixed $arrayOrKey1 A key => value array or the name of the first key, see MUtil_Args::pairs() + * @param mixed $value1 The value for $arrayOrKey1 or null when $arrayOrKey1 is an array + * @param string $key2 Optional second key when $arrayOrKey1 is a string + * @param mixed $value2 Optional second value when $arrayOrKey1 is a string, + * an unlimited number of $key values pairs can be given. + * @return \MUtil_Model_ModelTransformerAbstract */ - public function getKeyRef($forData, $href = array()) - { - if ($this->sourceModel) { - return $this->sourceModel->getKeyRef($forData, $href); - } - } - - public function getKeys($reset = false) - { - if ($this->sourceModel) { - return $this->sourceModel->getKeys($reset); - } - } - - public function getMeta($key, $default = null) - { - if ($this->sourceModel) { - return $this->sourceModel->getMeta($key, $default); - } - } - - public function getSourceModel() - { - return $this->sourceModel; - } - - public function has($name, $subkey = null) - { - if ($this->sourceModel) { - return $this->sourceModel->has($name, $subkey); - } - return false; - } - - public function hasMeta($key) - { - if ($this->sourceModel) { - return $this->sourceModel->hasMeta($key); - } - return false; - } - - public function hasNew() - { - return false; - } - - public function resetOrder() - { - if ($this->sourceModel) { - $this->sourceModel->resetOrder(); - } - return $this; - } - - public function save(array $newValues, array $filter = null) - { - throw new Exception('Cannot save ' . get_class($this) . ' data.'); - } - public function set($name, $arrayOrKey1 = null, $value1 = null, $key2 = null, $value2 = null) { - if ($this->sourceModel) { - $args = func_get_args(); + $args = func_get_args(); + $args = MUtil_Ra::pairs($args, 1); - call_user_func_array(array($this->sourceModel, 'set'), $args); - } - return $this; - } + foreach ($args as $key => $value) { + // If $key end with ] it is array value + if (substr($key, -1) == ']') { + if (substr($key, -2) == '[]') { + // If $key ends with [], append it to array + $key = substr($key, 0, -2); + $this->_fields[$name][$key][] = $value; + } else { + // Otherwise extract subkey + $pos = strpos($key, '['); + $subkey = substr($key, $pos + 1, -1); + $key = substr($key, 0, $pos); - public function setKeys(array $keys) - { - if ($this->sourceModel) { - $this->sourceModel->setKeys($key, $value); + $this->_fields[$name][$key][$subkey] = $value; + } + } else { + $this->_fields[$name][$key] = $value; + } } - return $this; - } - public function setMeta($key, $value) - { - if ($this->sourceModel) { - $this->sourceModel->setMeta($key, $value); - } return $this; } - public function setSourceModel(MUtil_Model_ModelAbstract $model) + /** + * The transform function performs the actual transformation of the data and is called after + * the loading of the data in the source model. + * + * @param MUtil_Model_ModelAbstract $model The parent model + * @param array $data Nested array + * @return array Nested array containing (optionally) transformed data + */ + public function transformLoad(MUtil_Model_ModelAbstract $model, array $data) { - $this->sourceModel = $model; - return $this; + return $data; } - - abstract public function transform($data, $filter = true, $sort = true); } Added: trunk/library/classes/MUtil/Model/ModelTransformerInterface.php =================================================================== --- trunk/library/classes/MUtil/Model/ModelTransformerInterface.php (rev 0) +++ trunk/library/classes/MUtil/Model/ModelTransformerInterface.php 2013-01-15 18:02:16 UTC (rev 1101) @@ -0,0 +1,69 @@ +<?php + +/** + * Copyright (c) 2012, Erasmus MC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Erasmus MC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * @package MUtil + * @subpackage Model + * @author Matijs de Jong <mj...@ma...> + * @copyright Copyright (c) 2012 Erasmus MC + * @license New BSD License + * @version $id: ModelTransformerInterface.php 203 2012-01-01t 12:51:32Z matijs $ + */ + +/** + * An general interface to transform the data retrieved by a model + * + * @package MUtil + * @subpackage Model + * @copyright Copyright (c) 2012 Erasmus MC + * @license New BSD License + * @since Class available since MUtil version 1.2 + */ +interface MUtil_Model_ModelTransformerInterface +{ + /** + * If the transformer add's fields, these should be returned here. + * Called in $model->AddTransformer(), so the transformer MUST + * know which fields to add by then (optionally using the model + * for that). + * + * @param MUtil_Model_ModelAbstract $model The parent model + * @return array Of filedname => set() values + */ + public function getFieldInfo(MUtil_Model_ModelAbstract $model); + + /** + * The transform function performs the actual transformation of the data and is called after + * the loading of the data in the source model. + * + * @param MUtil_Model_ModelAbstract $model The parent model + * @param array $data Nested array + * @return array Nested array containing (optionally) transformed data + */ + public function transformLoad(MUtil_Model_ModelAbstract $model, array $data); +} Modified: trunk/library/classes/MUtil/Model/SelectModelPaginator.php =================================================================== --- trunk/library/classes/MUtil/Model/SelectModelPaginator.php 2013-01-14 18:21:45 UTC (rev 1100) +++ trunk/library/classes/MUtil/Model/SelectModelPaginator.php 2013-01-15 18:02:16 UTC (rev 1101) @@ -94,7 +94,7 @@ $items = $this->_selectAdapter->getItems($offset, $itemCountPerPage); // MUtil_Echo::track($items); - if ($items && is_array($items)) { + if (is_array($items)) { $items = $this->_model->processAfterLoad($items); } // MUtil_Echo::track($items); Added: trunk/library/classes/MUtil/Model/Transform/CrossTabTransformer.php =================================================================== --- trunk/library/classes/MUtil/Model/Transform/CrossTabTransformer.php (rev 0) +++ trunk/library/classes/MUtil/Model/Transform/CrossTabTransformer.php 2013-01-15 18:02:16 UTC (rev 1101) @@ -0,0 +1,122 @@ +<?php + +/** + * Copyright (c) 2012, Erasmus MC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Erasmus MC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * @package MUtil + * @subpackage Model + * @author Matijs de Jong <mj...@ma...> + * @copyright Copyright (c) 2012 Erasmus MC + * @license New BSD License + * @version $id: CrossTabTransformer.php 203 2012-01-01t 12:51:32Z matijs $ + */ + +/** + * + * + * @package MUtil + * @subpackage Model + * @copyright Copyright (c) 2012 Erasmus MC + * @license New BSD License + * @since Class available since MUtil version 1.2 + */ +class MUtil_Model_Transform_CrossTabTransformer extends MUtil_Model_ModelTransformerAbstract +{ + /** + * The field to crosstab over + * + * @var string + */ + protected $idField; + + /** + * + * @var string + */ + protected $valueField; + + /** + * + * @param string $idField The field values to perform the crosstab over + * @param string $valueField The field values to crosstab + * @return MUtil_Model_Transform_CrossTabTransformer (continuation pattern) + */ + public function setCrosstabFields($idField, $valueField) + { + $this->idField = $idField; + $this->valueField = $valueField; + + return $this; + + } + + /** + * The transform function performs the actual transformation of the data and is called after + * the loading of the data in the source model. + * + * @param MUtil_Model_ModelAbstract $model The parent model + * @param array $data Nested array + * @return array Nested array containing (optionally) transformed data + */ + public function transformLoad(MUtil_Model_ModelAbstract $model, array $data) + { + if (! $data) { + return $data; + } + + //* + $row = reset($data); + if (! ($this->idField && + $this->valueField && + isset($row[$this->idField]) && + array_key_exists($this->valueField, $row) + )) { + return $data; + } + + $keys = $model->getKeys(); + $keys = array_combine($keys, $keys); + $default = array_fill_keys(array_keys($this->_fields), null); + $except = array($this->idField => 1, $this->valueField => 1); + $results = array(); + foreach ($data as $row) { + $name = 'col_' . $row[$this->idField]; + + if (isset($this->_fields[$name])) { + $key = implode("\t", array_intersect_key($row, $keys)); + + if (! isset($results[$key])) { + $results[$key] = array_diff_key($row, $except) + $default; + } + $results[$key][$name] = $row[$this->valueField]; + } + } + + // MUtil_Echo::track($results, $data); + return $results; + } +} Added: trunk/library/classes/MUtil/Model/Transform/JoinTransformer.php =================================================================== --- trunk/library/classes/MUtil/Model/Transform/JoinTransformer.php (rev 0) +++ trunk/library/classes/MUtil/Model/Transform/JoinTransformer.php 2013-01-15 18:02:16 UTC (rev 1101) @@ -0,0 +1,143 @@ +<?php + +/** + * Copyright (c) 2012, Erasmus MC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Erasmus MC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * @package MUtil + * @subpackage Model + * @author Matijs de Jong <mj...@ma...> + * @copyright Copyright (c) 2012 Erasmus MC + * @license New BSD License + * @version $id: JoinTransformer.php 203 2012-01-01t 12:51:32Z matijs $ + */ + +/** + * Transform that can be used to join models to another model in non-relational + * ways. + * + * @package MUtil + * @subpackage Model + * @copyright Copyright (c) 2012 Erasmus MC + * @license New BSD License + * @since Class available since MUtil version 1.2 + */ +class MUtil_Model_Transform_JoinTransformer implements MUtil_Model_ModelTransformerInterface +{ + /** + * + * @var array of join functions + */ + protected $_joins = array(); + + /** + * + * @var array of MUtil_Model_ModelAbstract + */ + protected $_subModels = array(); + + public function addModel(MUtil_Model_ModelAbstract $subModel, array $joinFields) + { + $name = $subModel->getName(); + $this->_subModels[$name] = $subModel; + $this->_joins[$name] = $joinFields; + + if (count($joinFields) > 1) { + throw new MUtil_Model_ModelException(__CLASS__ . " currently accepts single field joins only."); + } + + return $this; + } + + /** + * If the transformer add's fields, these should be returned here. + * Called in $model->AddTransformer(), so the transformer MUST + * know which fields to add by then (optionally using the model + * for that). + * + * @param MUtil_Model_ModelAbstract $model The parent model + * @return array Of filedname => set() values + */ + public function getFieldInfo(MUtil_Model_ModelAbstract $model) + { + $data = array(); + foreach ($this->_subModels as $sub) { + foreach ($sub->getItemNames() as $name) { + if (! $model->has($name)) { + $data[$name] = $sub->get($name); + } + } + } + return $data; + } + + /** + * The transform function performs the actual transformation of the data and is called after + * the loading of the data in the source model. + * + * @param MUtil_Model_ModelAbstract $model The parent model + * @param array $data Nested array + * @return array Nested array containing (optionally) transformed data + */ + public function transformLoad(MUtil_Model_ModelAbstract $model, array $data) + { + if (! $data) { + return $data; + } + + foreach ($this->_subModels as $name => $sub) { + /* @var $sub MUtil_Model_ModelAbstract */ + + if (1 === count($this->_joins[$name])) { + $mkey = key($this->_joins[$name]); + $skey = reset($this->_joins[$name]); + + $mfor = MUtil_Ra::column($mkey, $data); + + // MUtil_Echo::track($mfor); + + $sdata = $sub->load(array($skey => $mfor)); + // MUtil_Echo::track($sdata); + + $skeys = array_flip(MUtil_Ra::column($skey, $sdata)); + $empty = array_fill_keys(array_keys(reset($sdata)), null); + + foreach ($data as &$mrow) { + $mfind = $mrow[$mkey]; + + if (isset($skeys[$mfind])) { + $mrow += $sdata[$skeys[$mfind]]; + } else { + $mrow += $empty; + } + } + } + } + // MUtil_Echo::track($data); + + return $data; + } +} Modified: trunk/library/classes/MUtil/Model/Transform/RequiredRowsTransformer.php =================================================================== --- trunk/library/classes/MUtil/Model/Transform/RequiredRowsTransformer.php 2013-01-14 18:21:45 UTC (rev 1100) +++ trunk/library/classes/MUtil/Model/Transform/RequiredRowsTransformer.php 2013-01-15 18:02:16 UTC (rev 1101) @@ -49,22 +49,33 @@ */ class MUtil_Model_Transform_RequiredRowsTransformer extends MUtil_Model_ModelTransformerAbstract { + /** + * Contains default values for all missing row values + * + * @var mixed Something that can be made into an array using MUtil_Ra::to() + */ protected $_defaultRow; + + /** + * The number of key values to compare, if empty the number of fields in the first required row + * + * @var int + */ protected $_keyItemCount; + + /** + * + * @var mixed Something that can be made into an array using MUtil_Ra::to() + */ protected $_requiredRows; - public function __construct($requiredRows, $sourceModel_args = null) - { - $args = func_get_args(); - $paramTypes = array( - 'sourceModel' => 'MUtil_Model_ModelAbstract', - 'requiredRows' => 'is_ra_array', - 'keyItemCount' => 'is_int', - ); - - parent::__construct($args, $paramTypes); - } - + /** + * + * @param array $required + * @param array $row + * @param int $count + * @return boolean True if the rows refer to the same row + */ protected function _compareRows($required, $row, $count) { if ($row) { @@ -87,10 +98,16 @@ } } - public function getDefaultRow() + /** + * Returns the required rows set or calculates the rows using the $model and the required rows info + * + * @param MUtil_Model_ModelAbstract $model Optional model for calculation + * @return array + * @throws MUtil_Model_ModelException + */ + public function getDefaultRow(MUtil_Model_ModelAbstract $model = null) { if (! $this->_defaultRow) { - $model = $this->getSourceModel(); $requireds = $this->getRequiredRows(); $required = MUtil_Ra::to(reset($requireds)); @@ -98,7 +115,7 @@ $this->setKeyItemCount(count($required)); } - if ($model && $required) { + if ($required && ($model instanceof MUtil_Model_ModelAbstract)) { $defaults = array(); foreach ($model->getItemNames() as $name) { if (! array_key_exists($name, $required)) { @@ -116,6 +133,11 @@ return $this->_defaultRow; } + /** + * The number of key values to compare + * + * @return int + */ public function getKeyItemCount() { if (! $this->_keyItemCount) { @@ -126,6 +148,11 @@ return $this->_keyItemCount; } + /** + * Array of required rows + * + * @return array + */ public function getRequiredRows() { if (! is_array($this->_requiredRows)) { @@ -135,6 +162,13 @@ return $this->_requiredRows; } + /** + * Contains default values for all missing row values + * + * @param mixed $defaultRow Something that can be made into an array using MUtil_Ra::to() + * @return \MUtil_Model_Transform_RequiredRowsTransformer + * @throws MUtil_Model_ModelException + */ public function setDefaultRow($defaultRow) { if (MUtil_Ra::is($defaultRow)) { @@ -145,12 +179,25 @@ throw new MUtil_Model_ModelException('Invalid parameter type for ' . __FUNCTION__ . ': $rows cannot be converted to an array.'); } + /** + * The number of key values to compare + * + * @param int $count + * @return \MUtil_Model_Transform_RequiredRowsTransformer + */ public function setKeyItemCount($count) { $this->_keyItemCount = $count; return $this; } + /** + * The keys for the required rows + * + * @param mixed $rows Something that can be made into an array using MUtil_Ra::to() + * @return \MUtil_Model_Transform_RequiredRowsTransformer + * @throws MUtil_Model_ModelException + */ public function setRequiredRows($rows) { if (MUtil_Ra::is($rows)) { @@ -161,9 +208,17 @@ throw new MUtil_Model_ModelException('Invalid parameter type for ' . __FUNCTION__ . ': $rows cannot be converted to an array.'); } - public function transform($data, $filter = true, $sort = true) + /** + * The transform function performs the actual transformation of the data and is called after + * the loading of the data in the source model. + * + * @param MUtil_Model_ModelAbstract $model The parent model + * @param array $data Nested array + * @return array Nested array containing (optionally) transformed data + */ + public function transformLoad(MUtil_Model_ModelAbstract $model... [truncated message content] |