PluginProbe
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.0.3
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.0.3
5.13.0 5.12.1 5.12.0 5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 All 83 releases
matomo / app / libs / Zend / Db / Table / Abstract.php
Abstract.php
1,535 lines 49.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Zend Framework
4 *
5 * LICENSE
6 *
7 * This source file is subject to the new BSD license that is bundled
8 * with this package in the file LICENSE.txt.
9 * It is also available through the world-wide-web at this URL:
10 * http://framework.zend.com/license/new-bsd
11 * If you did not receive a copy of the license and are unable to
12 * obtain it through the world-wide-web, please send an email
13 * to license@zend.com so we can send you a copy immediately.
14 *
15 * @category Zend
16 * @package Zend_Db
17 * @subpackage Table
18 * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
19 * @license http://framework.zend.com/license/new-bsd New BSD License
20 * @version $Id: Abstract.php 24148 2011-06-21 15:14:00Z yoshida@zend.co.jp $
21 */
22
23 /**
24 * @see Zend_Db_Adapter_Abstract
25 */
26 // require_once 'Zend/Db/Adapter/Abstract.php';
27
28 /**
29 * @see Zend_Db_Adapter_Abstract
30 */
31 // require_once 'Zend/Db/Select.php';
32
33 /**
34 * @see Zend_Db
35 */
36 // require_once 'Zend/Db.php';
37
38 /**
39 * Class for SQL table interface.
40 *
41 * @category Zend
42 * @package Zend_Db
43 * @subpackage Table
44 * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
45 * @license http://framework.zend.com/license/new-bsd New BSD License
46 */
47 abstract class Zend_Db_Table_Abstract
48 {
49
50 const ADAPTER = 'db';
51 const DEFINITION = 'definition';
52 const DEFINITION_CONFIG_NAME = 'definitionConfigName';
53 const SCHEMA = 'schema';
54 const NAME = 'name';
55 const PRIMARY = 'primary';
56 const COLS = 'cols';
57 const METADATA = 'metadata';
58 const METADATA_CACHE = 'metadataCache';
59 const METADATA_CACHE_IN_CLASS = 'metadataCacheInClass';
60 const ROW_CLASS = 'rowClass';
61 const ROWSET_CLASS = 'rowsetClass';
62 const REFERENCE_MAP = 'referenceMap';
63 const DEPENDENT_TABLES = 'dependentTables';
64 const SEQUENCE = 'sequence';
65
66 const COLUMNS = 'columns';
67 const REF_TABLE_CLASS = 'refTableClass';
68 const REF_COLUMNS = 'refColumns';
69 const ON_DELETE = 'onDelete';
70 const ON_UPDATE = 'onUpdate';
71
72 const CASCADE = 'cascade';
73 const RESTRICT = 'restrict';
74 const SET_NULL = 'setNull';
75
76 const DEFAULT_NONE = 'defaultNone';
77 const DEFAULT_CLASS = 'defaultClass';
78 const DEFAULT_DB = 'defaultDb';
79
80 const SELECT_WITH_FROM_PART = true;
81 const SELECT_WITHOUT_FROM_PART = false;
82
83 /**
84 * Default Zend_Db_Adapter_Abstract object.
85 *
86 * @var Zend_Db_Adapter_Abstract
87 */
88 protected static $_defaultDb;
89
90 /**
91 * Optional Zend_Db_Table_Definition object
92 *
93 * @var unknown_type
94 */
95 protected $_definition = null;
96
97 /**
98 * Optional definition config name used in concrete implementation
99 *
100 * @var string
101 */
102 protected $_definitionConfigName = null;
103
104 /**
105 * Default cache for information provided by the adapter's describeTable() method.
106 *
107 * @var Zend_Cache_Core
108 */
109 protected static $_defaultMetadataCache = null;
110
111 /**
112 * Zend_Db_Adapter_Abstract object.
113 *
114 * @var Zend_Db_Adapter_Abstract
115 */
116 protected $_db;
117
118 /**
119 * The schema name (default null means current schema)
120 *
121 * @var array
122 */
123 protected $_schema = null;
124
125 /**
126 * The table name.
127 *
128 * @var string
129 */
130 protected $_name = null;
131
132 /**
133 * The table column names derived from Zend_Db_Adapter_Abstract::describeTable().
134 *
135 * @var array
136 */
137 protected $_cols;
138
139 /**
140 * The primary key column or columns.
141 * A compound key should be declared as an array.
142 * You may declare a single-column primary key
143 * as a string.
144 *
145 * @var mixed
146 */
147 protected $_primary = null;
148
149 /**
150 * If your primary key is a compound key, and one of the columns uses
151 * an auto-increment or sequence-generated value, set _identity
152 * to the ordinal index in the $_primary array for that column.
153 * Note this index is the position of the column in the primary key,
154 * not the position of the column in the table. The primary key
155 * array is 1-based.
156 *
157 * @var integer
158 */
159 protected $_identity = 1;
160
161 /**
162 * Define the logic for new values in the primary key.
163 * May be a string, boolean true, or boolean false.
164 *
165 * @var mixed
166 */
167 protected $_sequence = true;
168
169 /**
170 * Information provided by the adapter's describeTable() method.
171 *
172 * @var array
173 */
174 protected $_metadata = array();
175
176 /**
177 * Cache for information provided by the adapter's describeTable() method.
178 *
179 * @var Zend_Cache_Core
180 */
181 protected $_metadataCache = null;
182
183 /**
184 * Flag: whether or not to cache metadata in the class
185 * @var bool
186 */
187 protected $_metadataCacheInClass = true;
188
189 /**
190 * Classname for row
191 *
192 * @var string
193 */
194 protected $_rowClass = 'Zend_Db_Table_Row';
195
196 /**
197 * Classname for rowset
198 *
199 * @var string
200 */
201 protected $_rowsetClass = 'Zend_Db_Table_Rowset';
202
203 /**
204 * Associative array map of declarative referential integrity rules.
205 * This array has one entry per foreign key in the current table.
206 * Each key is a mnemonic name for one reference rule.
207 *
208 * Each value is also an associative array, with the following keys:
209 * - columns = array of names of column(s) in the child table.
210 * - refTableClass = class name of the parent table.
211 * - refColumns = array of names of column(s) in the parent table,
212 * in the same order as those in the 'columns' entry.
213 * - onDelete = "cascade" means that a delete in the parent table also
214 * causes a delete of referencing rows in the child table.
215 * - onUpdate = "cascade" means that an update of primary key values in
216 * the parent table also causes an update of referencing
217 * rows in the child table.
218 *
219 * @var array
220 */
221 protected $_referenceMap = array();
222
223 /**
224 * Simple array of class names of tables that are "children" of the current
225 * table, in other words tables that contain a foreign key to this one.
226 * Array elements are not table names; they are class names of classes that
227 * extend Zend_Db_Table_Abstract.
228 *
229 * @var array
230 */
231 protected $_dependentTables = array();
232
233
234 protected $_defaultSource = self::DEFAULT_NONE;
235 protected $_defaultValues = array();
236
237 /**
238 * Constructor.
239 *
240 * Supported params for $config are:
241 * - db = user-supplied instance of database connector,
242 * or key name of registry instance.
243 * - name = table name.
244 * - primary = string or array of primary key(s).
245 * - rowClass = row class name.
246 * - rowsetClass = rowset class name.
247 * - referenceMap = array structure to declare relationship
248 * to parent tables.
249 * - dependentTables = array of child tables.
250 * - metadataCache = cache for information from adapter describeTable().
251 *
252 * @param mixed $config Array of user-specified config options, or just the Db Adapter.
253 * @return void
254 */
255 public function __construct($config = array())
256 {
257 /**
258 * Allow a scalar argument to be the Adapter object or Registry key.
259 */
260 if (!is_array($config)) {
261 $config = array(self::ADAPTER => $config);
262 }
263
264 if ($config) {
265 $this->setOptions($config);
266 }
267
268 $this->_setup();
269 $this->init();
270 }
271
272 /**
273 * setOptions()
274 *
275 * @param array $options
276 * @return Zend_Db_Table_Abstract
277 */
278 public function setOptions(Array $options)
279 {
280 foreach ($options as $key => $value) {
281 switch ($key) {
282 case self::ADAPTER:
283 $this->_setAdapter($value);
284 break;
285 case self::DEFINITION:
286 $this->setDefinition($value);
287 break;
288 case self::DEFINITION_CONFIG_NAME:
289 $this->setDefinitionConfigName($value);
290 break;
291 case self::SCHEMA:
292 $this->_schema = (string) $value;
293 break;
294 case self::NAME:
295 $this->_name = (string) $value;
296 break;
297 case self::PRIMARY:
298 $this->_primary = (array) $value;
299 break;
300 case self::ROW_CLASS:
301 $this->setRowClass($value);
302 break;
303 case self::ROWSET_CLASS:
304 $this->setRowsetClass($value);
305 break;
306 case self::REFERENCE_MAP:
307 $this->setReferences($value);
308 break;
309 case self::DEPENDENT_TABLES:
310 $this->setDependentTables($value);
311 break;
312 case self::METADATA_CACHE:
313 $this->_setMetadataCache($value);
314 break;
315 case self::METADATA_CACHE_IN_CLASS:
316 $this->setMetadataCacheInClass($value);
317 break;
318 case self::SEQUENCE:
319 $this->_setSequence($value);
320 break;
321 default:
322 // ignore unrecognized configuration directive
323 break;
324 }
325 }
326
327 return $this;
328 }
329
330 /**
331 * setDefinition()
332 *
333 * @param Zend_Db_Table_Definition $definition
334 * @return Zend_Db_Table_Abstract
335 */
336 public function setDefinition(Zend_Db_Table_Definition $definition)
337 {
338 $this->_definition = $definition;
339 return $this;
340 }
341
342 /**
343 * getDefinition()
344 *
345 * @return Zend_Db_Table_Definition|null
346 */
347 public function getDefinition()
348 {
349 return $this->_definition;
350 }
351
352 /**
353 * setDefinitionConfigName()
354 *
355 * @param string $definition
356 * @return Zend_Db_Table_Abstract
357 */
358 public function setDefinitionConfigName($definitionConfigName)
359 {
360 $this->_definitionConfigName = $definitionConfigName;
361 return $this;
362 }
363
364 /**
365 * getDefinitionConfigName()
366 *
367 * @return string
368 */
369 public function getDefinitionConfigName()
370 {
371 return $this->_definitionConfigName;
372 }
373
374 /**
375 * @param string $classname
376 * @return Zend_Db_Table_Abstract Provides a fluent interface
377 */
378 public function setRowClass($classname)
379 {
380 $this->_rowClass = (string) $classname;
381
382 return $this;
383 }
384
385 /**
386 * @return string
387 */
388 public function getRowClass()
389 {
390 return $this->_rowClass;
391 }
392
393 /**
394 * @param string $classname
395 * @return Zend_Db_Table_Abstract Provides a fluent interface
396 */
397 public function setRowsetClass($classname)
398 {
399 $this->_rowsetClass = (string) $classname;
400
401 return $this;
402 }
403
404 /**
405 * @return string
406 */
407 public function getRowsetClass()
408 {
409 return $this->_rowsetClass;
410 }
411
412 /**
413 * Add a reference to the reference map
414 *
415 * @param string $ruleKey
416 * @param string|array $columns
417 * @param string $refTableClass
418 * @param string|array $refColumns
419 * @param string $onDelete
420 * @param string $onUpdate
421 * @return Zend_Db_Table_Abstract
422 */
423 public function addReference($ruleKey, $columns, $refTableClass, $refColumns,
424 $onDelete = null, $onUpdate = null)
425 {
426 $reference = array(self::COLUMNS => (array) $columns,
427 self::REF_TABLE_CLASS => $refTableClass,
428 self::REF_COLUMNS => (array) $refColumns);
429
430 if (!empty($onDelete)) {
431 $reference[self::ON_DELETE] = $onDelete;
432 }
433
434 if (!empty($onUpdate)) {
435 $reference[self::ON_UPDATE] = $onUpdate;
436 }
437
438 $this->_referenceMap[$ruleKey] = $reference;
439
440 return $this;
441 }
442
443 /**
444 * @param array $referenceMap
445 * @return Zend_Db_Table_Abstract Provides a fluent interface
446 */
447 public function setReferences(array $referenceMap)
448 {
449 $this->_referenceMap = $referenceMap;
450
451 return $this;
452 }
453
454 /**
455 * @param string $tableClassname
456 * @param string $ruleKey OPTIONAL
457 * @return array
458 * @throws Zend_Db_Table_Exception
459 */
460 public function getReference($tableClassname, $ruleKey = null)
461 {
462 $thisClass = get_class($this);
463 if ($thisClass === 'Zend_Db_Table') {
464 $thisClass = $this->_definitionConfigName;
465 }
466 $refMap = $this->_getReferenceMapNormalized();
467 if ($ruleKey !== null) {
468 if (!isset($refMap[$ruleKey])) {
469 // require_once "Zend/Db/Table/Exception.php";
470 throw new Zend_Db_Table_Exception("No reference rule \"$ruleKey\" from table $thisClass to table $tableClassname");
471 }
472 if ($refMap[$ruleKey][self::REF_TABLE_CLASS] != $tableClassname) {
473 // require_once "Zend/Db/Table/Exception.php";
474 throw new Zend_Db_Table_Exception("Reference rule \"$ruleKey\" does not reference table $tableClassname");
475 }
476 return $refMap[$ruleKey];
477 }
478 foreach ($refMap as $reference) {
479 if ($reference[self::REF_TABLE_CLASS] == $tableClassname) {
480 return $reference;
481 }
482 }
483 // require_once "Zend/Db/Table/Exception.php";
484 throw new Zend_Db_Table_Exception("No reference from table $thisClass to table $tableClassname");
485 }
486
487 /**
488 * @param array $dependentTables
489 * @return Zend_Db_Table_Abstract Provides a fluent interface
490 */
491 public function setDependentTables(array $dependentTables)
492 {
493 $this->_dependentTables = $dependentTables;
494
495 return $this;
496 }
497
498 /**
499 * @return array
500 */
501 public function getDependentTables()
502 {
503 return $this->_dependentTables;
504 }
505
506 /**
507 * set the defaultSource property - this tells the table class where to find default values
508 *
509 * @param string $defaultSource
510 * @return Zend_Db_Table_Abstract
511 */
512 public function setDefaultSource($defaultSource = self::DEFAULT_NONE)
513 {
514 if (!in_array($defaultSource, array(self::DEFAULT_CLASS, self::DEFAULT_DB, self::DEFAULT_NONE))) {
515 $defaultSource = self::DEFAULT_NONE;
516 }
517
518 $this->_defaultSource = $defaultSource;
519 return $this;
520 }
521
522 /**
523 * returns the default source flag that determines where defaultSources come from
524 *
525 * @return unknown
526 */
527 public function getDefaultSource()
528 {
529 return $this->_defaultSource;
530 }
531
532 /**
533 * set the default values for the table class
534 *
535 * @param array $defaultValues
536 * @return Zend_Db_Table_Abstract
537 */
538 public function setDefaultValues(Array $defaultValues)
539 {
540 foreach ($defaultValues as $defaultName => $defaultValue) {
541 if (array_key_exists($defaultName, $this->_metadata)) {
542 $this->_defaultValues[$defaultName] = $defaultValue;
543 }
544 }
545 return $this;
546 }
547
548 public function getDefaultValues()
549 {
550 return $this->_defaultValues;
551 }
552
553
554 /**
555 * Sets the default Zend_Db_Adapter_Abstract for all Zend_Db_Table objects.
556 *
557 * @param mixed $db Either an Adapter object, or a string naming a Registry key
558 * @return void
559 */
560 public static function setDefaultAdapter($db = null)
561 {
562 self::$_defaultDb = self::_setupAdapter($db);
563 }
564
565 /**
566 * Gets the default Zend_Db_Adapter_Abstract for all Zend_Db_Table objects.
567 *
568 * @return Zend_Db_Adapter_Abstract or null
569 */
570 public static function getDefaultAdapter()
571 {
572 return self::$_defaultDb;
573 }
574
575 /**
576 * @param mixed $db Either an Adapter object, or a string naming a Registry key
577 * @return Zend_Db_Table_Abstract Provides a fluent interface
578 */
579 protected function _setAdapter($db)
580 {
581 $this->_db = self::_setupAdapter($db);
582 return $this;
583 }
584
585 /**
586 * Gets the Zend_Db_Adapter_Abstract for this particular Zend_Db_Table object.
587 *
588 * @return Zend_Db_Adapter_Abstract
589 */
590 public function getAdapter()
591 {
592 return $this->_db;
593 }
594
595 /**
596 * @param mixed $db Either an Adapter object, or a string naming a Registry key
597 * @return Zend_Db_Adapter_Abstract
598 * @throws Zend_Db_Table_Exception
599 */
600 protected static function _setupAdapter($db)
601 {
602 if ($db === null) {
603 return null;
604 }
605 if (is_string($db)) {
606 // require_once 'Zend/Registry.php';
607 $db = \Zend_Registry::get($db);
608 }
609 if (!$db instanceof Zend_Db_Adapter_Abstract) {
610 // require_once 'Zend/Db/Table/Exception.php';
611 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');
612 }
613 return $db;
614 }
615
616 /**
617 * Sets the default metadata cache for information returned by Zend_Db_Adapter_Abstract::describeTable().
618 *
619 * If $defaultMetadataCache is null, then no metadata cache is used by default.
620 *
621 * @param mixed $metadataCache Either a Cache object, or a string naming a Registry key
622 * @return void
623 */
624 public static function setDefaultMetadataCache($metadataCache = null)
625 {
626 self::$_defaultMetadataCache = self::_setupMetadataCache($metadataCache);
627 }
628
629 /**
630 * Gets the default metadata cache for information returned by Zend_Db_Adapter_Abstract::describeTable().
631 *
632 * @return Zend_Cache_Core or null
633 */
634 public static function getDefaultMetadataCache()
635 {
636 return self::$_defaultMetadataCache;
637 }
638
639 /**
640 * Sets the metadata cache for information returned by Zend_Db_Adapter_Abstract::describeTable().
641 *
642 * If $metadataCache is null, then no metadata cache is used. Since there is no opportunity to reload metadata
643 * after instantiation, this method need not be public, particularly because that it would have no effect
644 * results in unnecessary API complexity. To configure the metadata cache, use the metadataCache configuration
645 * option for the class constructor upon instantiation.
646 *
647 * @param mixed $metadataCache Either a Cache object, or a string naming a Registry key
648 * @return Zend_Db_Table_Abstract Provides a fluent interface
649 */
650 protected function _setMetadataCache($metadataCache)
651 {
652 $this->_metadataCache = self::_setupMetadataCache($metadataCache);
653 return $this;
654 }
655
656 /**
657 * Gets the metadata cache for information returned by Zend_Db_Adapter_Abstract::describeTable().
658 *
659 * @return Zend_Cache_Core or null
660 */
661 public function getMetadataCache()
662 {
663 return $this->_metadataCache;
664 }
665
666 /**
667 * Indicate whether metadata should be cached in the class for the duration
668 * of the instance
669 *
670 * @param bool $flag
671 * @return Zend_Db_Table_Abstract
672 */
673 public function setMetadataCacheInClass($flag)
674 {
675 $this->_metadataCacheInClass = (bool) $flag;
676 return $this;
677 }
678
679 /**
680 * Retrieve flag indicating if metadata should be cached for duration of
681 * instance
682 *
683 * @return bool
684 */
685 public function metadataCacheInClass()
686 {
687 return $this->_metadataCacheInClass;
688 }
689
690 /**
691 * @param mixed $metadataCache Either a Cache object, or a string naming a Registry key
692 * @return Zend_Cache_Core
693 * @throws Zend_Db_Table_Exception
694 */
695 protected static function _setupMetadataCache($metadataCache)
696 {
697 if ($metadataCache === null) {
698 return null;
699 }
700 if (is_string($metadataCache)) {
701 // require_once 'Zend/Registry.php';
702 $metadataCache = \Zend_Registry::get($metadataCache);
703 }
704 if (!$metadataCache instanceof Zend_Cache_Core) {
705 // require_once 'Zend/Db/Table/Exception.php';
706 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');
707 }
708 return $metadataCache;
709 }
710
711 /**
712 * Sets the sequence member, which defines the behavior for generating
713 * primary key values in new rows.
714 * - If this is a string, then the string names the sequence object.
715 * - If this is boolean true, then the key uses an auto-incrementing
716 * or identity mechanism.
717 * - If this is boolean false, then the key is user-defined.
718 * Use this for natural keys, for example.
719 *
720 * @param mixed $sequence
721 * @return Zend_Db_Table_Adapter_Abstract Provides a fluent interface
722 */
723 protected function _setSequence($sequence)
724 {
725 $this->_sequence = $sequence;
726
727 return $this;
728 }
729
730 /**
731 * Turnkey for initialization of a table object.
732 * Calls other protected methods for individual tasks, to make it easier
733 * for a subclass to override part of the setup logic.
734 *
735 * @return void
736 */
737 protected function _setup()
738 {
739 $this->_setupDatabaseAdapter();
740 $this->_setupTableName();
741 }
742
743 /**
744 * Initialize database adapter.
745 *
746 * @return void
747 * @throws Zend_Db_Table_Exception
748 */
749 protected function _setupDatabaseAdapter()
750 {
751 if (! $this->_db) {
752 $this->_db = self::getDefaultAdapter();
753 if (!$this->_db instanceof Zend_Db_Adapter_Abstract) {
754 // require_once 'Zend/Db/Table/Exception.php';
755 throw new Zend_Db_Table_Exception('No adapter found for ' . get_class($this));
756 }
757 }
758 }
759
760 /**
761 * Initialize table and schema names.
762 *
763 * If the table name is not set in the class definition,
764 * use the class name itself as the table name.
765 *
766 * A schema name provided with the table name (e.g., "schema.table") overrides
767 * any existing value for $this->_schema.
768 *
769 * @return void
770 */
771 protected function _setupTableName()
772 {
773 if (! $this->_name) {
774 $this->_name = get_class($this);
775 } else if (strpos($this->_name, '.')) {
776 list($this->_schema, $this->_name) = explode('.', $this->_name);
777 }
778 }
779
780 /**
781 * Initializes metadata.
782 *
783 * If metadata cannot be loaded from cache, adapter's describeTable() method is called to discover metadata
784 * information. Returns true if and only if the metadata are loaded from cache.
785 *
786 * @return boolean
787 * @throws Zend_Db_Table_Exception
788 */
789 protected function _setupMetadata()
790 {
791 if ($this->metadataCacheInClass() && (count($this->_metadata) > 0)) {
792 return true;
793 }
794
795 // Assume that metadata will be loaded from cache
796 $isMetadataFromCache = true;
797
798 // If $this has no metadata cache but the class has a default metadata cache
799 if (null === $this->_metadataCache && null !== self::$_defaultMetadataCache) {
800 // Make $this use the default metadata cache of the class
801 $this->_setMetadataCache(self::$_defaultMetadataCache);
802 }
803
804 // If $this has a metadata cache
805 if (null !== $this->_metadataCache) {
806 // Define the cache identifier where the metadata are saved
807
808 //get db configuration
809 $dbConfig = $this->_db->getConfig();
810
811 $port = isset($dbConfig['options']['port'])
812 ? ':'.$dbConfig['options']['port']
813 : (isset($dbConfig['port'])
814 ? ':'.$dbConfig['port']
815 : null);
816
817 $host = isset($dbConfig['options']['host'])
818 ? ':'.$dbConfig['options']['host']
819 : (isset($dbConfig['host'])
820 ? ':'.$dbConfig['host']
821 : null);
822
823 // Define the cache identifier where the metadata are saved
824 $cacheId = md5( // port:host/dbname:schema.table (based on availabilty)
825 $port . $host . '/'. $dbConfig['dbname'] . ':'
826 . $this->_schema. '.' . $this->_name
827 );
828 }
829
830 // If $this has no metadata cache or metadata cache misses
831 if (null === $this->_metadataCache || !($metadata = $this->_metadataCache->load($cacheId))) {
832 // Metadata are not loaded from cache
833 $isMetadataFromCache = false;
834 // Fetch metadata from the adapter's describeTable() method
835 $metadata = $this->_db->describeTable($this->_name, $this->_schema);
836 // If $this has a metadata cache, then cache the metadata
837 if (null !== $this->_metadataCache && !$this->_metadataCache->save($metadata, $cacheId)) {
838 trigger_error('Failed saving metadata to metadataCache', E_USER_NOTICE);
839 }
840 }
841
842 // Assign the metadata to $this
843 $this->_metadata = $metadata;
844
845 // Return whether the metadata were loaded from cache
846 return $isMetadataFromCache;
847 }
848
849 /**
850 * Retrieve table columns
851 *
852 * @return array
853 */
854 protected function _getCols()
855 {
856 if (null === $this->_cols) {
857 $this->_setupMetadata();
858 $this->_cols = array_keys($this->_metadata);
859 }
860 return $this->_cols;
861 }
862
863 /**
864 * Initialize primary key from metadata.
865 * If $_primary is not defined, discover primary keys
866 * from the information returned by describeTable().
867 *
868 * @return void
869 * @throws Zend_Db_Table_Exception
870 */
871 protected function _setupPrimaryKey()
872 {
873 if (!$this->_primary) {
874 $this->_setupMetadata();
875 $this->_primary = array();
876 foreach ($this->_metadata as $col) {
877 if ($col['PRIMARY']) {
878 $this->_primary[ $col['PRIMARY_POSITION'] ] = $col['COLUMN_NAME'];
879 if ($col['IDENTITY']) {
880 $this->_identity = $col['PRIMARY_POSITION'];
881 }
882 }
883 }
884 // if no primary key was specified and none was found in the metadata
885 // then throw an exception.
886 if (empty($this->_primary)) {
887 // require_once 'Zend/Db/Table/Exception.php';
888 throw new Zend_Db_Table_Exception('A table must have a primary key, but none was found');
889 }
890 } else if (!is_array($this->_primary)) {
891 $this->_primary = array(1 => $this->_primary);
892 } else if (isset($this->_primary[0])) {
893 array_unshift($this->_primary, null);
894 unset($this->_primary[0]);
895 }
896
897 $cols = $this->_getCols();
898 if (! array_intersect((array) $this->_primary, $cols) == (array) $this->_primary) {
899 // require_once 'Zend/Db/Table/Exception.php';
900 throw new Zend_Db_Table_Exception("Primary key column(s) ("
901 . implode(',', (array) $this->_primary)
902 . ") are not columns in this table ("
903 . implode(',', $cols)
904 . ")");
905 }
906
907 $primary = (array) $this->_primary;
908 $pkIdentity = $primary[(int) $this->_identity];
909
910 /**
911 * Special case for PostgreSQL: a SERIAL key implicitly uses a sequence
912 * object whose name is "<table>_<column>_seq".
913 */
914 if ($this->_sequence === true && $this->_db instanceof Zend_Db_Adapter_Pdo_Pgsql) {
915 $this->_sequence = $this->_db->quoteIdentifier("{$this->_name}_{$pkIdentity}_seq");
916 if ($this->_schema) {
917 $this->_sequence = $this->_db->quoteIdentifier($this->_schema) . '.' . $this->_sequence;
918 }
919 }
920 }
921
922 /**
923 * Returns a normalized version of the reference map
924 *
925 * @return array
926 */
927 protected function _getReferenceMapNormalized()
928 {
929 $referenceMapNormalized = array();
930
931 foreach ($this->_referenceMap as $rule => $map) {
932
933 $referenceMapNormalized[$rule] = array();
934
935 foreach ($map as $key => $value) {
936 switch ($key) {
937
938 // normalize COLUMNS and REF_COLUMNS to arrays
939 case self::COLUMNS:
940 case self::REF_COLUMNS:
941 if (!is_array($value)) {
942 $referenceMapNormalized[$rule][$key] = array($value);
943 } else {
944 $referenceMapNormalized[$rule][$key] = $value;
945 }
946 break;
947
948 // other values are copied as-is
949 default:
950 $referenceMapNormalized[$rule][$key] = $value;
951 break;
952 }
953 }
954 }
955
956 return $referenceMapNormalized;
957 }
958
959 /**
960 * Initialize object
961 *
962 * Called from {@link __construct()} as final step of object instantiation.
963 *
964 * @return void
965 */
966 public function init()
967 {
968 }
969
970 /**
971 * Returns table information.
972 *
973 * You can elect to return only a part of this information by supplying its key name,
974 * otherwise all information is returned as an array.
975 *
976 * @param string $key The specific info part to return OPTIONAL
977 * @return mixed
978 * @throws Zend_Db_Table_Exception
979 */
980 public function info($key = null)
981 {
982 $this->_setupPrimaryKey();
983
984 $info = array(
985 self::SCHEMA => $this->_schema,
986 self::NAME => $this->_name,
987 self::COLS => $this->_getCols(),
988 self::PRIMARY => (array) $this->_primary,
989 self::METADATA => $this->_metadata,
990 self::ROW_CLASS => $this->getRowClass(),
991 self::ROWSET_CLASS => $this->getRowsetClass(),
992 self::REFERENCE_MAP => $this->_referenceMap,
993 self::DEPENDENT_TABLES => $this->_dependentTables,
994 self::SEQUENCE => $this->_sequence
995 );
996
997 if ($key === null) {
998 return $info;
999 }
1000
1001 if (!array_key_exists($key, $info)) {
1002 // require_once 'Zend/Db/Table/Exception.php';
1003 throw new Zend_Db_Table_Exception('There is no table information for the key "' . $key . '"');
1004 }
1005
1006 return $info[$key];
1007 }
1008
1009 /**
1010 * Returns an instance of a Zend_Db_Table_Select object.
1011 *
1012 * @param bool $withFromPart Whether or not to include the from part of the select based on the table
1013 * @return Zend_Db_Table_Select
1014 */
1015 public function select($withFromPart = self::SELECT_WITHOUT_FROM_PART)
1016 {
1017 // require_once 'Zend/Db/Table/Select.php';
1018 $select = new Zend_Db_Table_Select($this);
1019 if ($withFromPart == self::SELECT_WITH_FROM_PART) {
1020 $select->from($this->info(self::NAME), Zend_Db_Table_Select::SQL_WILDCARD, $this->info(self::SCHEMA));
1021 }
1022 return $select;
1023 }
1024
1025 /**
1026 * Inserts a new row.
1027 *
1028 * @param array $data Column-value pairs.
1029 * @return mixed The primary key of the row inserted.
1030 */
1031 public function insert(array $data)
1032 {
1033 $this->_setupPrimaryKey();
1034
1035 /**
1036 * Zend_Db_Table assumes that if you have a compound primary key
1037 * and one of the columns in the key uses a sequence,
1038 * it's the _first_ column in the compound key.
1039 */
1040 $primary = (array) $this->_primary;
1041 $pkIdentity = $primary[(int)$this->_identity];
1042
1043 /**
1044 * If this table uses a database sequence object and the data does not
1045 * specify a value, then get the next ID from the sequence and add it
1046 * to the row. We assume that only the first column in a compound
1047 * primary key takes a value from a sequence.
1048 */
1049 if (is_string($this->_sequence) && !isset($data[$pkIdentity])) {
1050 $data[$pkIdentity] = $this->_db->nextSequenceId($this->_sequence);
1051 $pkSuppliedBySequence = true;
1052 }
1053
1054 /**
1055 * If the primary key can be generated automatically, and no value was
1056 * specified in the user-supplied data, then omit it from the tuple.
1057 *
1058 * Note: this checks for sensible values in the supplied primary key
1059 * position of the data. The following values are considered empty:
1060 * null, false, true, '', array()
1061 */
1062 if (!isset($pkSuppliedBySequence) && array_key_exists($pkIdentity, $data)) {
1063 if ($data[$pkIdentity] === null // null
1064 || $data[$pkIdentity] === '' // empty string
1065 || is_bool($data[$pkIdentity]) // boolean
1066 || (is_array($data[$pkIdentity]) && empty($data[$pkIdentity]))) { // empty array
1067 unset($data[$pkIdentity]);
1068 }
1069 }
1070
1071 /**
1072 * INSERT the new row.
1073 */
1074 $tableSpec = ($this->_schema ? $this->_schema . '.' : '') . $this->_name;
1075 $this->_db->insert($tableSpec, $data);
1076
1077 /**
1078 * Fetch the most recent ID generated by an auto-increment
1079 * or IDENTITY column, unless the user has specified a value,
1080 * overriding the auto-increment mechanism.
1081 */
1082 if ($this->_sequence === true && !isset($data[$pkIdentity])) {
1083 $data[$pkIdentity] = $this->_db->lastInsertId();
1084 }
1085
1086 /**
1087 * Return the primary key value if the PK is a single column,
1088 * else return an associative array of the PK column/value pairs.
1089 */
1090 $pkData = array_intersect_key($data, array_flip($primary));
1091 if (count($primary) == 1) {
1092 reset($pkData);
1093 return current($pkData);
1094 }
1095
1096 return $pkData;
1097 }
1098
1099 /**
1100 * Check if the provided column is an identity of the table
1101 *
1102 * @param string $column
1103 * @throws Zend_Db_Table_Exception
1104 * @return boolean
1105 */
1106 public function isIdentity($column)
1107 {
1108 $this->_setupPrimaryKey();
1109
1110 if (!isset($this->_metadata[$column])) {
1111 /**
1112 * @see Zend_Db_Table_Exception
1113 */
1114 // require_once 'Zend/Db/Table/Exception.php';
1115
1116 throw new Zend_Db_Table_Exception('Column "' . $column . '" not found in table.');
1117 }
1118
1119 return (bool) $this->_metadata[$column]['IDENTITY'];
1120 }
1121
1122 /**
1123 * Updates existing rows.
1124 *
1125 * @param array $data Column-value pairs.
1126 * @param array|string $where An SQL WHERE clause, or an array of SQL WHERE clauses.
1127 * @return int The number of rows updated.
1128 */
1129 public function update(array $data, $where)
1130 {
1131 $tableSpec = ($this->_schema ? $this->_schema . '.' : '') . $this->_name;
1132 return $this->_db->update($tableSpec, $data, $where);
1133 }
1134
1135 /**
1136 * Called by a row object for the parent table's class during save() method.
1137 *
1138 * @param string $parentTableClassname
1139 * @param array $oldPrimaryKey
1140 * @param array $newPrimaryKey
1141 * @return int
1142 */
1143 public function _cascadeUpdate($parentTableClassname, array $oldPrimaryKey, array $newPrimaryKey)
1144 {
1145 $this->_setupMetadata();
1146 $rowsAffected = 0;
1147 foreach ($this->_getReferenceMapNormalized() as $map) {
1148 if ($map[self::REF_TABLE_CLASS] == $parentTableClassname && isset($map[self::ON_UPDATE])) {
1149 switch ($map[self::ON_UPDATE]) {
1150 case self::CASCADE:
1151 $newRefs = array();
1152 $where = array();
1153 for ($i = 0; $i < count($map[self::COLUMNS]); ++$i) {
1154 $col = $this->_db->foldCase($map[self::COLUMNS][$i]);
1155 $refCol = $this->_db->foldCase($map[self::REF_COLUMNS][$i]);
1156 if (array_key_exists($refCol, $newPrimaryKey)) {
1157 $newRefs[$col] = $newPrimaryKey[$refCol];
1158 }
1159 $type = $this->_metadata[$col]['DATA_TYPE'];
1160 $where[] = $this->_db->quoteInto(
1161 $this->_db->quoteIdentifier($col, true) . ' = ?',
1162 $oldPrimaryKey[$refCol], $type);
1163 }
1164 $rowsAffected += $this->update($newRefs, $where);
1165 break;
1166 default:
1167 // no action
1168 break;
1169 }
1170 }
1171 }
1172 return $rowsAffected;
1173 }
1174
1175 /**
1176 * Deletes existing rows.
1177 *
1178 * @param array|string $where SQL WHERE clause(s).
1179 * @return int The number of rows deleted.
1180 */
1181 public function delete($where)
1182 {
1183 $tableSpec = ($this->_schema ? $this->_schema . '.' : '') . $this->_name;
1184 return $this->_db->delete($tableSpec, $where);
1185 }
1186
1187 /**
1188 * Called by parent table's class during delete() method.
1189 *
1190 * @param string $parentTableClassname
1191 * @param array $primaryKey
1192 * @return int Number of affected rows
1193 */
1194 public function _cascadeDelete($parentTableClassname, array $primaryKey)
1195 {
1196 $this->_setupMetadata();
1197 $rowsAffected = 0;
1198 foreach ($this->_getReferenceMapNormalized() as $map) {
1199 if ($map[self::REF_TABLE_CLASS] == $parentTableClassname && isset($map[self::ON_DELETE])) {
1200 switch ($map[self::ON_DELETE]) {
1201 case self::CASCADE:
1202 $where = array();
1203 for ($i = 0; $i < count($map[self::COLUMNS]); ++$i) {
1204 $col = $this->_db->foldCase($map[self::COLUMNS][$i]);
1205 $refCol = $this->_db->foldCase($map[self::REF_COLUMNS][$i]);
1206 $type = $this->_metadata[$col]['DATA_TYPE'];
1207 $where[] = $this->_db->quoteInto(
1208 $this->_db->quoteIdentifier($col, true) . ' = ?',
1209 $primaryKey[$refCol], $type);
1210 }
1211 $rowsAffected += $this->delete($where);
1212 break;
1213 default:
1214 // no action
1215 break;
1216 }
1217 }
1218 }
1219 return $rowsAffected;
1220 }
1221
1222 /**
1223 * Fetches rows by primary key. The argument specifies one or more primary
1224 * key value(s). To find multiple rows by primary key, the argument must
1225 * be an array.
1226 *
1227 * This method accepts a variable number of arguments. If the table has a
1228 * multi-column primary key, the number of arguments must be the same as
1229 * the number of columns in the primary key. To find multiple rows in a
1230 * table with a multi-column primary key, each argument must be an array
1231 * with the same number of elements.
1232 *
1233 * The find() method always returns a Rowset object, even if only one row
1234 * was found.
1235 *
1236 * @param mixed $key The value(s) of the primary keys.
1237 * @return Zend_Db_Table_Rowset_Abstract Row(s) matching the criteria.
1238 * @throws Zend_Db_Table_Exception
1239 */
1240 public function find()
1241 {
1242 $this->_setupPrimaryKey();
1243 $args = func_get_args();
1244 $keyNames = array_values((array) $this->_primary);
1245
1246 if (count($args) < count($keyNames)) {
1247 // require_once 'Zend/Db/Table/Exception.php';
1248 throw new Zend_Db_Table_Exception("Too few columns for the primary key");
1249 }
1250
1251 if (count($args) > count($keyNames)) {
1252 // require_once 'Zend/Db/Table/Exception.php';
1253 throw new Zend_Db_Table_Exception("Too many columns for the primary key");
1254 }
1255
1256 $whereList = array();
1257 $numberTerms = 0;
1258 foreach ($args as $keyPosition => $keyValues) {
1259 $keyValuesCount = count($keyValues);
1260 // Coerce the values to an array.
1261 // Don't simply typecast to array, because the values
1262 // might be Zend_Db_Expr objects.
1263 if (!is_array($keyValues)) {
1264 $keyValues = array($keyValues);
1265 }
1266 if ($numberTerms == 0) {
1267 $numberTerms = $keyValuesCount;
1268 } else if ($keyValuesCount != $numberTerms) {
1269 // require_once 'Zend/Db/Table/Exception.php';
1270 throw new Zend_Db_Table_Exception("Missing value(s) for the primary key");
1271 }
1272 $keyValues = array_values($keyValues);
1273 for ($i = 0; $i < $keyValuesCount; ++$i) {
1274 if (!isset($whereList[$i])) {
1275 $whereList[$i] = array();
1276 }
1277 $whereList[$i][$keyPosition] = $keyValues[$i];
1278 }
1279 }
1280
1281 $whereClause = null;
1282 if (count($whereList)) {
1283 $whereOrTerms = array();
1284 $tableName = $this->_db->quoteTableAs($this->_name, null, true);
1285 foreach ($whereList as $keyValueSets) {
1286 $whereAndTerms = array();
1287 foreach ($keyValueSets as $keyPosition => $keyValue) {
1288 $type = $this->_metadata[$keyNames[$keyPosition]]['DATA_TYPE'];
1289 $columnName = $this->_db->quoteIdentifier($keyNames[$keyPosition], true);
1290 $whereAndTerms[] = $this->_db->quoteInto(
1291 $tableName . '.' . $columnName . ' = ?',
1292 $keyValue, $type);
1293 }
1294 $whereOrTerms[] = '(' . implode(' AND ', $whereAndTerms) . ')';
1295 }
1296 $whereClause = '(' . implode(' OR ', $whereOrTerms) . ')';
1297 }
1298
1299 // issue ZF-5775 (empty where clause should return empty rowset)
1300 if ($whereClause == null) {
1301 $rowsetClass = $this->getRowsetClass();
1302 if (!class_exists($rowsetClass)) {
1303 // require_once 'Zend/Loader.php';
1304 Zend_Loader::loadClass($rowsetClass);
1305 }
1306 return new $rowsetClass(array('table' => $this, 'rowClass' => $this->getRowClass(), 'stored' => true));
1307 }
1308
1309 return $this->fetchAll($whereClause);
1310 }
1311
1312 /**
1313 * Fetches all rows.
1314 *
1315 * Honors the Zend_Db_Adapter fetch mode.
1316 *
1317 * @param string|array|Zend_Db_Table_Select $where OPTIONAL An SQL WHERE clause or Zend_Db_Table_Select object.
1318 * @param string|array $order OPTIONAL An SQL ORDER clause.
1319 * @param int $count OPTIONAL An SQL LIMIT count.
1320 * @param int $offset OPTIONAL An SQL LIMIT offset.
1321 * @return Zend_Db_Table_Rowset_Abstract The row results per the Zend_Db_Adapter fetch mode.
1322 */
1323 public function fetchAll($where = null, $order = null, $count = null, $offset = null)
1324 {
1325 if (!($where instanceof Zend_Db_Table_Select)) {
1326 $select = $this->select();
1327
1328 if ($where !== null) {
1329 $this->_where($select, $where);
1330 }
1331
1332 if ($order !== null) {
1333 $this->_order($select, $order);
1334 }
1335
1336 if ($count !== null || $offset !== null) {
1337 $select->limit($count, $offset);
1338 }
1339
1340 } else {
1341 $select = $where;
1342 }
1343
1344 $rows = $this->_fetch($select);
1345
1346 $data = array(
1347 'table' => $this,
1348 'data' => $rows,
1349 'readOnly' => $select->isReadOnly(),
1350 'rowClass' => $this->getRowClass(),
1351 'stored' => true
1352 );
1353
1354 $rowsetClass = $this->getRowsetClass();
1355 if (!class_exists($rowsetClass)) {
1356 // require_once 'Zend/Loader.php';
1357 Zend_Loader::loadClass($rowsetClass);
1358 }
1359 return new $rowsetClass($data);
1360 }
1361
1362 /**
1363 * Fetches one row in an object of type Zend_Db_Table_Row_Abstract,
1364 * or returns null if no row matches the specified criteria.
1365 *
1366 * @param string|array|Zend_Db_Table_Select $where OPTIONAL An SQL WHERE clause or Zend_Db_Table_Select object.
1367 * @param string|array $order OPTIONAL An SQL ORDER clause.
1368 * @param int $offset OPTIONAL An SQL OFFSET value.
1369 * @return Zend_Db_Table_Row_Abstract|null The row results per the
1370 * Zend_Db_Adapter fetch mode, or null if no row found.
1371 */
1372 public function fetchRow($where = null, $order = null, $offset = null)
1373 {
1374 if (!($where instanceof Zend_Db_Table_Select)) {
1375 $select = $this->select();
1376
1377 if ($where !== null) {
1378 $this->_where($select, $where);
1379 }
1380
1381 if ($order !== null) {
1382 $this->_order($select, $order);
1383 }
1384
1385 $select->limit(1, ((is_numeric($offset)) ? (int) $offset : null));
1386
1387 } else {
1388 $select = $where->limit(1, $where->getPart(Zend_Db_Select::LIMIT_OFFSET));
1389 }
1390
1391 $rows = $this->_fetch($select);
1392
1393 if (count($rows) == 0) {
1394 return null;
1395 }
1396
1397 $data = array(
1398 'table' => $this,
1399 'data' => $rows[0],
1400 'readOnly' => $select->isReadOnly(),
1401 'stored' => true
1402 );
1403
1404 $rowClass = $this->getRowClass();
1405 if (!class_exists($rowClass)) {
1406 // require_once 'Zend/Loader.php';
1407 Zend_Loader::loadClass($rowClass);
1408 }
1409 return new $rowClass($data);
1410 }
1411
1412 /**
1413 * Fetches a new blank row (not from the database).
1414 *
1415 * @return Zend_Db_Table_Row_Abstract
1416 * @deprecated since 0.9.3 - use createRow() instead.
1417 */
1418 public function fetchNew()
1419 {
1420 return $this->createRow();
1421 }
1422
1423 /**
1424 * Fetches a new blank row (not from the database).
1425 *
1426 * @param array $data OPTIONAL data to populate in the new row.
1427 * @param string $defaultSource OPTIONAL flag to force default values into new row
1428 * @return Zend_Db_Table_Row_Abstract
1429 */
1430 public function createRow(array $data = array(), $defaultSource = null)
1431 {
1432 $cols = $this->_getCols();
1433 $defaults = array_combine($cols, array_fill(0, count($cols), null));
1434
1435 // nothing provided at call-time, take the class value
1436 if ($defaultSource == null) {
1437 $defaultSource = $this->_defaultSource;
1438 }
1439
1440 if (!in_array($defaultSource, array(self::DEFAULT_CLASS, self::DEFAULT_DB, self::DEFAULT_NONE))) {
1441 $defaultSource = self::DEFAULT_NONE;
1442 }
1443
1444 if ($defaultSource == self::DEFAULT_DB) {
1445 foreach ($this->_metadata as $metadataName => $metadata) {
1446 if (($metadata['DEFAULT'] != null) &&
1447 ($metadata['NULLABLE'] !== true || ($metadata['NULLABLE'] === true && isset($this->_defaultValues[$metadataName]) && $this->_defaultValues[$metadataName] === true)) &&
1448 (!(isset($this->_defaultValues[$metadataName]) && $this->_defaultValues[$metadataName] === false))) {
1449 $defaults[$metadataName] = $metadata['DEFAULT'];
1450 }
1451 }
1452 } elseif ($defaultSource == self::DEFAULT_CLASS && $this->_defaultValues) {
1453 foreach ($this->_defaultValues as $defaultName => $defaultValue) {
1454 if (array_key_exists($defaultName, $defaults)) {
1455 $defaults[$defaultName] = $defaultValue;
1456 }
1457 }
1458 }
1459
1460 $config = array(
1461 'table' => $this,
1462 'data' => $defaults,
1463 'readOnly' => false,
1464 'stored' => false
1465 );
1466
1467 $rowClass = $this->getRowClass();
1468 if (!class_exists($rowClass)) {
1469 // require_once 'Zend/Loader.php';
1470 Zend_Loader::loadClass($rowClass);
1471 }
1472 $row = new $rowClass($config);
1473 $row->setFromArray($data);
1474 return $row;
1475 }
1476
1477 /**
1478 * Generate WHERE clause from user-supplied string or array
1479 *
1480 * @param string|array $where OPTIONAL An SQL WHERE clause.
1481 * @return Zend_Db_Table_Select
1482 */
1483 protected function _where(Zend_Db_Table_Select $select, $where)
1484 {
1485 $where = (array) $where;
1486
1487 foreach ($where as $key => $val) {
1488 // is $key an int?
1489 if (is_int($key)) {
1490 // $val is the full condition
1491 $select->where($val);
1492 } else {
1493 // $key is the condition with placeholder,
1494 // and $val is quoted into the condition
1495 $select->where($key, $val);
1496 }
1497 }
1498
1499 return $select;
1500 }
1501
1502 /**
1503 * Generate ORDER clause from user-supplied string or array
1504 *
1505 * @param string|array $order OPTIONAL An SQL ORDER clause.
1506 * @return Zend_Db_Table_Select
1507 */
1508 protected function _order(Zend_Db_Table_Select $select, $order)
1509 {
1510 if (!is_array($order)) {
1511 $order = array($order);
1512 }
1513
1514 foreach ($order as $val) {
1515 $select->order($val);
1516 }
1517
1518 return $select;
1519 }
1520
1521 /**
1522 * Support method for fetching rows.
1523 *
1524 * @param Zend_Db_Table_Select $select query options.
1525 * @return array An array containing the row results in FETCH_ASSOC mode.
1526 */
1527 protected function _fetch(Zend_Db_Table_Select $select)
1528 {
1529 $stmt = $this->_db->query($select);
1530 $data = $stmt->fetchAll(Zend_Db::FETCH_ASSOC);
1531 return $data;
1532 }
1533
1534 }
1535