File indexing completed on 2025-01-26 05:29:24
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Db 0017 * @subpackage Table 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 /** 0024 * @see Zend_Db_Adapter_Abstract 0025 */ 0026 // require_once 'Zend/Db/Adapter/Abstract.php'; 0027 0028 /** 0029 * @see Zend_Db_Adapter_Abstract 0030 */ 0031 // require_once 'Zend/Db/Select.php'; 0032 0033 /** 0034 * @see Zend_Db 0035 */ 0036 // require_once 'Zend/Db.php'; 0037 0038 /** 0039 * Class for SQL table interface. 0040 * 0041 * @category Zend 0042 * @package Zend_Db 0043 * @subpackage Table 0044 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0045 * @license http://framework.zend.com/license/new-bsd New BSD License 0046 */ 0047 abstract class Zend_Db_Table_Abstract 0048 { 0049 0050 const ADAPTER = 'db'; 0051 const DEFINITION = 'definition'; 0052 const DEFINITION_CONFIG_NAME = 'definitionConfigName'; 0053 const SCHEMA = 'schema'; 0054 const NAME = 'name'; 0055 const PRIMARY = 'primary'; 0056 const COLS = 'cols'; 0057 const METADATA = 'metadata'; 0058 const METADATA_CACHE = 'metadataCache'; 0059 const METADATA_CACHE_IN_CLASS = 'metadataCacheInClass'; 0060 const ROW_CLASS = 'rowClass'; 0061 const ROWSET_CLASS = 'rowsetClass'; 0062 const REFERENCE_MAP = 'referenceMap'; 0063 const DEPENDENT_TABLES = 'dependentTables'; 0064 const SEQUENCE = 'sequence'; 0065 0066 const COLUMNS = 'columns'; 0067 const REF_TABLE_CLASS = 'refTableClass'; 0068 const REF_COLUMNS = 'refColumns'; 0069 const ON_DELETE = 'onDelete'; 0070 const ON_UPDATE = 'onUpdate'; 0071 0072 const CASCADE = 'cascade'; 0073 const CASCADE_RECURSE = 'cascadeRecurse'; 0074 const RESTRICT = 'restrict'; 0075 const SET_NULL = 'setNull'; 0076 0077 const DEFAULT_NONE = 'defaultNone'; 0078 const DEFAULT_CLASS = 'defaultClass'; 0079 const DEFAULT_DB = 'defaultDb'; 0080 0081 const SELECT_WITH_FROM_PART = true; 0082 const SELECT_WITHOUT_FROM_PART = false; 0083 0084 /** 0085 * Default Zend_Db_Adapter_Abstract object. 0086 * 0087 * @var Zend_Db_Adapter_Abstract 0088 */ 0089 protected static $_defaultDb; 0090 0091 /** 0092 * Optional Zend_Db_Table_Definition object 0093 * 0094 * @var unknown_type 0095 */ 0096 protected $_definition = null; 0097 0098 /** 0099 * Optional definition config name used in concrete implementation 0100 * 0101 * @var string 0102 */ 0103 protected $_definitionConfigName = null; 0104 0105 /** 0106 * Default cache for information provided by the adapter's describeTable() method. 0107 * 0108 * @var Zend_Cache_Core 0109 */ 0110 protected static $_defaultMetadataCache = null; 0111 0112 /** 0113 * Zend_Db_Adapter_Abstract object. 0114 * 0115 * @var Zend_Db_Adapter_Abstract 0116 */ 0117 protected $_db; 0118 0119 /** 0120 * The schema name (default null means current schema) 0121 * 0122 * @var array 0123 */ 0124 protected $_schema = null; 0125 0126 /** 0127 * The table name. 0128 * 0129 * @var string 0130 */ 0131 protected $_name = null; 0132 0133 /** 0134 * The table column names derived from Zend_Db_Adapter_Abstract::describeTable(). 0135 * 0136 * @var array 0137 */ 0138 protected $_cols; 0139 0140 /** 0141 * The primary key column or columns. 0142 * A compound key should be declared as an array. 0143 * You may declare a single-column primary key 0144 * as a string. 0145 * 0146 * @var mixed 0147 */ 0148 protected $_primary = null; 0149 0150 /** 0151 * If your primary key is a compound key, and one of the columns uses 0152 * an auto-increment or sequence-generated value, set _identity 0153 * to the ordinal index in the $_primary array for that column. 0154 * Note this index is the position of the column in the primary key, 0155 * not the position of the column in the table. The primary key 0156 * array is 1-based. 0157 * 0158 * @var integer 0159 */ 0160 protected $_identity = 1; 0161 0162 /** 0163 * Define the logic for new values in the primary key. 0164 * May be a string, boolean true, or boolean false. 0165 * 0166 * @var mixed 0167 */ 0168 protected $_sequence = true; 0169 0170 /** 0171 * Information provided by the adapter's describeTable() method. 0172 * 0173 * @var array 0174 */ 0175 protected $_metadata = array(); 0176 0177 /** 0178 * Cache for information provided by the adapter's describeTable() method. 0179 * 0180 * @var Zend_Cache_Core 0181 */ 0182 protected $_metadataCache = null; 0183 0184 /** 0185 * Flag: whether or not to cache metadata in the class 0186 * @var bool 0187 */ 0188 protected $_metadataCacheInClass = true; 0189 0190 /** 0191 * Classname for row 0192 * 0193 * @var string 0194 */ 0195 protected $_rowClass = 'Zend_Db_Table_Row'; 0196 0197 /** 0198 * Classname for rowset 0199 * 0200 * @var string 0201 */ 0202 protected $_rowsetClass = 'Zend_Db_Table_Rowset'; 0203 0204 /** 0205 * Associative array map of declarative referential integrity rules. 0206 * This array has one entry per foreign key in the current table. 0207 * Each key is a mnemonic name for one reference rule. 0208 * 0209 * Each value is also an associative array, with the following keys: 0210 * - columns = array of names of column(s) in the child table. 0211 * - refTableClass = class name of the parent table. 0212 * - refColumns = array of names of column(s) in the parent table, 0213 * in the same order as those in the 'columns' entry. 0214 * - onDelete = "cascade" means that a delete in the parent table also 0215 * causes a delete of referencing rows in the child table. 0216 * - onUpdate = "cascade" means that an update of primary key values in 0217 * the parent table also causes an update of referencing 0218 * rows in the child table. 0219 * 0220 * @var array 0221 */ 0222 protected $_referenceMap = array(); 0223 0224 /** 0225 * Simple array of class names of tables that are "children" of the current 0226 * table, in other words tables that contain a foreign key to this one. 0227 * Array elements are not table names; they are class names of classes that 0228 * extend Zend_Db_Table_Abstract. 0229 * 0230 * @var array 0231 */ 0232 protected $_dependentTables = array(); 0233 0234 0235 protected $_defaultSource = self::DEFAULT_NONE; 0236 protected $_defaultValues = array(); 0237 0238 /** 0239 * Constructor. 0240 * 0241 * Supported params for $config are: 0242 * - db = user-supplied instance of database connector, 0243 * or key name of registry instance. 0244 * - name = table name. 0245 * - primary = string or array of primary key(s). 0246 * - rowClass = row class name. 0247 * - rowsetClass = rowset class name. 0248 * - referenceMap = array structure to declare relationship 0249 * to parent tables. 0250 * - dependentTables = array of child tables. 0251 * - metadataCache = cache for information from adapter describeTable(). 0252 * 0253 * @param mixed $config Array of user-specified config options, or just the Db Adapter. 0254 * @return void 0255 */ 0256 public function __construct($config = array()) 0257 { 0258 /** 0259 * Allow a scalar argument to be the Adapter object or Registry key. 0260 */ 0261 if (!is_array($config)) { 0262 $config = array(self::ADAPTER => $config); 0263 } 0264 0265 if ($config) { 0266 $this->setOptions($config); 0267 } 0268 0269 $this->_setup(); 0270 $this->init(); 0271 } 0272 0273 /** 0274 * setOptions() 0275 * 0276 * @param array $options 0277 * @return Zend_Db_Table_Abstract 0278 */ 0279 public function setOptions(Array $options) 0280 { 0281 foreach ($options as $key => $value) { 0282 switch ($key) { 0283 case self::ADAPTER: 0284 $this->_setAdapter($value); 0285 break; 0286 case self::DEFINITION: 0287 $this->setDefinition($value); 0288 break; 0289 case self::DEFINITION_CONFIG_NAME: 0290 $this->setDefinitionConfigName($value); 0291 break; 0292 case self::SCHEMA: 0293 $this->_schema = (string) $value; 0294 break; 0295 case self::NAME: 0296 $this->_name = (string) $value; 0297 break; 0298 case self::PRIMARY: 0299 $this->_primary = (array) $value; 0300 break; 0301 case self::ROW_CLASS: 0302 $this->setRowClass($value); 0303 break; 0304 case self::ROWSET_CLASS: 0305 $this->setRowsetClass($value); 0306 break; 0307 case self::REFERENCE_MAP: 0308 $this->setReferences($value); 0309 break; 0310 case self::DEPENDENT_TABLES: 0311 $this->setDependentTables($value); 0312 break; 0313 case self::METADATA_CACHE: 0314 $this->_setMetadataCache($value); 0315 break; 0316 case self::METADATA_CACHE_IN_CLASS: 0317 $this->setMetadataCacheInClass($value); 0318 break; 0319 case self::SEQUENCE: 0320 $this->_setSequence($value); 0321 break; 0322 default: 0323 // ignore unrecognized configuration directive 0324 break; 0325 } 0326 } 0327 0328 return $this; 0329 } 0330 0331 /** 0332 * setDefinition() 0333 * 0334 * @param Zend_Db_Table_Definition $definition 0335 * @return Zend_Db_Table_Abstract 0336 */ 0337 public function setDefinition(Zend_Db_Table_Definition $definition) 0338 { 0339 $this->_definition = $definition; 0340 return $this; 0341 } 0342 0343 /** 0344 * getDefinition() 0345 * 0346 * @return Zend_Db_Table_Definition|null 0347 */ 0348 public function getDefinition() 0349 { 0350 return $this->_definition; 0351 } 0352 0353 /** 0354 * setDefinitionConfigName() 0355 * 0356 * @param string $definition 0357 * @return Zend_Db_Table_Abstract 0358 */ 0359 public function setDefinitionConfigName($definitionConfigName) 0360 { 0361 $this->_definitionConfigName = $definitionConfigName; 0362 return $this; 0363 } 0364 0365 /** 0366 * getDefinitionConfigName() 0367 * 0368 * @return string 0369 */ 0370 public function getDefinitionConfigName() 0371 { 0372 return $this->_definitionConfigName; 0373 } 0374 0375 /** 0376 * @param string $classname 0377 * @return Zend_Db_Table_Abstract Provides a fluent interface 0378 */ 0379 public function setRowClass($classname) 0380 { 0381 $this->_rowClass = (string) $classname; 0382 0383 return $this; 0384 } 0385 0386 /** 0387 * @return string 0388 */ 0389 public function getRowClass() 0390 { 0391 return $this->_rowClass; 0392 } 0393 0394 /** 0395 * @param string $classname 0396 * @return Zend_Db_Table_Abstract Provides a fluent interface 0397 */ 0398 public function setRowsetClass($classname) 0399 { 0400 $this->_rowsetClass = (string) $classname; 0401 0402 return $this; 0403 } 0404 0405 /** 0406 * @return string 0407 */ 0408 public function getRowsetClass() 0409 { 0410 return $this->_rowsetClass; 0411 } 0412 0413 /** 0414 * Add a reference to the reference map 0415 * 0416 * @param string $ruleKey 0417 * @param string|array $columns 0418 * @param string $refTableClass 0419 * @param string|array $refColumns 0420 * @param string $onDelete 0421 * @param string $onUpdate 0422 * @return Zend_Db_Table_Abstract 0423 */ 0424 public function addReference($ruleKey, $columns, $refTableClass, $refColumns, 0425 $onDelete = null, $onUpdate = null) 0426 { 0427 $reference = array(self::COLUMNS => (array) $columns, 0428 self::REF_TABLE_CLASS => $refTableClass, 0429 self::REF_COLUMNS => (array) $refColumns); 0430 0431 if (!empty($onDelete)) { 0432 $reference[self::ON_DELETE] = $onDelete; 0433 } 0434 0435 if (!empty($onUpdate)) { 0436 $reference[self::ON_UPDATE] = $onUpdate; 0437 } 0438 0439 $this->_referenceMap[$ruleKey] = $reference; 0440 0441 return $this; 0442 } 0443 0444 /** 0445 * @param array $referenceMap 0446 * @return Zend_Db_Table_Abstract Provides a fluent interface 0447 */ 0448 public function setReferences(array $referenceMap) 0449 { 0450 $this->_referenceMap = $referenceMap; 0451 0452 return $this; 0453 } 0454 0455 /** 0456 * @param string $tableClassname 0457 * @param string $ruleKey OPTIONAL 0458 * @return array 0459 * @throws Zend_Db_Table_Exception 0460 */ 0461 public function getReference($tableClassname, $ruleKey = null) 0462 { 0463 $thisClass = get_class($this); 0464 if ($thisClass === 'Zend_Db_Table') { 0465 $thisClass = $this->_definitionConfigName; 0466 } 0467 $refMap = $this->_getReferenceMapNormalized(); 0468 if ($ruleKey !== null) { 0469 if (!isset($refMap[$ruleKey])) { 0470 // require_once "Zend/Db/Table/Exception.php"; 0471 throw new Zend_Db_Table_Exception("No reference rule \"$ruleKey\" from table $thisClass to table $tableClassname"); 0472 } 0473 if ($refMap[$ruleKey][self::REF_TABLE_CLASS] != $tableClassname) { 0474 // require_once "Zend/Db/Table/Exception.php"; 0475 throw new Zend_Db_Table_Exception("Reference rule \"$ruleKey\" does not reference table $tableClassname"); 0476 } 0477 return $refMap[$ruleKey]; 0478 } 0479 foreach ($refMap as $reference) { 0480 if ($reference[self::REF_TABLE_CLASS] == $tableClassname) { 0481 return $reference; 0482 } 0483 } 0484 // require_once "Zend/Db/Table/Exception.php"; 0485 throw new Zend_Db_Table_Exception("No reference from table $thisClass to table $tableClassname"); 0486 } 0487 0488 /** 0489 * @param array $dependentTables 0490 * @return Zend_Db_Table_Abstract Provides a fluent interface 0491 */ 0492 public function setDependentTables(array $dependentTables) 0493 { 0494 $this->_dependentTables = $dependentTables; 0495 0496 return $this; 0497 } 0498 0499 /** 0500 * @return array 0501 */ 0502 public function getDependentTables() 0503 { 0504 return $this->_dependentTables; 0505 } 0506 0507 /** 0508 * set the defaultSource property - this tells the table class where to find default values 0509 * 0510 * @param string $defaultSource 0511 * @return Zend_Db_Table_Abstract 0512 */ 0513 public function setDefaultSource($defaultSource = self::DEFAULT_NONE) 0514 { 0515 if (!in_array($defaultSource, array(self::DEFAULT_CLASS, self::DEFAULT_DB, self::DEFAULT_NONE))) { 0516 $defaultSource = self::DEFAULT_NONE; 0517 } 0518 0519 $this->_defaultSource = $defaultSource; 0520 return $this; 0521 } 0522 0523 /** 0524 * returns the default source flag that determines where defaultSources come from 0525 * 0526 * @return unknown 0527 */ 0528 public function getDefaultSource() 0529 { 0530 return $this->_defaultSource; 0531 } 0532 0533 /** 0534 * set the default values for the table class 0535 * 0536 * @param array $defaultValues 0537 * @return Zend_Db_Table_Abstract 0538 */ 0539 public function setDefaultValues(Array $defaultValues) 0540 { 0541 foreach ($defaultValues as $defaultName => $defaultValue) { 0542 if (array_key_exists($defaultName, $this->_metadata)) { 0543 $this->_defaultValues[$defaultName] = $defaultValue; 0544 } 0545 } 0546 return $this; 0547 } 0548 0549 public function getDefaultValues() 0550 { 0551 return $this->_defaultValues; 0552 } 0553 0554 0555 /** 0556 * Sets the default Zend_Db_Adapter_Abstract for all Zend_Db_Table objects. 0557 * 0558 * @param mixed $db Either an Adapter object, or a string naming a Registry key 0559 * @return void 0560 */ 0561 public static function setDefaultAdapter($db = null) 0562 { 0563 self::$_defaultDb = self::_setupAdapter($db); 0564 } 0565 0566 /** 0567 * Gets the default Zend_Db_Adapter_Abstract for all Zend_Db_Table objects. 0568 * 0569 * @return Zend_Db_Adapter_Abstract or null 0570 */ 0571 public static function getDefaultAdapter() 0572 { 0573 return self::$_defaultDb; 0574 } 0575 0576 /** 0577 * @param mixed $db Either an Adapter object, or a string naming a Registry key 0578 * @return Zend_Db_Table_Abstract Provides a fluent interface 0579 */ 0580 protected function _setAdapter($db) 0581 { 0582 $this->_db = self::_setupAdapter($db); 0583 return $this; 0584 } 0585 0586 /** 0587 * Gets the Zend_Db_Adapter_Abstract for this particular Zend_Db_Table object. 0588 * 0589 * @return Zend_Db_Adapter_Abstract 0590 */ 0591 public function getAdapter() 0592 { 0593 return $this->_db; 0594 } 0595 0596 /** 0597 * @param mixed $db Either an Adapter object, or a string naming a Registry key 0598 * @return Zend_Db_Adapter_Abstract 0599 * @throws Zend_Db_Table_Exception 0600 */ 0601 protected static function _setupAdapter($db) 0602 { 0603 if ($db === null) { 0604 return null; 0605 } 0606 if (is_string($db)) { 0607 // require_once 'Zend/Registry.php'; 0608 $db = Zend_Registry::get($db); 0609 } 0610 if (!$db instanceof Zend_Db_Adapter_Abstract) { 0611 // require_once 'Zend/Db/Table/Exception.php'; 0612 throw new Zend_Db_Table_Exception('Argument must be of type Zend_Db_Adapter_Abstract, or a Registry key where a Zend_Db_Adapter_Abstract object is stored'); 0613 } 0614 return $db; 0615 } 0616 0617 /** 0618 * Sets the default metadata cache for information returned by Zend_Db_Adapter_Abstract::describeTable(). 0619 * 0620 * If $defaultMetadataCache is null, then no metadata cache is used by default. 0621 * 0622 * @param mixed $metadataCache Either a Cache object, or a string naming a Registry key 0623 * @return void 0624 */ 0625 public static function setDefaultMetadataCache($metadataCache = null) 0626 { 0627 self::$_defaultMetadataCache = self::_setupMetadataCache($metadataCache); 0628 } 0629 0630 /** 0631 * Gets the default metadata cache for information returned by Zend_Db_Adapter_Abstract::describeTable(). 0632 * 0633 * @return Zend_Cache_Core or null 0634 */ 0635 public static function getDefaultMetadataCache() 0636 { 0637 return self::$_defaultMetadataCache; 0638 } 0639 0640 /** 0641 * Sets the metadata cache for information returned by Zend_Db_Adapter_Abstract::describeTable(). 0642 * 0643 * If $metadataCache is null, then no metadata cache is used. Since there is no opportunity to reload metadata 0644 * after instantiation, this method need not be public, particularly because that it would have no effect 0645 * results in unnecessary API complexity. To configure the metadata cache, use the metadataCache configuration 0646 * option for the class constructor upon instantiation. 0647 * 0648 * @param mixed $metadataCache Either a Cache object, or a string naming a Registry key 0649 * @return Zend_Db_Table_Abstract Provides a fluent interface 0650 */ 0651 protected function _setMetadataCache($metadataCache) 0652 { 0653 $this->_metadataCache = self::_setupMetadataCache($metadataCache); 0654 return $this; 0655 } 0656 0657 /** 0658 * Gets the metadata cache for information returned by Zend_Db_Adapter_Abstract::describeTable(). 0659 * 0660 * @return Zend_Cache_Core or null 0661 */ 0662 public function getMetadataCache() 0663 { 0664 return $this->_metadataCache; 0665 } 0666 0667 /** 0668 * Indicate whether metadata should be cached in the class for the duration 0669 * of the instance 0670 * 0671 * @param bool $flag 0672 * @return Zend_Db_Table_Abstract 0673 */ 0674 public function setMetadataCacheInClass($flag) 0675 { 0676 $this->_metadataCacheInClass = (bool) $flag; 0677 return $this; 0678 } 0679 0680 /** 0681 * Retrieve flag indicating if metadata should be cached for duration of 0682 * instance 0683 * 0684 * @return bool 0685 */ 0686 public function metadataCacheInClass() 0687 { 0688 return $this->_metadataCacheInClass; 0689 } 0690 0691 /** 0692 * @param mixed $metadataCache Either a Cache object, or a string naming a Registry key 0693 * @return Zend_Cache_Core 0694 * @throws Zend_Db_Table_Exception 0695 */ 0696 protected static function _setupMetadataCache($metadataCache) 0697 { 0698 if ($metadataCache === null) { 0699 return null; 0700 } 0701 if (is_string($metadataCache)) { 0702 // require_once 'Zend/Registry.php'; 0703 $metadataCache = Zend_Registry::get($metadataCache); 0704 } 0705 if (!$metadataCache instanceof Zend_Cache_Core) { 0706 // require_once 'Zend/Db/Table/Exception.php'; 0707 throw new Zend_Db_Table_Exception('Argument must be of type Zend_Cache_Core, or a Registry key where a Zend_Cache_Core object is stored'); 0708 } 0709 return $metadataCache; 0710 } 0711 0712 /** 0713 * Sets the sequence member, which defines the behavior for generating 0714 * primary key values in new rows. 0715 * - If this is a string, then the string names the sequence object. 0716 * - If this is boolean true, then the key uses an auto-incrementing 0717 * or identity mechanism. 0718 * - If this is boolean false, then the key is user-defined. 0719 * Use this for natural keys, for example. 0720 * 0721 * @param mixed $sequence 0722 * @return Zend_Db_Table_Adapter_Abstract Provides a fluent interface 0723 */ 0724 protected function _setSequence($sequence) 0725 { 0726 $this->_sequence = $sequence; 0727 0728 return $this; 0729 } 0730 0731 /** 0732 * Turnkey for initialization of a table object. 0733 * Calls other protected methods for individual tasks, to make it easier 0734 * for a subclass to override part of the setup logic. 0735 * 0736 * @return void 0737 */ 0738 protected function _setup() 0739 { 0740 $this->_setupDatabaseAdapter(); 0741 $this->_setupTableName(); 0742 } 0743 0744 /** 0745 * Initialize database adapter. 0746 * 0747 * @return void 0748 * @throws Zend_Db_Table_Exception 0749 */ 0750 protected function _setupDatabaseAdapter() 0751 { 0752 if (! $this->_db) { 0753 $this->_db = self::getDefaultAdapter(); 0754 if (!$this->_db instanceof Zend_Db_Adapter_Abstract) { 0755 // require_once 'Zend/Db/Table/Exception.php'; 0756 throw new Zend_Db_Table_Exception('No adapter found for ' . get_class($this)); 0757 } 0758 } 0759 } 0760 0761 /** 0762 * Initialize table and schema names. 0763 * 0764 * If the table name is not set in the class definition, 0765 * use the class name itself as the table name. 0766 * 0767 * A schema name provided with the table name (e.g., "schema.table") overrides 0768 * any existing value for $this->_schema. 0769 * 0770 * @return void 0771 */ 0772 protected function _setupTableName() 0773 { 0774 if (! $this->_name) { 0775 $this->_name = get_class($this); 0776 } else if (strpos($this->_name, '.')) { 0777 list($this->_schema, $this->_name) = explode('.', $this->_name); 0778 } 0779 } 0780 0781 /** 0782 * Initializes metadata. 0783 * 0784 * If metadata cannot be loaded from cache, adapter's describeTable() method is called to discover metadata 0785 * information. Returns true if and only if the metadata are loaded from cache. 0786 * 0787 * @return boolean 0788 * @throws Zend_Db_Table_Exception 0789 */ 0790 protected function _setupMetadata() 0791 { 0792 if ($this->metadataCacheInClass() && (count($this->_metadata) > 0)) { 0793 return true; 0794 } 0795 0796 // Assume that metadata will be loaded from cache 0797 $isMetadataFromCache = true; 0798 0799 // If $this has no metadata cache but the class has a default metadata cache 0800 if (null === $this->_metadataCache && null !== self::$_defaultMetadataCache) { 0801 // Make $this use the default metadata cache of the class 0802 $this->_setMetadataCache(self::$_defaultMetadataCache); 0803 } 0804 0805 // If $this has a metadata cache 0806 if (null !== $this->_metadataCache) { 0807 // Define the cache identifier where the metadata are saved 0808 0809 //get db configuration 0810 $dbConfig = $this->_db->getConfig(); 0811 0812 $port = isset($dbConfig['options']['port']) 0813 ? ':'.$dbConfig['options']['port'] 0814 : (isset($dbConfig['port']) 0815 ? ':'.$dbConfig['port'] 0816 : null); 0817 0818 $host = isset($dbConfig['options']['host']) 0819 ? ':'.$dbConfig['options']['host'] 0820 : (isset($dbConfig['host']) 0821 ? ':'.$dbConfig['host'] 0822 : null); 0823 0824 // Define the cache identifier where the metadata are saved 0825 $cacheId = md5( // port:host/dbname:schema.table (based on availabilty) 0826 $port . $host . '/'. $dbConfig['dbname'] . ':' 0827 . $this->_schema. '.' . $this->_name 0828 ); 0829 } 0830 0831 // If $this has no metadata cache or metadata cache misses 0832 if (null === $this->_metadataCache || !($metadata = $this->_metadataCache->load($cacheId))) { 0833 // Metadata are not loaded from cache 0834 $isMetadataFromCache = false; 0835 // Fetch metadata from the adapter's describeTable() method 0836 $metadata = $this->_db->describeTable($this->_name, $this->_schema); 0837 // If $this has a metadata cache, then cache the metadata 0838 if (null !== $this->_metadataCache && !$this->_metadataCache->save($metadata, $cacheId)) { 0839 trigger_error('Failed saving metadata to metadataCache', E_USER_NOTICE); 0840 } 0841 } 0842 0843 // Assign the metadata to $this 0844 $this->_metadata = $metadata; 0845 0846 // Return whether the metadata were loaded from cache 0847 return $isMetadataFromCache; 0848 } 0849 0850 /** 0851 * Retrieve table columns 0852 * 0853 * @return array 0854 */ 0855 protected function _getCols() 0856 { 0857 if (null === $this->_cols) { 0858 $this->_setupMetadata(); 0859 $this->_cols = array_keys($this->_metadata); 0860 } 0861 return $this->_cols; 0862 } 0863 0864 /** 0865 * Initialize primary key from metadata. 0866 * If $_primary is not defined, discover primary keys 0867 * from the information returned by describeTable(). 0868 * 0869 * @return void 0870 * @throws Zend_Db_Table_Exception 0871 */ 0872 protected function _setupPrimaryKey() 0873 { 0874 if (!$this->_primary) { 0875 $this->_setupMetadata(); 0876 $this->_primary = array(); 0877 foreach ($this->_metadata as $col) { 0878 if ($col['PRIMARY']) { 0879 $this->_primary[ $col['PRIMARY_POSITION'] ] = $col['COLUMN_NAME']; 0880 if ($col['IDENTITY']) { 0881 $this->_identity = $col['PRIMARY_POSITION']; 0882 } 0883 } 0884 } 0885 // if no primary key was specified and none was found in the metadata 0886 // then throw an exception. 0887 if (empty($this->_primary)) { 0888 // require_once 'Zend/Db/Table/Exception.php'; 0889 throw new Zend_Db_Table_Exception("A table must have a primary key, but none was found for table '{$this->_name}'"); 0890 } 0891 } else if (!is_array($this->_primary)) { 0892 $this->_primary = array(1 => $this->_primary); 0893 } else if (isset($this->_primary[0])) { 0894 array_unshift($this->_primary, null); 0895 unset($this->_primary[0]); 0896 } 0897 0898 $cols = $this->_getCols(); 0899 if (! array_intersect((array) $this->_primary, $cols) == (array) $this->_primary) { 0900 // require_once 'Zend/Db/Table/Exception.php'; 0901 throw new Zend_Db_Table_Exception("Primary key column(s) (" 0902 . implode(',', (array) $this->_primary) 0903 . ") are not columns in this table (" 0904 . implode(',', $cols) 0905 . ")"); 0906 } 0907 0908 $primary = (array) $this->_primary; 0909 $pkIdentity = $primary[(int) $this->_identity]; 0910 0911 /** 0912 * Special case for PostgreSQL: a SERIAL key implicitly uses a sequence 0913 * object whose name is "<table>_<column>_seq". 0914 */ 0915 if ($this->_sequence === true && $this->_db instanceof Zend_Db_Adapter_Pdo_Pgsql) { 0916 $this->_sequence = $this->_db->quoteIdentifier("{$this->_name}_{$pkIdentity}_seq"); 0917 if ($this->_schema) { 0918 $this->_sequence = $this->_db->quoteIdentifier($this->_schema) . '.' . $this->_sequence; 0919 } 0920 } 0921 } 0922 0923 /** 0924 * Returns a normalized version of the reference map 0925 * 0926 * @return array 0927 */ 0928 protected function _getReferenceMapNormalized() 0929 { 0930 $referenceMapNormalized = array(); 0931 0932 foreach ($this->_referenceMap as $rule => $map) { 0933 0934 $referenceMapNormalized[$rule] = array(); 0935 0936 foreach ($map as $key => $value) { 0937 switch ($key) { 0938 0939 // normalize COLUMNS and REF_COLUMNS to arrays 0940 case self::COLUMNS: 0941 case self::REF_COLUMNS: 0942 if (!is_array($value)) { 0943 $referenceMapNormalized[$rule][$key] = array($value); 0944 } else { 0945 $referenceMapNormalized[$rule][$key] = $value; 0946 } 0947 break; 0948 0949 // other values are copied as-is 0950 default: 0951 $referenceMapNormalized[$rule][$key] = $value; 0952 break; 0953 } 0954 } 0955 } 0956 0957 return $referenceMapNormalized; 0958 } 0959 0960 /** 0961 * Initialize object 0962 * 0963 * Called from {@link __construct()} as final step of object instantiation. 0964 * 0965 * @return void 0966 */ 0967 public function init() 0968 { 0969 } 0970 0971 /** 0972 * Returns table information. 0973 * 0974 * You can elect to return only a part of this information by supplying its key name, 0975 * otherwise all information is returned as an array. 0976 * 0977 * @param string $key The specific info part to return OPTIONAL 0978 * @return mixed 0979 * @throws Zend_Db_Table_Exception 0980 */ 0981 public function info($key = null) 0982 { 0983 $this->_setupPrimaryKey(); 0984 0985 $info = array( 0986 self::SCHEMA => $this->_schema, 0987 self::NAME => $this->_name, 0988 self::COLS => $this->_getCols(), 0989 self::PRIMARY => (array) $this->_primary, 0990 self::METADATA => $this->_metadata, 0991 self::ROW_CLASS => $this->getRowClass(), 0992 self::ROWSET_CLASS => $this->getRowsetClass(), 0993 self::REFERENCE_MAP => $this->_referenceMap, 0994 self::DEPENDENT_TABLES => $this->_dependentTables, 0995 self::SEQUENCE => $this->_sequence 0996 ); 0997 0998 if ($key === null) { 0999 return $info; 1000 } 1001 1002 if (!array_key_exists($key, $info)) { 1003 // require_once 'Zend/Db/Table/Exception.php'; 1004 throw new Zend_Db_Table_Exception('There is no table information for the key "' . $key . '"'); 1005 } 1006 1007 return $info[$key]; 1008 } 1009 1010 /** 1011 * Returns an instance of a Zend_Db_Table_Select object. 1012 * 1013 * @param bool $withFromPart Whether or not to include the from part of the select based on the table 1014 * @return Zend_Db_Table_Select 1015 */ 1016 public function select($withFromPart = self::SELECT_WITHOUT_FROM_PART) 1017 { 1018 // require_once 'Zend/Db/Table/Select.php'; 1019 $select = new Zend_Db_Table_Select($this); 1020 if ($withFromPart == self::SELECT_WITH_FROM_PART) { 1021 $select->from($this->info(self::NAME), Zend_Db_Table_Select::SQL_WILDCARD, $this->info(self::SCHEMA)); 1022 } 1023 return $select; 1024 } 1025 1026 /** 1027 * Inserts a new row. 1028 * 1029 * @param array $data Column-value pairs. 1030 * @return mixed The primary key of the row inserted. 1031 */ 1032 public function insert(array $data) 1033 { 1034 $this->_setupPrimaryKey(); 1035 1036 /** 1037 * Zend_Db_Table assumes that if you have a compound primary key 1038 * and one of the columns in the key uses a sequence, 1039 * it's the _first_ column in the compound key. 1040 */ 1041 $primary = (array) $this->_primary; 1042 $pkIdentity = $primary[(int)$this->_identity]; 1043 1044 1045 /** 1046 * If the primary key can be generated automatically, and no value was 1047 * specified in the user-supplied data, then omit it from the tuple. 1048 * 1049 * Note: this checks for sensible values in the supplied primary key 1050 * position of the data. The following values are considered empty: 1051 * null, false, true, '', array() 1052 */ 1053 if (array_key_exists($pkIdentity, $data)) { 1054 if ($data[$pkIdentity] === null // null 1055 || $data[$pkIdentity] === '' // empty string 1056 || is_bool($data[$pkIdentity]) // boolean 1057 || (is_array($data[$pkIdentity]) && empty($data[$pkIdentity]))) { // empty array 1058 unset($data[$pkIdentity]); 1059 } 1060 } 1061 1062 /** 1063 * If this table uses a database sequence object and the data does not 1064 * specify a value, then get the next ID from the sequence and add it 1065 * to the row. We assume that only the first column in a compound 1066 * primary key takes a value from a sequence. 1067 */ 1068 if (is_string($this->_sequence) && !isset($data[$pkIdentity])) { 1069 $data[$pkIdentity] = $this->_db->nextSequenceId($this->_sequence); 1070 } 1071 1072 /** 1073 * INSERT the new row. 1074 */ 1075 $tableSpec = ($this->_schema ? $this->_schema . '.' : '') . $this->_name; 1076 $this->_db->insert($tableSpec, $data); 1077 1078 /** 1079 * Fetch the most recent ID generated by an auto-increment 1080 * or IDENTITY column, unless the user has specified a value, 1081 * overriding the auto-increment mechanism. 1082 */ 1083 if ($this->_sequence === true && !isset($data[$pkIdentity])) { 1084 $data[$pkIdentity] = $this->_db->lastInsertId(); 1085 } 1086 1087 /** 1088 * Return the primary key value if the PK is a single column, 1089 * else return an associative array of the PK column/value pairs. 1090 */ 1091 $pkData = array_intersect_key($data, array_flip($primary)); 1092 if (count($primary) == 1) { 1093 reset($pkData); 1094 return current($pkData); 1095 } 1096 1097 return $pkData; 1098 } 1099 1100 /** 1101 * Check if the provided column is an identity of the table 1102 * 1103 * @param string $column 1104 * @throws Zend_Db_Table_Exception 1105 * @return boolean 1106 */ 1107 public function isIdentity($column) 1108 { 1109 $this->_setupPrimaryKey(); 1110 1111 if (!isset($this->_metadata[$column])) { 1112 /** 1113 * @see Zend_Db_Table_Exception 1114 */ 1115 // require_once 'Zend/Db/Table/Exception.php'; 1116 1117 throw new Zend_Db_Table_Exception('Column "' . $column . '" not found in table.'); 1118 } 1119 1120 return (bool) $this->_metadata[$column]['IDENTITY']; 1121 } 1122 1123 /** 1124 * Updates existing rows. 1125 * 1126 * @param array $data Column-value pairs. 1127 * @param array|string $where An SQL WHERE clause, or an array of SQL WHERE clauses. 1128 * @return int The number of rows updated. 1129 */ 1130 public function update(array $data, $where) 1131 { 1132 $tableSpec = ($this->_schema ? $this->_schema . '.' : '') . $this->_name; 1133 return $this->_db->update($tableSpec, $data, $where); 1134 } 1135 1136 /** 1137 * Called by a row object for the parent table's class during save() method. 1138 * 1139 * @param string $parentTableClassname 1140 * @param array $oldPrimaryKey 1141 * @param array $newPrimaryKey 1142 * @return int 1143 */ 1144 public function _cascadeUpdate($parentTableClassname, array $oldPrimaryKey, array $newPrimaryKey) 1145 { 1146 $this->_setupMetadata(); 1147 $rowsAffected = 0; 1148 foreach ($this->_getReferenceMapNormalized() as $map) { 1149 if ($map[self::REF_TABLE_CLASS] == $parentTableClassname && isset($map[self::ON_UPDATE])) { 1150 switch ($map[self::ON_UPDATE]) { 1151 case self::CASCADE: 1152 $newRefs = array(); 1153 $where = array(); 1154 for ($i = 0; $i < count($map[self::COLUMNS]); ++$i) { 1155 $col = $this->_db->foldCase($map[self::COLUMNS][$i]); 1156 $refCol = $this->_db->foldCase($map[self::REF_COLUMNS][$i]); 1157 if (array_key_exists($refCol, $newPrimaryKey)) { 1158 $newRefs[$col] = $newPrimaryKey[$refCol]; 1159 } 1160 $type = $this->_metadata[$col]['DATA_TYPE']; 1161 $where[] = $this->_db->quoteInto( 1162 $this->_db->quoteIdentifier($col, true) . ' = ?', 1163 $oldPrimaryKey[$refCol], $type); 1164 } 1165 $rowsAffected += $this->update($newRefs, $where); 1166 break; 1167 default: 1168 // no action 1169 break; 1170 } 1171 } 1172 } 1173 return $rowsAffected; 1174 } 1175 1176 /** 1177 * Deletes existing rows. 1178 * 1179 * @param array|string $where SQL WHERE clause(s). 1180 * @return int The number of rows deleted. 1181 */ 1182 public function delete($where) 1183 { 1184 $depTables = $this->getDependentTables(); 1185 if (!empty($depTables)) { 1186 $resultSet = $this->fetchAll($where); 1187 if (count($resultSet) > 0 ) { 1188 foreach ($resultSet as $row) { 1189 /** 1190 * Execute cascading deletes against dependent tables 1191 */ 1192 foreach ($depTables as $tableClass) { 1193 $t = self::getTableFromString($tableClass, $this); 1194 $t->_cascadeDelete( 1195 get_class($this), $row->getPrimaryKey() 1196 ); 1197 } 1198 } 1199 } 1200 } 1201 1202 $tableSpec = ($this->_schema ? $this->_schema . '.' : '') . $this->_name; 1203 return $this->_db->delete($tableSpec, $where); 1204 } 1205 1206 /** 1207 * Called by parent table's class during delete() method. 1208 * 1209 * @param string $parentTableClassname 1210 * @param array $primaryKey 1211 * @return int Number of affected rows 1212 */ 1213 public function _cascadeDelete($parentTableClassname, array $primaryKey) 1214 { 1215 // setup metadata 1216 $this->_setupMetadata(); 1217 1218 // get this class name 1219 $thisClass = get_class($this); 1220 if ($thisClass === 'Zend_Db_Table') { 1221 $thisClass = $this->_definitionConfigName; 1222 } 1223 1224 $rowsAffected = 0; 1225 1226 foreach ($this->_getReferenceMapNormalized() as $map) { 1227 if ($map[self::REF_TABLE_CLASS] == $parentTableClassname && isset($map[self::ON_DELETE])) { 1228 1229 $where = array(); 1230 1231 // CASCADE or CASCADE_RECURSE 1232 if (in_array($map[self::ON_DELETE], array(self::CASCADE, self::CASCADE_RECURSE))) { 1233 for ($i = 0; $i < count($map[self::COLUMNS]); ++$i) { 1234 $col = $this->_db->foldCase($map[self::COLUMNS][$i]); 1235 $refCol = $this->_db->foldCase($map[self::REF_COLUMNS][$i]); 1236 $type = $this->_metadata[$col]['DATA_TYPE']; 1237 $where[] = $this->_db->quoteInto( 1238 $this->_db->quoteIdentifier($col, true) . ' = ?', 1239 $primaryKey[$refCol], $type); 1240 } 1241 } 1242 1243 // CASCADE_RECURSE 1244 if ($map[self::ON_DELETE] == self::CASCADE_RECURSE) { 1245 1246 /** 1247 * Execute cascading deletes against dependent tables 1248 */ 1249 $depTables = $this->getDependentTables(); 1250 if (!empty($depTables)) { 1251 foreach ($depTables as $tableClass) { 1252 $t = self::getTableFromString($tableClass, $this); 1253 foreach ($this->fetchAll($where) as $depRow) { 1254 $rowsAffected += $t->_cascadeDelete($thisClass, $depRow->getPrimaryKey()); 1255 } 1256 } 1257 } 1258 } 1259 1260 // CASCADE or CASCADE_RECURSE 1261 if (in_array($map[self::ON_DELETE], array(self::CASCADE, self::CASCADE_RECURSE))) { 1262 $rowsAffected += $this->delete($where); 1263 } 1264 1265 } 1266 } 1267 return $rowsAffected; 1268 } 1269 1270 /** 1271 * Fetches rows by primary key. The argument specifies one or more primary 1272 * key value(s). To find multiple rows by primary key, the argument must 1273 * be an array. 1274 * 1275 * This method accepts a variable number of arguments. If the table has a 1276 * multi-column primary key, the number of arguments must be the same as 1277 * the number of columns in the primary key. To find multiple rows in a 1278 * table with a multi-column primary key, each argument must be an array 1279 * with the same number of elements. 1280 * 1281 * The find() method always returns a Rowset object, even if only one row 1282 * was found. 1283 * 1284 * @param mixed $key The value(s) of the primary keys. 1285 * @return Zend_Db_Table_Rowset_Abstract Row(s) matching the criteria. 1286 * @throws Zend_Db_Table_Exception 1287 */ 1288 public function find() 1289 { 1290 $this->_setupPrimaryKey(); 1291 $args = func_get_args(); 1292 $keyNames = array_values((array) $this->_primary); 1293 1294 if (count($args) < count($keyNames)) { 1295 // require_once 'Zend/Db/Table/Exception.php'; 1296 throw new Zend_Db_Table_Exception("Too few columns for the primary key"); 1297 } 1298 1299 if (count($args) > count($keyNames)) { 1300 // require_once 'Zend/Db/Table/Exception.php'; 1301 throw new Zend_Db_Table_Exception("Too many columns for the primary key"); 1302 } 1303 1304 $whereList = array(); 1305 $numberTerms = 0; 1306 foreach ($args as $keyPosition => $keyValues) { 1307 $keyValuesCount = count($keyValues); 1308 // Coerce the values to an array. 1309 // Don't simply typecast to array, because the values 1310 // might be Zend_Db_Expr objects. 1311 if (!is_array($keyValues)) { 1312 $keyValues = array($keyValues); 1313 } 1314 if ($numberTerms == 0) { 1315 $numberTerms = $keyValuesCount; 1316 } else if ($keyValuesCount != $numberTerms) { 1317 // require_once 'Zend/Db/Table/Exception.php'; 1318 throw new Zend_Db_Table_Exception("Missing value(s) for the primary key"); 1319 } 1320 $keyValues = array_values($keyValues); 1321 for ($i = 0; $i < $keyValuesCount; ++$i) { 1322 if (!isset($whereList[$i])) { 1323 $whereList[$i] = array(); 1324 } 1325 $whereList[$i][$keyPosition] = $keyValues[$i]; 1326 } 1327 } 1328 1329 $whereClause = null; 1330 if (count($whereList)) { 1331 $whereOrTerms = array(); 1332 $tableName = $this->_db->quoteTableAs($this->_name, null, true); 1333 foreach ($whereList as $keyValueSets) { 1334 $whereAndTerms = array(); 1335 foreach ($keyValueSets as $keyPosition => $keyValue) { 1336 $type = $this->_metadata[$keyNames[$keyPosition]]['DATA_TYPE']; 1337 $columnName = $this->_db->quoteIdentifier($keyNames[$keyPosition], true); 1338 $whereAndTerms[] = $this->_db->quoteInto( 1339 $tableName . '.' . $columnName . ' = ?', 1340 $keyValue, $type); 1341 } 1342 $whereOrTerms[] = '(' . implode(' AND ', $whereAndTerms) . ')'; 1343 } 1344 $whereClause = '(' . implode(' OR ', $whereOrTerms) . ')'; 1345 } 1346 1347 // issue ZF-5775 (empty where clause should return empty rowset) 1348 if ($whereClause == null) { 1349 $rowsetClass = $this->getRowsetClass(); 1350 if (!class_exists($rowsetClass)) { 1351 // require_once 'Zend/Loader.php'; 1352 Zend_Loader::loadClass($rowsetClass); 1353 } 1354 return new $rowsetClass(array('table' => $this, 'rowClass' => $this->getRowClass(), 'stored' => true)); 1355 } 1356 1357 return $this->fetchAll($whereClause); 1358 } 1359 1360 /** 1361 * Fetches all rows. 1362 * 1363 * Honors the Zend_Db_Adapter fetch mode. 1364 * 1365 * @param string|array|Zend_Db_Table_Select $where OPTIONAL An SQL WHERE clause or Zend_Db_Table_Select object. 1366 * @param string|array $order OPTIONAL An SQL ORDER clause. 1367 * @param int $count OPTIONAL An SQL LIMIT count. 1368 * @param int $offset OPTIONAL An SQL LIMIT offset. 1369 * @return Zend_Db_Table_Rowset_Abstract The row results per the Zend_Db_Adapter fetch mode. 1370 */ 1371 public function fetchAll($where = null, $order = null, $count = null, $offset = null) 1372 { 1373 if (!($where instanceof Zend_Db_Table_Select)) { 1374 $select = $this->select(); 1375 1376 if ($where !== null) { 1377 $this->_where($select, $where); 1378 } 1379 1380 if ($order !== null) { 1381 $this->_order($select, $order); 1382 } 1383 1384 if ($count !== null || $offset !== null) { 1385 $select->limit($count, $offset); 1386 } 1387 1388 } else { 1389 $select = $where; 1390 } 1391 1392 $rows = $this->_fetch($select); 1393 1394 $data = array( 1395 'table' => $this, 1396 'data' => $rows, 1397 'readOnly' => $select->isReadOnly(), 1398 'rowClass' => $this->getRowClass(), 1399 'stored' => true 1400 ); 1401 1402 $rowsetClass = $this->getRowsetClass(); 1403 if (!class_exists($rowsetClass)) { 1404 // require_once 'Zend/Loader.php'; 1405 Zend_Loader::loadClass($rowsetClass); 1406 } 1407 return new $rowsetClass($data); 1408 } 1409 1410 /** 1411 * Fetches one row in an object of type Zend_Db_Table_Row_Abstract, 1412 * or returns null if no row matches the specified criteria. 1413 * 1414 * @param string|array|Zend_Db_Table_Select $where OPTIONAL An SQL WHERE clause or Zend_Db_Table_Select object. 1415 * @param string|array $order OPTIONAL An SQL ORDER clause. 1416 * @param int $offset OPTIONAL An SQL OFFSET value. 1417 * @return Zend_Db_Table_Row_Abstract|null The row results per the 1418 * Zend_Db_Adapter fetch mode, or null if no row found. 1419 */ 1420 public function fetchRow($where = null, $order = null, $offset = null) 1421 { 1422 if (!($where instanceof Zend_Db_Table_Select)) { 1423 $select = $this->select(); 1424 1425 if ($where !== null) { 1426 $this->_where($select, $where); 1427 } 1428 1429 if ($order !== null) { 1430 $this->_order($select, $order); 1431 } 1432 1433 $select->limit(1, ((is_numeric($offset)) ? (int) $offset : null)); 1434 1435 } else { 1436 $select = $where->limit(1, $where->getPart(Zend_Db_Select::LIMIT_OFFSET)); 1437 } 1438 1439 $rows = $this->_fetch($select); 1440 1441 if (count($rows) == 0) { 1442 return null; 1443 } 1444 1445 $data = array( 1446 'table' => $this, 1447 'data' => $rows[0], 1448 'readOnly' => $select->isReadOnly(), 1449 'stored' => true 1450 ); 1451 1452 $rowClass = $this->getRowClass(); 1453 if (!class_exists($rowClass)) { 1454 // require_once 'Zend/Loader.php'; 1455 Zend_Loader::loadClass($rowClass); 1456 } 1457 return new $rowClass($data); 1458 } 1459 1460 /** 1461 * Fetches a new blank row (not from the database). 1462 * 1463 * @return Zend_Db_Table_Row_Abstract 1464 * @deprecated since 0.9.3 - use createRow() instead. 1465 */ 1466 public function fetchNew() 1467 { 1468 return $this->createRow(); 1469 } 1470 1471 /** 1472 * Fetches a new blank row (not from the database). 1473 * 1474 * @param array $data OPTIONAL data to populate in the new row. 1475 * @param string $defaultSource OPTIONAL flag to force default values into new row 1476 * @return Zend_Db_Table_Row_Abstract 1477 */ 1478 public function createRow(array $data = array(), $defaultSource = null) 1479 { 1480 $cols = $this->_getCols(); 1481 $defaults = array_combine($cols, array_fill(0, count($cols), null)); 1482 1483 // nothing provided at call-time, take the class value 1484 if ($defaultSource == null) { 1485 $defaultSource = $this->_defaultSource; 1486 } 1487 1488 if (!in_array($defaultSource, array(self::DEFAULT_CLASS, self::DEFAULT_DB, self::DEFAULT_NONE))) { 1489 $defaultSource = self::DEFAULT_NONE; 1490 } 1491 1492 if ($defaultSource == self::DEFAULT_DB) { 1493 foreach ($this->_metadata as $metadataName => $metadata) { 1494 if (($metadata['DEFAULT'] != null) && 1495 ($metadata['NULLABLE'] !== true || ($metadata['NULLABLE'] === true && isset($this->_defaultValues[$metadataName]) && $this->_defaultValues[$metadataName] === true)) && 1496 (!(isset($this->_defaultValues[$metadataName]) && $this->_defaultValues[$metadataName] === false))) { 1497 $defaults[$metadataName] = $metadata['DEFAULT']; 1498 } 1499 } 1500 } elseif ($defaultSource == self::DEFAULT_CLASS && $this->_defaultValues) { 1501 foreach ($this->_defaultValues as $defaultName => $defaultValue) { 1502 if (array_key_exists($defaultName, $defaults)) { 1503 $defaults[$defaultName] = $defaultValue; 1504 } 1505 } 1506 } 1507 1508 $config = array( 1509 'table' => $this, 1510 'data' => $defaults, 1511 'readOnly' => false, 1512 'stored' => false 1513 ); 1514 1515 $rowClass = $this->getRowClass(); 1516 if (!class_exists($rowClass)) { 1517 // require_once 'Zend/Loader.php'; 1518 Zend_Loader::loadClass($rowClass); 1519 } 1520 $row = new $rowClass($config); 1521 $row->setFromArray($data); 1522 return $row; 1523 } 1524 1525 /** 1526 * Generate WHERE clause from user-supplied string or array 1527 * 1528 * @param string|array $where OPTIONAL An SQL WHERE clause. 1529 * @return Zend_Db_Table_Select 1530 */ 1531 protected function _where(Zend_Db_Table_Select $select, $where) 1532 { 1533 $where = (array) $where; 1534 1535 foreach ($where as $key => $val) { 1536 // is $key an int? 1537 if (is_int($key)) { 1538 // $val is the full condition 1539 $select->where($val); 1540 } else { 1541 // $key is the condition with placeholder, 1542 // and $val is quoted into the condition 1543 $select->where($key, $val); 1544 } 1545 } 1546 1547 return $select; 1548 } 1549 1550 /** 1551 * Generate ORDER clause from user-supplied string or array 1552 * 1553 * @param string|array $order OPTIONAL An SQL ORDER clause. 1554 * @return Zend_Db_Table_Select 1555 */ 1556 protected function _order(Zend_Db_Table_Select $select, $order) 1557 { 1558 if (!is_array($order)) { 1559 $order = array($order); 1560 } 1561 1562 foreach ($order as $val) { 1563 $select->order($val); 1564 } 1565 1566 return $select; 1567 } 1568 1569 /** 1570 * Support method for fetching rows. 1571 * 1572 * @param Zend_Db_Table_Select $select query options. 1573 * @return array An array containing the row results in FETCH_ASSOC mode. 1574 */ 1575 protected function _fetch(Zend_Db_Table_Select $select) 1576 { 1577 $stmt = $this->_db->query($select); 1578 $data = $stmt->fetchAll(Zend_Db::FETCH_ASSOC); 1579 return $data; 1580 } 1581 1582 /** 1583 * Get table gateway object from string 1584 * 1585 * @param string $tableName 1586 * @param Zend_Db_Table_Abstract $referenceTable 1587 * @throws Zend_Db_Table_Row_Exception 1588 * @return Zend_Db_Table_Abstract 1589 */ 1590 public static function getTableFromString($tableName, Zend_Db_Table_Abstract $referenceTable = null) 1591 { 1592 if ($referenceTable instanceof Zend_Db_Table_Abstract) { 1593 $tableDefinition = $referenceTable->getDefinition(); 1594 1595 if ($tableDefinition !== null && $tableDefinition->hasTableConfig($tableName)) { 1596 return new Zend_Db_Table($tableName, $tableDefinition); 1597 } 1598 } 1599 1600 // assume the tableName is the class name 1601 if (!class_exists($tableName)) { 1602 try { 1603 // require_once 'Zend/Loader.php'; 1604 Zend_Loader::loadClass($tableName); 1605 } catch (Zend_Exception $e) { 1606 // require_once 'Zend/Db/Table/Row/Exception.php'; 1607 throw new Zend_Db_Table_Row_Exception($e->getMessage(), $e->getCode(), $e); 1608 } 1609 } 1610 1611 $options = array(); 1612 1613 if ($referenceTable instanceof Zend_Db_Table_Abstract) { 1614 $options['db'] = $referenceTable->getAdapter(); 1615 } 1616 1617 if (isset($tableDefinition) && $tableDefinition !== null) { 1618 $options[Zend_Db_Table_Abstract::DEFINITION] = $tableDefinition; 1619 } 1620 1621 return new $tableName($options); 1622 } 1623 1624 }