"Fossies" - the Fresh Open Source Software Archive

Member "icingaweb2-2.9.1/library/vendor/Zend/Db/Table/Abstract.php" (27 Jul 2021, 52341 Bytes) of package /linux/www/icingaweb2-2.9.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

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