web/lib/Zend/Db/Table/Abstract.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     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-2010 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 21078 2010-02-18 18:07:16Z tech13 $
       
    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-2010 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      */
       
   748     protected function _setupDatabaseAdapter()
       
   749     {
       
   750         if (! $this->_db) {
       
   751             $this->_db = self::getDefaultAdapter();
       
   752             if (!$this->_db instanceof Zend_Db_Adapter_Abstract) {
       
   753                 require_once 'Zend/Db/Table/Exception.php';
       
   754                 throw new Zend_Db_Table_Exception('No adapter found for ' . get_class($this));
       
   755             }
       
   756         }
       
   757     }
       
   758 
       
   759     /**
       
   760      * Initialize table and schema names.
       
   761      *
       
   762      * If the table name is not set in the class definition,
       
   763      * use the class name itself as the table name.
       
   764      *
       
   765      * A schema name provided with the table name (e.g., "schema.table") overrides
       
   766      * any existing value for $this->_schema.
       
   767      *
       
   768      * @return void
       
   769      */
       
   770     protected function _setupTableName()
       
   771     {
       
   772         if (! $this->_name) {
       
   773             $this->_name = get_class($this);
       
   774         } else if (strpos($this->_name, '.')) {
       
   775             list($this->_schema, $this->_name) = explode('.', $this->_name);
       
   776         }
       
   777     }
       
   778 
       
   779     /**
       
   780      * Initializes metadata.
       
   781      *
       
   782      * If metadata cannot be loaded from cache, adapter's describeTable() method is called to discover metadata
       
   783      * information. Returns true if and only if the metadata are loaded from cache.
       
   784      *
       
   785      * @return boolean
       
   786      * @throws Zend_Db_Table_Exception
       
   787      */
       
   788     protected function _setupMetadata()
       
   789     {
       
   790         if ($this->metadataCacheInClass() && (count($this->_metadata) > 0)) {
       
   791             return true;
       
   792         }
       
   793 
       
   794         // Assume that metadata will be loaded from cache
       
   795         $isMetadataFromCache = true;
       
   796 
       
   797         // If $this has no metadata cache but the class has a default metadata cache
       
   798         if (null === $this->_metadataCache && null !== self::$_defaultMetadataCache) {
       
   799             // Make $this use the default metadata cache of the class
       
   800             $this->_setMetadataCache(self::$_defaultMetadataCache);
       
   801         }
       
   802 
       
   803         // If $this has a metadata cache
       
   804         if (null !== $this->_metadataCache) {
       
   805             // Define the cache identifier where the metadata are saved
       
   806 
       
   807             //get db configuration
       
   808             $dbConfig = $this->_db->getConfig();
       
   809 
       
   810             // Define the cache identifier where the metadata are saved
       
   811             $cacheId = md5( // port:host/dbname:schema.table (based on availabilty)
       
   812                 (isset($dbConfig['options']['port']) ? ':'.$dbConfig['options']['port'] : null)
       
   813                 . (isset($dbConfig['options']['host']) ? ':'.$dbConfig['options']['host'] : null)
       
   814                 . '/'.$dbConfig['dbname'].':'.$this->_schema.'.'.$this->_name
       
   815                 );
       
   816         }
       
   817 
       
   818         // If $this has no metadata cache or metadata cache misses
       
   819         if (null === $this->_metadataCache || !($metadata = $this->_metadataCache->load($cacheId))) {
       
   820             // Metadata are not loaded from cache
       
   821             $isMetadataFromCache = false;
       
   822             // Fetch metadata from the adapter's describeTable() method
       
   823             $metadata = $this->_db->describeTable($this->_name, $this->_schema);
       
   824             // If $this has a metadata cache, then cache the metadata
       
   825             if (null !== $this->_metadataCache && !$this->_metadataCache->save($metadata, $cacheId)) {
       
   826                 trigger_error('Failed saving metadata to metadataCache', E_USER_NOTICE);
       
   827             }
       
   828         }
       
   829 
       
   830         // Assign the metadata to $this
       
   831         $this->_metadata = $metadata;
       
   832 
       
   833         // Return whether the metadata were loaded from cache
       
   834         return $isMetadataFromCache;
       
   835     }
       
   836 
       
   837     /**
       
   838      * Retrieve table columns
       
   839      *
       
   840      * @return array
       
   841      */
       
   842     protected function _getCols()
       
   843     {
       
   844         if (null === $this->_cols) {
       
   845             $this->_setupMetadata();
       
   846             $this->_cols = array_keys($this->_metadata);
       
   847         }
       
   848         return $this->_cols;
       
   849     }
       
   850 
       
   851     /**
       
   852      * Initialize primary key from metadata.
       
   853      * If $_primary is not defined, discover primary keys
       
   854      * from the information returned by describeTable().
       
   855      *
       
   856      * @return void
       
   857      * @throws Zend_Db_Table_Exception
       
   858      */
       
   859     protected function _setupPrimaryKey()
       
   860     {
       
   861         if (!$this->_primary) {
       
   862             $this->_setupMetadata();
       
   863             $this->_primary = array();
       
   864             foreach ($this->_metadata as $col) {
       
   865                 if ($col['PRIMARY']) {
       
   866                     $this->_primary[ $col['PRIMARY_POSITION'] ] = $col['COLUMN_NAME'];
       
   867                     if ($col['IDENTITY']) {
       
   868                         $this->_identity = $col['PRIMARY_POSITION'];
       
   869                     }
       
   870                 }
       
   871             }
       
   872             // if no primary key was specified and none was found in the metadata
       
   873             // then throw an exception.
       
   874             if (empty($this->_primary)) {
       
   875                 require_once 'Zend/Db/Table/Exception.php';
       
   876                 throw new Zend_Db_Table_Exception('A table must have a primary key, but none was found');
       
   877             }
       
   878         } else if (!is_array($this->_primary)) {
       
   879             $this->_primary = array(1 => $this->_primary);
       
   880         } else if (isset($this->_primary[0])) {
       
   881             array_unshift($this->_primary, null);
       
   882             unset($this->_primary[0]);
       
   883         }
       
   884 
       
   885         $cols = $this->_getCols();
       
   886         if (! array_intersect((array) $this->_primary, $cols) == (array) $this->_primary) {
       
   887             require_once 'Zend/Db/Table/Exception.php';
       
   888             throw new Zend_Db_Table_Exception("Primary key column(s) ("
       
   889                 . implode(',', (array) $this->_primary)
       
   890                 . ") are not columns in this table ("
       
   891                 . implode(',', $cols)
       
   892                 . ")");
       
   893         }
       
   894 
       
   895         $primary    = (array) $this->_primary;
       
   896         $pkIdentity = $primary[(int) $this->_identity];
       
   897 
       
   898         /**
       
   899          * Special case for PostgreSQL: a SERIAL key implicitly uses a sequence
       
   900          * object whose name is "<table>_<column>_seq".
       
   901          */
       
   902         if ($this->_sequence === true && $this->_db instanceof Zend_Db_Adapter_Pdo_Pgsql) {
       
   903             $this->_sequence = $this->_db->quoteIdentifier("{$this->_name}_{$pkIdentity}_seq");
       
   904             if ($this->_schema) {
       
   905                 $this->_sequence = $this->_db->quoteIdentifier($this->_schema) . '.' . $this->_sequence;
       
   906             }
       
   907         }
       
   908     }
       
   909 
       
   910     /**
       
   911      * Returns a normalized version of the reference map
       
   912      *
       
   913      * @return array
       
   914      */
       
   915     protected function _getReferenceMapNormalized()
       
   916     {
       
   917         $referenceMapNormalized = array();
       
   918 
       
   919         foreach ($this->_referenceMap as $rule => $map) {
       
   920 
       
   921             $referenceMapNormalized[$rule] = array();
       
   922 
       
   923             foreach ($map as $key => $value) {
       
   924                 switch ($key) {
       
   925 
       
   926                     // normalize COLUMNS and REF_COLUMNS to arrays
       
   927                     case self::COLUMNS:
       
   928                     case self::REF_COLUMNS:
       
   929                         if (!is_array($value)) {
       
   930                             $referenceMapNormalized[$rule][$key] = array($value);
       
   931                         } else {
       
   932                             $referenceMapNormalized[$rule][$key] = $value;
       
   933                         }
       
   934                         break;
       
   935 
       
   936                     // other values are copied as-is
       
   937                     default:
       
   938                         $referenceMapNormalized[$rule][$key] = $value;
       
   939                         break;
       
   940                 }
       
   941             }
       
   942         }
       
   943 
       
   944         return $referenceMapNormalized;
       
   945     }
       
   946 
       
   947     /**
       
   948      * Initialize object
       
   949      *
       
   950      * Called from {@link __construct()} as final step of object instantiation.
       
   951      *
       
   952      * @return void
       
   953      */
       
   954     public function init()
       
   955     {
       
   956     }
       
   957 
       
   958     /**
       
   959      * Returns table information.
       
   960      *
       
   961      * You can elect to return only a part of this information by supplying its key name,
       
   962      * otherwise all information is returned as an array.
       
   963      *
       
   964      * @param  $key The specific info part to return OPTIONAL
       
   965      * @return mixed
       
   966      */
       
   967     public function info($key = null)
       
   968     {
       
   969         $this->_setupPrimaryKey();
       
   970 
       
   971         $info = array(
       
   972             self::SCHEMA           => $this->_schema,
       
   973             self::NAME             => $this->_name,
       
   974             self::COLS             => $this->_getCols(),
       
   975             self::PRIMARY          => (array) $this->_primary,
       
   976             self::METADATA         => $this->_metadata,
       
   977             self::ROW_CLASS        => $this->getRowClass(),
       
   978             self::ROWSET_CLASS     => $this->getRowsetClass(),
       
   979             self::REFERENCE_MAP    => $this->_referenceMap,
       
   980             self::DEPENDENT_TABLES => $this->_dependentTables,
       
   981             self::SEQUENCE         => $this->_sequence
       
   982         );
       
   983 
       
   984         if ($key === null) {
       
   985             return $info;
       
   986         }
       
   987 
       
   988         if (!array_key_exists($key, $info)) {
       
   989             require_once 'Zend/Db/Table/Exception.php';
       
   990             throw new Zend_Db_Table_Exception('There is no table information for the key "' . $key . '"');
       
   991         }
       
   992 
       
   993         return $info[$key];
       
   994     }
       
   995 
       
   996     /**
       
   997      * Returns an instance of a Zend_Db_Table_Select object.
       
   998      *
       
   999      * @param bool $withFromPart Whether or not to include the from part of the select based on the table
       
  1000      * @return Zend_Db_Table_Select
       
  1001      */
       
  1002     public function select($withFromPart = self::SELECT_WITHOUT_FROM_PART)
       
  1003     {
       
  1004         require_once 'Zend/Db/Table/Select.php';
       
  1005         $select = new Zend_Db_Table_Select($this);
       
  1006         if ($withFromPart == self::SELECT_WITH_FROM_PART) {
       
  1007             $select->from($this->info(self::NAME), Zend_Db_Table_Select::SQL_WILDCARD, $this->info(self::SCHEMA));
       
  1008         }
       
  1009         return $select;
       
  1010     }
       
  1011 
       
  1012     /**
       
  1013      * Inserts a new row.
       
  1014      *
       
  1015      * @param  array  $data  Column-value pairs.
       
  1016      * @return mixed         The primary key of the row inserted.
       
  1017      */
       
  1018     public function insert(array $data)
       
  1019     {
       
  1020         $this->_setupPrimaryKey();
       
  1021 
       
  1022         /**
       
  1023          * Zend_Db_Table assumes that if you have a compound primary key
       
  1024          * and one of the columns in the key uses a sequence,
       
  1025          * it's the _first_ column in the compound key.
       
  1026          */
       
  1027         $primary = (array) $this->_primary;
       
  1028         $pkIdentity = $primary[(int)$this->_identity];
       
  1029 
       
  1030         /**
       
  1031          * If this table uses a database sequence object and the data does not
       
  1032          * specify a value, then get the next ID from the sequence and add it
       
  1033          * to the row.  We assume that only the first column in a compound
       
  1034          * primary key takes a value from a sequence.
       
  1035          */
       
  1036         if (is_string($this->_sequence) && !isset($data[$pkIdentity])) {
       
  1037             $data[$pkIdentity] = $this->_db->nextSequenceId($this->_sequence);
       
  1038         }
       
  1039 
       
  1040         /**
       
  1041          * If the primary key can be generated automatically, and no value was
       
  1042          * specified in the user-supplied data, then omit it from the tuple.
       
  1043          */
       
  1044         if (array_key_exists($pkIdentity, $data) && $data[$pkIdentity] === null) {
       
  1045             unset($data[$pkIdentity]);
       
  1046         }
       
  1047 
       
  1048         /**
       
  1049          * INSERT the new row.
       
  1050          */
       
  1051         $tableSpec = ($this->_schema ? $this->_schema . '.' : '') . $this->_name;
       
  1052         $this->_db->insert($tableSpec, $data);
       
  1053 
       
  1054         /**
       
  1055          * Fetch the most recent ID generated by an auto-increment
       
  1056          * or IDENTITY column, unless the user has specified a value,
       
  1057          * overriding the auto-increment mechanism.
       
  1058          */
       
  1059         if ($this->_sequence === true && !isset($data[$pkIdentity])) {
       
  1060             $data[$pkIdentity] = $this->_db->lastInsertId();
       
  1061         }
       
  1062 
       
  1063         /**
       
  1064          * Return the primary key value if the PK is a single column,
       
  1065          * else return an associative array of the PK column/value pairs.
       
  1066          */
       
  1067         $pkData = array_intersect_key($data, array_flip($primary));
       
  1068         if (count($primary) == 1) {
       
  1069             reset($pkData);
       
  1070             return current($pkData);
       
  1071         }
       
  1072 
       
  1073         return $pkData;
       
  1074     }
       
  1075 
       
  1076     /**
       
  1077      * Check if the provided column is an identity of the table
       
  1078      *
       
  1079      * @param  string $column
       
  1080      * @throws Zend_Db_Table_Exception
       
  1081      * @return boolean
       
  1082      */
       
  1083     public function isIdentity($column)
       
  1084     {
       
  1085         $this->_setupPrimaryKey();
       
  1086 
       
  1087         if (!isset($this->_metadata[$column])) {
       
  1088             /**
       
  1089              * @see Zend_Db_Table_Exception
       
  1090              */
       
  1091             require_once 'Zend/Db/Table/Exception.php';
       
  1092 
       
  1093             throw new Zend_Db_Table_Exception('Column "' . $column . '" not found in table.');
       
  1094         }
       
  1095 
       
  1096         return (bool) $this->_metadata[$column]['IDENTITY'];
       
  1097     }
       
  1098 
       
  1099     /**
       
  1100      * Updates existing rows.
       
  1101      *
       
  1102      * @param  array        $data  Column-value pairs.
       
  1103      * @param  array|string $where An SQL WHERE clause, or an array of SQL WHERE clauses.
       
  1104      * @return int          The number of rows updated.
       
  1105      */
       
  1106     public function update(array $data, $where)
       
  1107     {
       
  1108         $tableSpec = ($this->_schema ? $this->_schema . '.' : '') . $this->_name;
       
  1109         return $this->_db->update($tableSpec, $data, $where);
       
  1110     }
       
  1111 
       
  1112     /**
       
  1113      * Called by a row object for the parent table's class during save() method.
       
  1114      *
       
  1115      * @param  string $parentTableClassname
       
  1116      * @param  array  $oldPrimaryKey
       
  1117      * @param  array  $newPrimaryKey
       
  1118      * @return int
       
  1119      */
       
  1120     public function _cascadeUpdate($parentTableClassname, array $oldPrimaryKey, array $newPrimaryKey)
       
  1121     {
       
  1122         $this->_setupMetadata();
       
  1123         $rowsAffected = 0;
       
  1124         foreach ($this->_getReferenceMapNormalized() as $map) {
       
  1125             if ($map[self::REF_TABLE_CLASS] == $parentTableClassname && isset($map[self::ON_UPDATE])) {
       
  1126                 switch ($map[self::ON_UPDATE]) {
       
  1127                     case self::CASCADE:
       
  1128                         $newRefs = array();
       
  1129                         $where = array();
       
  1130                         for ($i = 0; $i < count($map[self::COLUMNS]); ++$i) {
       
  1131                             $col = $this->_db->foldCase($map[self::COLUMNS][$i]);
       
  1132                             $refCol = $this->_db->foldCase($map[self::REF_COLUMNS][$i]);
       
  1133                             if (array_key_exists($refCol, $newPrimaryKey)) {
       
  1134                                 $newRefs[$col] = $newPrimaryKey[$refCol];
       
  1135                             }
       
  1136                             $type = $this->_metadata[$col]['DATA_TYPE'];
       
  1137                             $where[] = $this->_db->quoteInto(
       
  1138                                 $this->_db->quoteIdentifier($col, true) . ' = ?',
       
  1139                                 $oldPrimaryKey[$refCol], $type);
       
  1140                         }
       
  1141                         $rowsAffected += $this->update($newRefs, $where);
       
  1142                         break;
       
  1143                     default:
       
  1144                         // no action
       
  1145                         break;
       
  1146                 }
       
  1147             }
       
  1148         }
       
  1149         return $rowsAffected;
       
  1150     }
       
  1151 
       
  1152     /**
       
  1153      * Deletes existing rows.
       
  1154      *
       
  1155      * @param  array|string $where SQL WHERE clause(s).
       
  1156      * @return int          The number of rows deleted.
       
  1157      */
       
  1158     public function delete($where)
       
  1159     {
       
  1160         $tableSpec = ($this->_schema ? $this->_schema . '.' : '') . $this->_name;
       
  1161         return $this->_db->delete($tableSpec, $where);
       
  1162     }
       
  1163 
       
  1164     /**
       
  1165      * Called by parent table's class during delete() method.
       
  1166      *
       
  1167      * @param  string $parentTableClassname
       
  1168      * @param  array  $primaryKey
       
  1169      * @return int    Number of affected rows
       
  1170      */
       
  1171     public function _cascadeDelete($parentTableClassname, array $primaryKey)
       
  1172     {
       
  1173         $this->_setupMetadata();
       
  1174         $rowsAffected = 0;
       
  1175         foreach ($this->_getReferenceMapNormalized() as $map) {
       
  1176             if ($map[self::REF_TABLE_CLASS] == $parentTableClassname && isset($map[self::ON_DELETE])) {
       
  1177                 switch ($map[self::ON_DELETE]) {
       
  1178                     case self::CASCADE:
       
  1179                         $where = array();
       
  1180                         for ($i = 0; $i < count($map[self::COLUMNS]); ++$i) {
       
  1181                             $col = $this->_db->foldCase($map[self::COLUMNS][$i]);
       
  1182                             $refCol = $this->_db->foldCase($map[self::REF_COLUMNS][$i]);
       
  1183                             $type = $this->_metadata[$col]['DATA_TYPE'];
       
  1184                             $where[] = $this->_db->quoteInto(
       
  1185                                 $this->_db->quoteIdentifier($col, true) . ' = ?',
       
  1186                                 $primaryKey[$refCol], $type);
       
  1187                         }
       
  1188                         $rowsAffected += $this->delete($where);
       
  1189                         break;
       
  1190                     default:
       
  1191                         // no action
       
  1192                         break;
       
  1193                 }
       
  1194             }
       
  1195         }
       
  1196         return $rowsAffected;
       
  1197     }
       
  1198 
       
  1199     /**
       
  1200      * Fetches rows by primary key.  The argument specifies one or more primary
       
  1201      * key value(s).  To find multiple rows by primary key, the argument must
       
  1202      * be an array.
       
  1203      *
       
  1204      * This method accepts a variable number of arguments.  If the table has a
       
  1205      * multi-column primary key, the number of arguments must be the same as
       
  1206      * the number of columns in the primary key.  To find multiple rows in a
       
  1207      * table with a multi-column primary key, each argument must be an array
       
  1208      * with the same number of elements.
       
  1209      *
       
  1210      * The find() method always returns a Rowset object, even if only one row
       
  1211      * was found.
       
  1212      *
       
  1213      * @param  mixed $key The value(s) of the primary keys.
       
  1214      * @return Zend_Db_Table_Rowset_Abstract Row(s) matching the criteria.
       
  1215      * @throws Zend_Db_Table_Exception
       
  1216      */
       
  1217     public function find()
       
  1218     {
       
  1219         $this->_setupPrimaryKey();
       
  1220         $args = func_get_args();
       
  1221         $keyNames = array_values((array) $this->_primary);
       
  1222 
       
  1223         if (count($args) < count($keyNames)) {
       
  1224             require_once 'Zend/Db/Table/Exception.php';
       
  1225             throw new Zend_Db_Table_Exception("Too few columns for the primary key");
       
  1226         }
       
  1227 
       
  1228         if (count($args) > count($keyNames)) {
       
  1229             require_once 'Zend/Db/Table/Exception.php';
       
  1230             throw new Zend_Db_Table_Exception("Too many columns for the primary key");
       
  1231         }
       
  1232 
       
  1233         $whereList = array();
       
  1234         $numberTerms = 0;
       
  1235         foreach ($args as $keyPosition => $keyValues) {
       
  1236             $keyValuesCount = count($keyValues);
       
  1237             // Coerce the values to an array.
       
  1238             // Don't simply typecast to array, because the values
       
  1239             // might be Zend_Db_Expr objects.
       
  1240             if (!is_array($keyValues)) {
       
  1241                 $keyValues = array($keyValues);
       
  1242             }
       
  1243             if ($numberTerms == 0) {
       
  1244                 $numberTerms = $keyValuesCount;
       
  1245             } else if ($keyValuesCount != $numberTerms) {
       
  1246                 require_once 'Zend/Db/Table/Exception.php';
       
  1247                 throw new Zend_Db_Table_Exception("Missing value(s) for the primary key");
       
  1248             }
       
  1249             $keyValues = array_values($keyValues);
       
  1250             for ($i = 0; $i < $keyValuesCount; ++$i) {
       
  1251                 if (!isset($whereList[$i])) {
       
  1252                     $whereList[$i] = array();
       
  1253                 }
       
  1254                 $whereList[$i][$keyPosition] = $keyValues[$i];
       
  1255             }
       
  1256         }
       
  1257 
       
  1258         $whereClause = null;
       
  1259         if (count($whereList)) {
       
  1260             $whereOrTerms = array();
       
  1261             $tableName = $this->_db->quoteTableAs($this->_name, null, true);
       
  1262             foreach ($whereList as $keyValueSets) {
       
  1263                 $whereAndTerms = array();
       
  1264                 foreach ($keyValueSets as $keyPosition => $keyValue) {
       
  1265                     $type = $this->_metadata[$keyNames[$keyPosition]]['DATA_TYPE'];
       
  1266                     $columnName = $this->_db->quoteIdentifier($keyNames[$keyPosition], true);
       
  1267                     $whereAndTerms[] = $this->_db->quoteInto(
       
  1268                         $tableName . '.' . $columnName . ' = ?',
       
  1269                         $keyValue, $type);
       
  1270                 }
       
  1271                 $whereOrTerms[] = '(' . implode(' AND ', $whereAndTerms) . ')';
       
  1272             }
       
  1273             $whereClause = '(' . implode(' OR ', $whereOrTerms) . ')';
       
  1274         }
       
  1275 
       
  1276         // issue ZF-5775 (empty where clause should return empty rowset)
       
  1277         if ($whereClause == null) {
       
  1278             $rowsetClass = $this->getRowsetClass();
       
  1279             if (!class_exists($rowsetClass)) {
       
  1280                 require_once 'Zend/Loader.php';
       
  1281                 Zend_Loader::loadClass($rowsetClass);
       
  1282             }
       
  1283             return new $rowsetClass(array('table' => $this, 'rowClass' => $this->getRowClass(), 'stored' => true));
       
  1284         }
       
  1285 
       
  1286         return $this->fetchAll($whereClause);
       
  1287     }
       
  1288 
       
  1289     /**
       
  1290      * Fetches all rows.
       
  1291      *
       
  1292      * Honors the Zend_Db_Adapter fetch mode.
       
  1293      *
       
  1294      * @param string|array|Zend_Db_Table_Select $where  OPTIONAL An SQL WHERE clause or Zend_Db_Table_Select object.
       
  1295      * @param string|array                      $order  OPTIONAL An SQL ORDER clause.
       
  1296      * @param int                               $count  OPTIONAL An SQL LIMIT count.
       
  1297      * @param int                               $offset OPTIONAL An SQL LIMIT offset.
       
  1298      * @return Zend_Db_Table_Rowset_Abstract The row results per the Zend_Db_Adapter fetch mode.
       
  1299      */
       
  1300     public function fetchAll($where = null, $order = null, $count = null, $offset = null)
       
  1301     {
       
  1302         if (!($where instanceof Zend_Db_Table_Select)) {
       
  1303             $select = $this->select();
       
  1304 
       
  1305             if ($where !== null) {
       
  1306                 $this->_where($select, $where);
       
  1307             }
       
  1308 
       
  1309             if ($order !== null) {
       
  1310                 $this->_order($select, $order);
       
  1311             }
       
  1312 
       
  1313             if ($count !== null || $offset !== null) {
       
  1314                 $select->limit($count, $offset);
       
  1315             }
       
  1316 
       
  1317         } else {
       
  1318             $select = $where;
       
  1319         }
       
  1320 
       
  1321         $rows = $this->_fetch($select);
       
  1322 
       
  1323         $data  = array(
       
  1324             'table'    => $this,
       
  1325             'data'     => $rows,
       
  1326             'readOnly' => $select->isReadOnly(),
       
  1327             'rowClass' => $this->getRowClass(),
       
  1328             'stored'   => true
       
  1329         );
       
  1330 
       
  1331         $rowsetClass = $this->getRowsetClass();
       
  1332         if (!class_exists($rowsetClass)) {
       
  1333             require_once 'Zend/Loader.php';
       
  1334             Zend_Loader::loadClass($rowsetClass);
       
  1335         }
       
  1336         return new $rowsetClass($data);
       
  1337     }
       
  1338 
       
  1339     /**
       
  1340      * Fetches one row in an object of type Zend_Db_Table_Row_Abstract,
       
  1341      * or returns null if no row matches the specified criteria.
       
  1342      *
       
  1343      * @param string|array|Zend_Db_Table_Select $where  OPTIONAL An SQL WHERE clause or Zend_Db_Table_Select object.
       
  1344      * @param string|array                      $order  OPTIONAL An SQL ORDER clause.
       
  1345      * @return Zend_Db_Table_Row_Abstract|null The row results per the
       
  1346      *     Zend_Db_Adapter fetch mode, or null if no row found.
       
  1347      */
       
  1348     public function fetchRow($where = null, $order = null)
       
  1349     {
       
  1350         if (!($where instanceof Zend_Db_Table_Select)) {
       
  1351             $select = $this->select();
       
  1352 
       
  1353             if ($where !== null) {
       
  1354                 $this->_where($select, $where);
       
  1355             }
       
  1356 
       
  1357             if ($order !== null) {
       
  1358                 $this->_order($select, $order);
       
  1359             }
       
  1360 
       
  1361             $select->limit(1);
       
  1362 
       
  1363         } else {
       
  1364             $select = $where->limit(1);
       
  1365         }
       
  1366 
       
  1367         $rows = $this->_fetch($select);
       
  1368 
       
  1369         if (count($rows) == 0) {
       
  1370             return null;
       
  1371         }
       
  1372 
       
  1373         $data = array(
       
  1374             'table'   => $this,
       
  1375             'data'     => $rows[0],
       
  1376             'readOnly' => $select->isReadOnly(),
       
  1377             'stored'  => true
       
  1378         );
       
  1379 
       
  1380         $rowClass = $this->getRowClass();
       
  1381         if (!class_exists($rowClass)) {
       
  1382             require_once 'Zend/Loader.php';
       
  1383             Zend_Loader::loadClass($rowClass);
       
  1384         }
       
  1385         return new $rowClass($data);
       
  1386     }
       
  1387 
       
  1388     /**
       
  1389      * Fetches a new blank row (not from the database).
       
  1390      *
       
  1391      * @return Zend_Db_Table_Row_Abstract
       
  1392      * @deprecated since 0.9.3 - use createRow() instead.
       
  1393      */
       
  1394     public function fetchNew()
       
  1395     {
       
  1396         return $this->createRow();
       
  1397     }
       
  1398 
       
  1399     /**
       
  1400      * Fetches a new blank row (not from the database).
       
  1401      *
       
  1402      * @param  array $data OPTIONAL data to populate in the new row.
       
  1403      * @param  string $defaultSource OPTIONAL flag to force default values into new row
       
  1404      * @return Zend_Db_Table_Row_Abstract
       
  1405      */
       
  1406     public function createRow(array $data = array(), $defaultSource = null)
       
  1407     {
       
  1408         $cols     = $this->_getCols();
       
  1409         $defaults = array_combine($cols, array_fill(0, count($cols), null));
       
  1410 
       
  1411         // nothing provided at call-time, take the class value
       
  1412         if ($defaultSource == null) {
       
  1413             $defaultSource = $this->_defaultSource;
       
  1414         }
       
  1415 
       
  1416         if (!in_array($defaultSource, array(self::DEFAULT_CLASS, self::DEFAULT_DB, self::DEFAULT_NONE))) {
       
  1417             $defaultSource = self::DEFAULT_NONE;
       
  1418         }
       
  1419 
       
  1420         if ($defaultSource == self::DEFAULT_DB) {
       
  1421             foreach ($this->_metadata as $metadataName => $metadata) {
       
  1422                 if (($metadata['DEFAULT'] != null) &&
       
  1423                     ($metadata['NULLABLE'] !== true || ($metadata['NULLABLE'] === true && isset($this->_defaultValues[$metadataName]) && $this->_defaultValues[$metadataName] === true)) &&
       
  1424                     (!(isset($this->_defaultValues[$metadataName]) && $this->_defaultValues[$metadataName] === false))) {
       
  1425                     $defaults[$metadataName] = $metadata['DEFAULT'];
       
  1426                 }
       
  1427             }
       
  1428         } elseif ($defaultSource == self::DEFAULT_CLASS && $this->_defaultValues) {
       
  1429             foreach ($this->_defaultValues as $defaultName => $defaultValue) {
       
  1430                 if (array_key_exists($defaultName, $defaults)) {
       
  1431                     $defaults[$defaultName] = $defaultValue;
       
  1432                 }
       
  1433             }
       
  1434         }
       
  1435 
       
  1436         $config = array(
       
  1437             'table'    => $this,
       
  1438             'data'     => $defaults,
       
  1439             'readOnly' => false,
       
  1440             'stored'   => false
       
  1441         );
       
  1442 
       
  1443         $rowClass = $this->getRowClass();
       
  1444         if (!class_exists($rowClass)) {
       
  1445             require_once 'Zend/Loader.php';
       
  1446             Zend_Loader::loadClass($rowClass);
       
  1447         }
       
  1448         $row = new $rowClass($config);
       
  1449         $row->setFromArray($data);
       
  1450         return $row;
       
  1451     }
       
  1452 
       
  1453     /**
       
  1454      * Generate WHERE clause from user-supplied string or array
       
  1455      *
       
  1456      * @param  string|array $where  OPTIONAL An SQL WHERE clause.
       
  1457      * @return Zend_Db_Table_Select
       
  1458      */
       
  1459     protected function _where(Zend_Db_Table_Select $select, $where)
       
  1460     {
       
  1461         $where = (array) $where;
       
  1462 
       
  1463         foreach ($where as $key => $val) {
       
  1464             // is $key an int?
       
  1465             if (is_int($key)) {
       
  1466                 // $val is the full condition
       
  1467                 $select->where($val);
       
  1468             } else {
       
  1469                 // $key is the condition with placeholder,
       
  1470                 // and $val is quoted into the condition
       
  1471                 $select->where($key, $val);
       
  1472             }
       
  1473         }
       
  1474 
       
  1475         return $select;
       
  1476     }
       
  1477 
       
  1478     /**
       
  1479      * Generate ORDER clause from user-supplied string or array
       
  1480      *
       
  1481      * @param  string|array $order  OPTIONAL An SQL ORDER clause.
       
  1482      * @return Zend_Db_Table_Select
       
  1483      */
       
  1484     protected function _order(Zend_Db_Table_Select $select, $order)
       
  1485     {
       
  1486         if (!is_array($order)) {
       
  1487             $order = array($order);
       
  1488         }
       
  1489 
       
  1490         foreach ($order as $val) {
       
  1491             $select->order($val);
       
  1492         }
       
  1493 
       
  1494         return $select;
       
  1495     }
       
  1496 
       
  1497     /**
       
  1498      * Support method for fetching rows.
       
  1499      *
       
  1500      * @param  Zend_Db_Table_Select $select  query options.
       
  1501      * @return array An array containing the row results in FETCH_ASSOC mode.
       
  1502      */
       
  1503     protected function _fetch(Zend_Db_Table_Select $select)
       
  1504     {
       
  1505         $stmt = $this->_db->query($select);
       
  1506         $data = $stmt->fetchAll(Zend_Db::FETCH_ASSOC);
       
  1507         return $data;
       
  1508     }
       
  1509 
       
  1510 }