summaryrefslogtreecommitdiffstats
path: root/library/vendor/Zend/Db/Table/Abstract.php
diff options
context:
space:
mode:
Diffstat (limited to 'library/vendor/Zend/Db/Table/Abstract.php')
-rw-r--r--library/vendor/Zend/Db/Table/Abstract.php1599
1 files changed, 1599 insertions, 0 deletions
diff --git a/library/vendor/Zend/Db/Table/Abstract.php b/library/vendor/Zend/Db/Table/Abstract.php
new file mode 100644
index 0000000..ea393f2
--- /dev/null
+++ b/library/vendor/Zend/Db/Table/Abstract.php
@@ -0,0 +1,1599 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category Zend
+ * @package Zend_Db
+ * @subpackage Table
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/**
+ * @see Zend_Db_Adapter_Abstract
+ */
+
+/**
+ * @see Zend_Db_Adapter_Abstract
+ */
+
+/**
+ * @see Zend_Db
+ */
+
+/**
+ * Class for SQL table interface.
+ *
+ * @category Zend
+ * @package Zend_Db
+ * @subpackage Table
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+abstract class Zend_Db_Table_Abstract
+{
+
+ const ADAPTER = 'db';
+ const DEFINITION = 'definition';
+ const DEFINITION_CONFIG_NAME = 'definitionConfigName';
+ const SCHEMA = 'schema';
+ const NAME = 'name';
+ const PRIMARY = 'primary';
+ const COLS = 'cols';
+ const METADATA = 'metadata';
+ const METADATA_CACHE = 'metadataCache';
+ const METADATA_CACHE_IN_CLASS = 'metadataCacheInClass';
+ const ROW_CLASS = 'rowClass';
+ const ROWSET_CLASS = 'rowsetClass';
+ const REFERENCE_MAP = 'referenceMap';
+ const DEPENDENT_TABLES = 'dependentTables';
+ const SEQUENCE = 'sequence';
+
+ const COLUMNS = 'columns';
+ const REF_TABLE_CLASS = 'refTableClass';
+ const REF_COLUMNS = 'refColumns';
+ const ON_DELETE = 'onDelete';
+ const ON_UPDATE = 'onUpdate';
+
+ const CASCADE = 'cascade';
+ const CASCADE_RECURSE = 'cascadeRecurse';
+ const RESTRICT = 'restrict';
+ const SET_NULL = 'setNull';
+
+ const DEFAULT_NONE = 'defaultNone';
+ const DEFAULT_CLASS = 'defaultClass';
+ const DEFAULT_DB = 'defaultDb';
+
+ const SELECT_WITH_FROM_PART = true;
+ const SELECT_WITHOUT_FROM_PART = false;
+
+ /**
+ * Default Zend_Db_Adapter_Abstract object.
+ *
+ * @var Zend_Db_Adapter_Abstract
+ */
+ protected static $_defaultDb;
+
+ /**
+ * Optional Zend_Db_Table_Definition object
+ *
+ * @var unknown_type
+ */
+ protected $_definition = null;
+
+ /**
+ * Optional definition config name used in concrete implementation
+ *
+ * @var string
+ */
+ protected $_definitionConfigName = null;
+
+ /**
+ * Default cache for information provided by the adapter's describeTable() method.
+ *
+ * @var Zend_Cache_Core
+ */
+ protected static $_defaultMetadataCache = null;
+
+ /**
+ * Zend_Db_Adapter_Abstract object.
+ *
+ * @var Zend_Db_Adapter_Abstract
+ */
+ protected $_db;
+
+ /**
+ * The schema name (default null means current schema)
+ *
+ * @var array
+ */
+ protected $_schema = null;
+
+ /**
+ * The table name.
+ *
+ * @var string
+ */
+ protected $_name = null;
+
+ /**
+ * The table column names derived from Zend_Db_Adapter_Abstract::describeTable().
+ *
+ * @var array
+ */
+ protected $_cols;
+
+ /**
+ * The primary key column or columns.
+ * A compound key should be declared as an array.
+ * You may declare a single-column primary key
+ * as a string.
+ *
+ * @var mixed
+ */
+ protected $_primary = null;
+
+ /**
+ * If your primary key is a compound key, and one of the columns uses
+ * an auto-increment or sequence-generated value, set _identity
+ * to the ordinal index in the $_primary array for that column.
+ * Note this index is the position of the column in the primary key,
+ * not the position of the column in the table. The primary key
+ * array is 1-based.
+ *
+ * @var integer
+ */
+ protected $_identity = 1;
+
+ /**
+ * Define the logic for new values in the primary key.
+ * May be a string, boolean true, or boolean false.
+ *
+ * @var mixed
+ */
+ protected $_sequence = true;
+
+ /**
+ * Information provided by the adapter's describeTable() method.
+ *
+ * @var array
+ */
+ protected $_metadata = array();
+
+ /**
+ * Cache for information provided by the adapter's describeTable() method.
+ *
+ * @var Zend_Cache_Core
+ */
+ protected $_metadataCache = null;
+
+ /**
+ * Flag: whether or not to cache metadata in the class
+ * @var bool
+ */
+ protected $_metadataCacheInClass = true;
+
+ /**
+ * Classname for row
+ *
+ * @var string
+ */
+ protected $_rowClass = 'Zend_Db_Table_Row';
+
+ /**
+ * Classname for rowset
+ *
+ * @var string
+ */
+ protected $_rowsetClass = 'Zend_Db_Table_Rowset';
+
+ /**
+ * Associative array map of declarative referential integrity rules.
+ * This array has one entry per foreign key in the current table.
+ * Each key is a mnemonic name for one reference rule.
+ *
+ * Each value is also an associative array, with the following keys:
+ * - columns = array of names of column(s) in the child table.
+ * - refTableClass = class name of the parent table.
+ * - refColumns = array of names of column(s) in the parent table,
+ * in the same order as those in the 'columns' entry.
+ * - onDelete = "cascade" means that a delete in the parent table also
+ * causes a delete of referencing rows in the child table.
+ * - onUpdate = "cascade" means that an update of primary key values in
+ * the parent table also causes an update of referencing
+ * rows in the child table.
+ *
+ * @var array
+ */
+ protected $_referenceMap = array();
+
+ /**
+ * Simple array of class names of tables that are "children" of the current
+ * table, in other words tables that contain a foreign key to this one.
+ * Array elements are not table names; they are class names of classes that
+ * extend Zend_Db_Table_Abstract.
+ *
+ * @var array
+ */
+ protected $_dependentTables = array();
+
+
+ protected $_defaultSource = self::DEFAULT_NONE;
+ protected $_defaultValues = array();
+
+ /**
+ * Constructor.
+ *
+ * Supported params for $config are:
+ * - db = user-supplied instance of database connector,
+ * or key name of registry instance.
+ * - name = table name.
+ * - primary = string or array of primary key(s).
+ * - rowClass = row class name.
+ * - rowsetClass = rowset class name.
+ * - referenceMap = array structure to declare relationship
+ * to parent tables.
+ * - dependentTables = array of child tables.
+ * - metadataCache = cache for information from adapter describeTable().
+ *
+ * @param mixed $config Array of user-specified config options, or just the Db Adapter.
+ * @return void
+ */
+ public function __construct($config = array())
+ {
+ /**
+ * Allow a scalar argument to be the Adapter object or Registry key.
+ */
+ if (!is_array($config)) {
+ $config = array(self::ADAPTER => $config);
+ }
+
+ if ($config) {
+ $this->setOptions($config);
+ }
+
+ $this->_setup();
+ $this->init();
+ }
+
+ /**
+ * setOptions()
+ *
+ * @param array $options
+ * @return Zend_Db_Table_Abstract
+ */
+ public function setOptions(Array $options)
+ {
+ foreach ($options as $key => $value) {
+ switch ($key) {
+ case self::ADAPTER:
+ $this->_setAdapter($value);
+ break;
+ case self::DEFINITION:
+ $this->setDefinition($value);
+ break;
+ case self::DEFINITION_CONFIG_NAME:
+ $this->setDefinitionConfigName($value);
+ break;
+ case self::SCHEMA:
+ $this->_schema = (string) $value;
+ break;
+ case self::NAME:
+ $this->_name = (string) $value;
+ break;
+ case self::PRIMARY:
+ $this->_primary = (array) $value;
+ break;
+ case self::ROW_CLASS:
+ $this->setRowClass($value);
+ break;
+ case self::ROWSET_CLASS:
+ $this->setRowsetClass($value);
+ break;
+ case self::REFERENCE_MAP:
+ $this->setReferences($value);
+ break;
+ case self::DEPENDENT_TABLES:
+ $this->setDependentTables($value);
+ break;
+ case self::METADATA_CACHE:
+ $this->_setMetadataCache($value);
+ break;
+ case self::METADATA_CACHE_IN_CLASS:
+ $this->setMetadataCacheInClass($value);
+ break;
+ case self::SEQUENCE:
+ $this->_setSequence($value);
+ break;
+ default:
+ // ignore unrecognized configuration directive
+ break;
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * setDefinition()
+ *
+ * @param Zend_Db_Table_Definition $definition
+ * @return Zend_Db_Table_Abstract
+ */
+ public function setDefinition(Zend_Db_Table_Definition $definition)
+ {
+ $this->_definition = $definition;
+ return $this;
+ }
+
+ /**
+ * getDefinition()
+ *
+ * @return Zend_Db_Table_Definition|null
+ */
+ public function getDefinition()
+ {
+ return $this->_definition;
+ }
+
+ /**
+ * setDefinitionConfigName()
+ *
+ * @param string $definition
+ * @return Zend_Db_Table_Abstract
+ */
+ public function setDefinitionConfigName($definitionConfigName)
+ {
+ $this->_definitionConfigName = $definitionConfigName;
+ return $this;
+ }
+
+ /**
+ * getDefinitionConfigName()
+ *
+ * @return string
+ */
+ public function getDefinitionConfigName()
+ {
+ return $this->_definitionConfigName;
+ }
+
+ /**
+ * @param string $classname
+ * @return Zend_Db_Table_Abstract Provides a fluent interface
+ */
+ public function setRowClass($classname)
+ {
+ $this->_rowClass = (string) $classname;
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getRowClass()
+ {
+ return $this->_rowClass;
+ }
+
+ /**
+ * @param string $classname
+ * @return Zend_Db_Table_Abstract Provides a fluent interface
+ */
+ public function setRowsetClass($classname)
+ {
+ $this->_rowsetClass = (string) $classname;
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getRowsetClass()
+ {
+ return $this->_rowsetClass;
+ }
+
+ /**
+ * Add a reference to the reference map
+ *
+ * @param string $ruleKey
+ * @param string|array $columns
+ * @param string $refTableClass
+ * @param string|array $refColumns
+ * @param string $onDelete
+ * @param string $onUpdate
+ * @return Zend_Db_Table_Abstract
+ */
+ public function addReference($ruleKey, $columns, $refTableClass, $refColumns,
+ $onDelete = null, $onUpdate = null)
+ {
+ $reference = array(self::COLUMNS => (array) $columns,
+ self::REF_TABLE_CLASS => $refTableClass,
+ self::REF_COLUMNS => (array) $refColumns);
+
+ if (!empty($onDelete)) {
+ $reference[self::ON_DELETE] = $onDelete;
+ }
+
+ if (!empty($onUpdate)) {
+ $reference[self::ON_UPDATE] = $onUpdate;
+ }
+
+ $this->_referenceMap[$ruleKey] = $reference;
+
+ return $this;
+ }
+
+ /**
+ * @param array $referenceMap
+ * @return Zend_Db_Table_Abstract Provides a fluent interface
+ */
+ public function setReferences(array $referenceMap)
+ {
+ $this->_referenceMap = $referenceMap;
+
+ return $this;
+ }
+
+ /**
+ * @param string $tableClassname
+ * @param string $ruleKey OPTIONAL
+ * @return array
+ * @throws Zend_Db_Table_Exception
+ */
+ public function getReference($tableClassname, $ruleKey = null)
+ {
+ $thisClass = get_class($this);
+ if ($thisClass === 'Zend_Db_Table') {
+ $thisClass = $this->_definitionConfigName;
+ }
+ $refMap = $this->_getReferenceMapNormalized();
+ if ($ruleKey !== null) {
+ if (!isset($refMap[$ruleKey])) {
+ throw new Zend_Db_Table_Exception("No reference rule \"$ruleKey\" from table $thisClass to table $tableClassname");
+ }
+ if ($refMap[$ruleKey][self::REF_TABLE_CLASS] != $tableClassname) {
+ throw new Zend_Db_Table_Exception("Reference rule \"$ruleKey\" does not reference table $tableClassname");
+ }
+ return $refMap[$ruleKey];
+ }
+ foreach ($refMap as $reference) {
+ if ($reference[self::REF_TABLE_CLASS] == $tableClassname) {
+ return $reference;
+ }
+ }
+ throw new Zend_Db_Table_Exception("No reference from table $thisClass to table $tableClassname");
+ }
+
+ /**
+ * @param array $dependentTables
+ * @return Zend_Db_Table_Abstract Provides a fluent interface
+ */
+ public function setDependentTables(array $dependentTables)
+ {
+ $this->_dependentTables = $dependentTables;
+
+ return $this;
+ }
+
+ /**
+ * @return array
+ */
+ public function getDependentTables()
+ {
+ return $this->_dependentTables;
+ }
+
+ /**
+ * set the defaultSource property - this tells the table class where to find default values
+ *
+ * @param string $defaultSource
+ * @return Zend_Db_Table_Abstract
+ */
+ public function setDefaultSource($defaultSource = self::DEFAULT_NONE)
+ {
+ if (!in_array($defaultSource, array(self::DEFAULT_CLASS, self::DEFAULT_DB, self::DEFAULT_NONE))) {
+ $defaultSource = self::DEFAULT_NONE;
+ }
+
+ $this->_defaultSource = $defaultSource;
+ return $this;
+ }
+
+ /**
+ * returns the default source flag that determines where defaultSources come from
+ *
+ * @return unknown
+ */
+ public function getDefaultSource()
+ {
+ return $this->_defaultSource;
+ }
+
+ /**
+ * set the default values for the table class
+ *
+ * @param array $defaultValues
+ * @return Zend_Db_Table_Abstract
+ */
+ public function setDefaultValues(Array $defaultValues)
+ {
+ foreach ($defaultValues as $defaultName => $defaultValue) {
+ if (array_key_exists($defaultName, $this->_metadata)) {
+ $this->_defaultValues[$defaultName] = $defaultValue;
+ }
+ }
+ return $this;
+ }
+
+ public function getDefaultValues()
+ {
+ return $this->_defaultValues;
+ }
+
+
+ /**
+ * Sets the default Zend_Db_Adapter_Abstract for all Zend_Db_Table objects.
+ *
+ * @param mixed $db Either an Adapter object, or a string naming a Registry key
+ * @return void
+ */
+ public static function setDefaultAdapter($db = null)
+ {
+ self::$_defaultDb = self::_setupAdapter($db);
+ }
+
+ /**
+ * Gets the default Zend_Db_Adapter_Abstract for all Zend_Db_Table objects.
+ *
+ * @return Zend_Db_Adapter_Abstract or null
+ */
+ public static function getDefaultAdapter()
+ {
+ return self::$_defaultDb;
+ }
+
+ /**
+ * @param mixed $db Either an Adapter object, or a string naming a Registry key
+ * @return Zend_Db_Table_Abstract Provides a fluent interface
+ */
+ protected function _setAdapter($db)
+ {
+ $this->_db = self::_setupAdapter($db);
+ return $this;
+ }
+
+ /**
+ * Gets the Zend_Db_Adapter_Abstract for this particular Zend_Db_Table object.
+ *
+ * @return Zend_Db_Adapter_Abstract
+ */
+ public function getAdapter()
+ {
+ return $this->_db;
+ }
+
+ /**
+ * @param mixed $db Either an Adapter object, or a string naming a Registry key
+ * @return Zend_Db_Adapter_Abstract
+ * @throws Zend_Db_Table_Exception
+ */
+ protected static function _setupAdapter($db)
+ {
+ if ($db === null) {
+ return null;
+ }
+ if (is_string($db)) {
+ $db = Zend_Registry::get($db);
+ }
+ if (!$db instanceof Zend_Db_Adapter_Abstract) {
+ 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');
+ }
+ return $db;
+ }
+
+ /**
+ * Sets the default metadata cache for information returned by Zend_Db_Adapter_Abstract::describeTable().
+ *
+ * If $defaultMetadataCache is null, then no metadata cache is used by default.
+ *
+ * @param mixed $metadataCache Either a Cache object, or a string naming a Registry key
+ * @return void
+ */
+ public static function setDefaultMetadataCache($metadataCache = null)
+ {
+ self::$_defaultMetadataCache = self::_setupMetadataCache($metadataCache);
+ }
+
+ /**
+ * Gets the default metadata cache for information returned by Zend_Db_Adapter_Abstract::describeTable().
+ *
+ * @return Zend_Cache_Core or null
+ */
+ public static function getDefaultMetadataCache()
+ {
+ return self::$_defaultMetadataCache;
+ }
+
+ /**
+ * Sets the metadata cache for information returned by Zend_Db_Adapter_Abstract::describeTable().
+ *
+ * If $metadataCache is null, then no metadata cache is used. Since there is no opportunity to reload metadata
+ * after instantiation, this method need not be public, particularly because that it would have no effect
+ * results in unnecessary API complexity. To configure the metadata cache, use the metadataCache configuration
+ * option for the class constructor upon instantiation.
+ *
+ * @param mixed $metadataCache Either a Cache object, or a string naming a Registry key
+ * @return Zend_Db_Table_Abstract Provides a fluent interface
+ */
+ protected function _setMetadataCache($metadataCache)
+ {
+ $this->_metadataCache = self::_setupMetadataCache($metadataCache);
+ return $this;
+ }
+
+ /**
+ * Gets the metadata cache for information returned by Zend_Db_Adapter_Abstract::describeTable().
+ *
+ * @return Zend_Cache_Core or null
+ */
+ public function getMetadataCache()
+ {
+ return $this->_metadataCache;
+ }
+
+ /**
+ * Indicate whether metadata should be cached in the class for the duration
+ * of the instance
+ *
+ * @param bool $flag
+ * @return Zend_Db_Table_Abstract
+ */
+ public function setMetadataCacheInClass($flag)
+ {
+ $this->_metadataCacheInClass = (bool) $flag;
+ return $this;
+ }
+
+ /**
+ * Retrieve flag indicating if metadata should be cached for duration of
+ * instance
+ *
+ * @return bool
+ */
+ public function metadataCacheInClass()
+ {
+ return $this->_metadataCacheInClass;
+ }
+
+ /**
+ * @param mixed $metadataCache Either a Cache object, or a string naming a Registry key
+ * @return Zend_Cache_Core
+ * @throws Zend_Db_Table_Exception
+ */
+ protected static function _setupMetadataCache($metadataCache)
+ {
+ if ($metadataCache === null) {
+ return null;
+ }
+ if (is_string($metadataCache)) {
+ $metadataCache = Zend_Registry::get($metadataCache);
+ }
+ if (!$metadataCache instanceof Zend_Cache_Core) {
+ 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');
+ }
+ return $metadataCache;
+ }
+
+ /**
+ * Sets the sequence member, which defines the behavior for generating
+ * primary key values in new rows.
+ * - If this is a string, then the string names the sequence object.
+ * - If this is boolean true, then the key uses an auto-incrementing
+ * or identity mechanism.
+ * - If this is boolean false, then the key is user-defined.
+ * Use this for natural keys, for example.
+ *
+ * @param mixed $sequence
+ * @return Zend_Db_Table_Adapter_Abstract Provides a fluent interface
+ */
+ protected function _setSequence($sequence)
+ {
+ $this->_sequence = $sequence;
+
+ return $this;
+ }
+
+ /**
+ * Turnkey for initialization of a table object.
+ * Calls other protected methods for individual tasks, to make it easier
+ * for a subclass to override part of the setup logic.
+ *
+ * @return void
+ */
+ protected function _setup()
+ {
+ $this->_setupDatabaseAdapter();
+ $this->_setupTableName();
+ }
+
+ /**
+ * Initialize database adapter.
+ *
+ * @return void
+ * @throws Zend_Db_Table_Exception
+ */
+ protected function _setupDatabaseAdapter()
+ {
+ if (! $this->_db) {
+ $this->_db = self::getDefaultAdapter();
+ if (!$this->_db instanceof Zend_Db_Adapter_Abstract) {
+ throw new Zend_Db_Table_Exception('No adapter found for ' . get_class($this));
+ }
+ }
+ }
+
+ /**
+ * Initialize table and schema names.
+ *
+ * If the table name is not set in the class definition,
+ * use the class name itself as the table name.
+ *
+ * A schema name provided with the table name (e.g., "schema.table") overrides
+ * any existing value for $this->_schema.
+ *
+ * @return void
+ */
+ protected function _setupTableName()
+ {
+ if (! $this->_name) {
+ $this->_name = get_class($this);
+ } else if (strpos($this->_name, '.')) {
+ list($this->_schema, $this->_name) = explode('.', $this->_name);
+ }
+ }
+
+ /**
+ * Initializes metadata.
+ *
+ * If metadata cannot be loaded from cache, adapter's describeTable() method is called to discover metadata
+ * information. Returns true if and only if the metadata are loaded from cache.
+ *
+ * @return boolean
+ * @throws Zend_Db_Table_Exception
+ */
+ protected function _setupMetadata()
+ {
+ if ($this->metadataCacheInClass() && (count($this->_metadata) > 0)) {
+ return true;
+ }
+
+ // Assume that metadata will be loaded from cache
+ $isMetadataFromCache = true;
+
+ // If $this has no metadata cache but the class has a default metadata cache
+ if (null === $this->_metadataCache && null !== self::$_defaultMetadataCache) {
+ // Make $this use the default metadata cache of the class
+ $this->_setMetadataCache(self::$_defaultMetadataCache);
+ }
+
+ // If $this has a metadata cache
+ if (null !== $this->_metadataCache) {
+ // Define the cache identifier where the metadata are saved
+
+ //get db configuration
+ $dbConfig = $this->_db->getConfig();
+
+ $port = isset($dbConfig['options']['port'])
+ ? ':'.$dbConfig['options']['port']
+ : (isset($dbConfig['port'])
+ ? ':'.$dbConfig['port']
+ : null);
+
+ $host = isset($dbConfig['options']['host'])
+ ? ':'.$dbConfig['options']['host']
+ : (isset($dbConfig['host'])
+ ? ':'.$dbConfig['host']
+ : null);
+
+ // Define the cache identifier where the metadata are saved
+ $cacheId = md5( // port:host/dbname:schema.table (based on availabilty)
+ $port . $host . '/'. $dbConfig['dbname'] . ':'
+ . $this->_schema. '.' . $this->_name
+ );
+ }
+
+ // If $this has no metadata cache or metadata cache misses
+ if (null === $this->_metadataCache || !($metadata = $this->_metadataCache->load($cacheId))) {
+ // Metadata are not loaded from cache
+ $isMetadataFromCache = false;
+ // Fetch metadata from the adapter's describeTable() method
+ $metadata = $this->_db->describeTable($this->_name, $this->_schema);
+ // If $this has a metadata cache, then cache the metadata
+ if (null !== $this->_metadataCache && !$this->_metadataCache->save($metadata, $cacheId)) {
+ trigger_error('Failed saving metadata to metadataCache', E_USER_NOTICE);
+ }
+ }
+
+ // Assign the metadata to $this
+ $this->_metadata = $metadata;
+
+ // Return whether the metadata were loaded from cache
+ return $isMetadataFromCache;
+ }
+
+ /**
+ * Retrieve table columns
+ *
+ * @return array
+ */
+ protected function _getCols()
+ {
+ if (null === $this->_cols) {
+ $this->_setupMetadata();
+ $this->_cols = array_keys($this->_metadata);
+ }
+ return $this->_cols;
+ }
+
+ /**
+ * Initialize primary key from metadata.
+ * If $_primary is not defined, discover primary keys
+ * from the information returned by describeTable().
+ *
+ * @return void
+ * @throws Zend_Db_Table_Exception
+ */
+ protected function _setupPrimaryKey()
+ {
+ if (!$this->_primary) {
+ $this->_setupMetadata();
+ $this->_primary = array();
+ foreach ($this->_metadata as $col) {
+ if ($col['PRIMARY']) {
+ $this->_primary[ $col['PRIMARY_POSITION'] ] = $col['COLUMN_NAME'];
+ if ($col['IDENTITY']) {
+ $this->_identity = $col['PRIMARY_POSITION'];
+ }
+ }
+ }
+ // if no primary key was specified and none was found in the metadata
+ // then throw an exception.
+ if (empty($this->_primary)) {
+ throw new Zend_Db_Table_Exception("A table must have a primary key, but none was found for table '{$this->_name}'");
+ }
+ } else if (!is_array($this->_primary)) {
+ $this->_primary = array(1 => $this->_primary);
+ } else if (isset($this->_primary[0])) {
+ array_unshift($this->_primary, null);
+ unset($this->_primary[0]);
+ }
+
+ $cols = $this->_getCols();
+ if (! array_intersect((array) $this->_primary, $cols) == (array) $this->_primary) {
+ throw new Zend_Db_Table_Exception("Primary key column(s) ("
+ . implode(',', (array) $this->_primary)
+ . ") are not columns in this table ("
+ . implode(',', $cols)
+ . ")");
+ }
+
+ $primary = (array) $this->_primary;
+ $pkIdentity = $primary[(int) $this->_identity];
+
+ /**
+ * Special case for PostgreSQL: a SERIAL key implicitly uses a sequence
+ * object whose name is "<table>_<column>_seq".
+ */
+ if ($this->_sequence === true && $this->_db instanceof Zend_Db_Adapter_Pdo_Pgsql) {
+ $this->_sequence = $this->_db->quoteIdentifier("{$this->_name}_{$pkIdentity}_seq");
+ if ($this->_schema) {
+ $this->_sequence = $this->_db->quoteIdentifier($this->_schema) . '.' . $this->_sequence;
+ }
+ }
+ }
+
+ /**
+ * Returns a normalized version of the reference map
+ *
+ * @return array
+ */
+ protected function _getReferenceMapNormalized()
+ {
+ $referenceMapNormalized = array();
+
+ foreach ($this->_referenceMap as $rule => $map) {
+
+ $referenceMapNormalized[$rule] = array();
+
+ foreach ($map as $key => $value) {
+ switch ($key) {
+
+ // normalize COLUMNS and REF_COLUMNS to arrays
+ case self::COLUMNS:
+ case self::REF_COLUMNS:
+ if (!is_array($value)) {
+ $referenceMapNormalized[$rule][$key] = array($value);
+ } else {
+ $referenceMapNormalized[$rule][$key] = $value;
+ }
+ break;
+
+ // other values are copied as-is
+ default:
+ $referenceMapNormalized[$rule][$key] = $value;
+ break;
+ }
+ }
+ }
+
+ return $referenceMapNormalized;
+ }
+
+ /**
+ * Initialize object
+ *
+ * Called from {@link __construct()} as final step of object instantiation.
+ *
+ * @return void
+ */
+ public function init()
+ {
+ }
+
+ /**
+ * Returns table information.
+ *
+ * You can elect to return only a part of this information by supplying its key name,
+ * otherwise all information is returned as an array.
+ *
+ * @param string $key The specific info part to return OPTIONAL
+ * @return mixed
+ * @throws Zend_Db_Table_Exception
+ */
+ public function info($key = null)
+ {
+ $this->_setupPrimaryKey();
+
+ $info = array(
+ self::SCHEMA => $this->_schema,
+ self::NAME => $this->_name,
+ self::COLS => $this->_getCols(),
+ self::PRIMARY => (array) $this->_primary,
+ self::METADATA => $this->_metadata,
+ self::ROW_CLASS => $this->getRowClass(),
+ self::ROWSET_CLASS => $this->getRowsetClass(),
+ self::REFERENCE_MAP => $this->_referenceMap,
+ self::DEPENDENT_TABLES => $this->_dependentTables,
+ self::SEQUENCE => $this->_sequence
+ );
+
+ if ($key === null) {
+ return $info;
+ }
+
+ if (!array_key_exists($key, $info)) {
+ throw new Zend_Db_Table_Exception('There is no table information for the key "' . $key . '"');
+ }
+
+ return $info[$key];
+ }
+
+ /**
+ * Returns an instance of a Zend_Db_Table_Select object.
+ *
+ * @param bool $withFromPart Whether or not to include the from part of the select based on the table
+ * @return Zend_Db_Table_Select
+ */
+ public function select($withFromPart = self::SELECT_WITHOUT_FROM_PART)
+ {
+ $select = new Zend_Db_Table_Select($this);
+ if ($withFromPart == self::SELECT_WITH_FROM_PART) {
+ $select->from($this->info(self::NAME), Zend_Db_Table_Select::SQL_WILDCARD, $this->info(self::SCHEMA));
+ }
+ return $select;
+ }
+
+ /**
+ * Inserts a new row.
+ *
+ * @param array $data Column-value pairs.
+ * @return mixed The primary key of the row inserted.
+ */
+ public function insert(array $data)
+ {
+ $this->_setupPrimaryKey();
+
+ /**
+ * Zend_Db_Table assumes that if you have a compound primary key
+ * and one of the columns in the key uses a sequence,
+ * it's the _first_ column in the compound key.
+ */
+ $primary = (array) $this->_primary;
+ $pkIdentity = $primary[(int)$this->_identity];
+
+
+ /**
+ * If the primary key can be generated automatically, and no value was
+ * specified in the user-supplied data, then omit it from the tuple.
+ *
+ * Note: this checks for sensible values in the supplied primary key
+ * position of the data. The following values are considered empty:
+ * null, false, true, '', array()
+ */
+ if (array_key_exists($pkIdentity, $data)) {
+ if ($data[$pkIdentity] === null // null
+ || $data[$pkIdentity] === '' // empty string
+ || is_bool($data[$pkIdentity]) // boolean
+ || (is_array($data[$pkIdentity]) && empty($data[$pkIdentity]))) { // empty array
+ unset($data[$pkIdentity]);
+ }
+ }
+
+ /**
+ * If this table uses a database sequence object and the data does not
+ * specify a value, then get the next ID from the sequence and add it
+ * to the row. We assume that only the first column in a compound
+ * primary key takes a value from a sequence.
+ */
+ if (is_string($this->_sequence) && !isset($data[$pkIdentity])) {
+ $data[$pkIdentity] = $this->_db->nextSequenceId($this->_sequence);
+ }
+
+ /**
+ * INSERT the new row.
+ */
+ $tableSpec = ($this->_schema ? $this->_schema . '.' : '') . $this->_name;
+ $this->_db->insert($tableSpec, $data);
+
+ /**
+ * Fetch the most recent ID generated by an auto-increment
+ * or IDENTITY column, unless the user has specified a value,
+ * overriding the auto-increment mechanism.
+ */
+ if ($this->_sequence === true && !isset($data[$pkIdentity])) {
+ $data[$pkIdentity] = $this->_db->lastInsertId();
+ }
+
+ /**
+ * Return the primary key value if the PK is a single column,
+ * else return an associative array of the PK column/value pairs.
+ */
+ $pkData = array_intersect_key($data, array_flip($primary));
+ if (count($primary) == 1) {
+ reset($pkData);
+ return current($pkData);
+ }
+
+ return $pkData;
+ }
+
+ /**
+ * Check if the provided column is an identity of the table
+ *
+ * @param string $column
+ * @throws Zend_Db_Table_Exception
+ * @return boolean
+ */
+ public function isIdentity($column)
+ {
+ $this->_setupPrimaryKey();
+
+ if (!isset($this->_metadata[$column])) {
+ /**
+ * @see Zend_Db_Table_Exception
+ */
+
+ throw new Zend_Db_Table_Exception('Column "' . $column . '" not found in table.');
+ }
+
+ return (bool) $this->_metadata[$column]['IDENTITY'];
+ }
+
+ /**
+ * Updates existing rows.
+ *
+ * @param array $data Column-value pairs.
+ * @param array|string $where An SQL WHERE clause, or an array of SQL WHERE clauses.
+ * @return int The number of rows updated.
+ */
+ public function update(array $data, $where)
+ {
+ $tableSpec = ($this->_schema ? $this->_schema . '.' : '') . $this->_name;
+ return $this->_db->update($tableSpec, $data, $where);
+ }
+
+ /**
+ * Called by a row object for the parent table's class during save() method.
+ *
+ * @param string $parentTableClassname
+ * @param array $oldPrimaryKey
+ * @param array $newPrimaryKey
+ * @return int
+ */
+ public function _cascadeUpdate($parentTableClassname, array $oldPrimaryKey, array $newPrimaryKey)
+ {
+ $this->_setupMetadata();
+ $rowsAffected = 0;
+ foreach ($this->_getReferenceMapNormalized() as $map) {
+ if ($map[self::REF_TABLE_CLASS] == $parentTableClassname && isset($map[self::ON_UPDATE])) {
+ switch ($map[self::ON_UPDATE]) {
+ case self::CASCADE:
+ $newRefs = array();
+ $where = array();
+ for ($i = 0; $i < count($map[self::COLUMNS]); ++$i) {
+ $col = $this->_db->foldCase($map[self::COLUMNS][$i]);
+ $refCol = $this->_db->foldCase($map[self::REF_COLUMNS][$i]);
+ if (array_key_exists($refCol, $newPrimaryKey)) {
+ $newRefs[$col] = $newPrimaryKey[$refCol];
+ }
+ $type = $this->_metadata[$col]['DATA_TYPE'];
+ $where[] = $this->_db->quoteInto(
+ $this->_db->quoteIdentifier($col, true) . ' = ?',
+ $oldPrimaryKey[$refCol], $type);
+ }
+ $rowsAffected += $this->update($newRefs, $where);
+ break;
+ default:
+ // no action
+ break;
+ }
+ }
+ }
+ return $rowsAffected;
+ }
+
+ /**
+ * Deletes existing rows.
+ *
+ * @param array|string $where SQL WHERE clause(s).
+ * @return int The number of rows deleted.
+ */
+ public function delete($where)
+ {
+ $depTables = $this->getDependentTables();
+ if (!empty($depTables)) {
+ $resultSet = $this->fetchAll($where);
+ if (count($resultSet) > 0 ) {
+ foreach ($resultSet as $row) {
+ /**
+ * Execute cascading deletes against dependent tables
+ */
+ foreach ($depTables as $tableClass) {
+ $t = self::getTableFromString($tableClass, $this);
+ $t->_cascadeDelete(
+ get_class($this), $row->getPrimaryKey()
+ );
+ }
+ }
+ }
+ }
+
+ $tableSpec = ($this->_schema ? $this->_schema . '.' : '') . $this->_name;
+ return $this->_db->delete($tableSpec, $where);
+ }
+
+ /**
+ * Called by parent table's class during delete() method.
+ *
+ * @param string $parentTableClassname
+ * @param array $primaryKey
+ * @return int Number of affected rows
+ */
+ public function _cascadeDelete($parentTableClassname, array $primaryKey)
+ {
+ // setup metadata
+ $this->_setupMetadata();
+
+ // get this class name
+ $thisClass = get_class($this);
+ if ($thisClass === 'Zend_Db_Table') {
+ $thisClass = $this->_definitionConfigName;
+ }
+
+ $rowsAffected = 0;
+
+ foreach ($this->_getReferenceMapNormalized() as $map) {
+ if ($map[self::REF_TABLE_CLASS] == $parentTableClassname && isset($map[self::ON_DELETE])) {
+
+ $where = array();
+
+ // CASCADE or CASCADE_RECURSE
+ if (in_array($map[self::ON_DELETE], array(self::CASCADE, self::CASCADE_RECURSE))) {
+ for ($i = 0; $i < count($map[self::COLUMNS]); ++$i) {
+ $col = $this->_db->foldCase($map[self::COLUMNS][$i]);
+ $refCol = $this->_db->foldCase($map[self::REF_COLUMNS][$i]);
+ $type = $this->_metadata[$col]['DATA_TYPE'];
+ $where[] = $this->_db->quoteInto(
+ $this->_db->quoteIdentifier($col, true) . ' = ?',
+ $primaryKey[$refCol], $type);
+ }
+ }
+
+ // CASCADE_RECURSE
+ if ($map[self::ON_DELETE] == self::CASCADE_RECURSE) {
+
+ /**
+ * Execute cascading deletes against dependent tables
+ */
+ $depTables = $this->getDependentTables();
+ if (!empty($depTables)) {
+ foreach ($depTables as $tableClass) {
+ $t = self::getTableFromString($tableClass, $this);
+ foreach ($this->fetchAll($where) as $depRow) {
+ $rowsAffected += $t->_cascadeDelete($thisClass, $depRow->getPrimaryKey());
+ }
+ }
+ }
+ }
+
+ // CASCADE or CASCADE_RECURSE
+ if (in_array($map[self::ON_DELETE], array(self::CASCADE, self::CASCADE_RECURSE))) {
+ $rowsAffected += $this->delete($where);
+ }
+
+ }
+ }
+ return $rowsAffected;
+ }
+
+ /**
+ * Fetches rows by primary key. The argument specifies one or more primary
+ * key value(s). To find multiple rows by primary key, the argument must
+ * be an array.
+ *
+ * This method accepts a variable number of arguments. If the table has a
+ * multi-column primary key, the number of arguments must be the same as
+ * the number of columns in the primary key. To find multiple rows in a
+ * table with a multi-column primary key, each argument must be an array
+ * with the same number of elements.
+ *
+ * The find() method always returns a Rowset object, even if only one row
+ * was found.
+ *
+ * @param mixed $key The value(s) of the primary keys.
+ * @return Zend_Db_Table_Rowset_Abstract Row(s) matching the criteria.
+ * @throws Zend_Db_Table_Exception
+ */
+ public function find()
+ {
+ $this->_setupPrimaryKey();
+ $args = func_get_args();
+ $keyNames = array_values((array) $this->_primary);
+
+ if (count($args) < count($keyNames)) {
+ throw new Zend_Db_Table_Exception("Too few columns for the primary key");
+ }
+
+ if (count($args) > count($keyNames)) {
+ throw new Zend_Db_Table_Exception("Too many columns for the primary key");
+ }
+
+ $whereList = array();
+ $numberTerms = 0;
+ foreach ($args as $keyPosition => $keyValues) {
+ $keyValuesCount = count($keyValues);
+ // Coerce the values to an array.
+ // Don't simply typecast to array, because the values
+ // might be Zend_Db_Expr objects.
+ if (!is_array($keyValues)) {
+ $keyValues = array($keyValues);
+ }
+ if ($numberTerms == 0) {
+ $numberTerms = $keyValuesCount;
+ } else if ($keyValuesCount != $numberTerms) {
+ throw new Zend_Db_Table_Exception("Missing value(s) for the primary key");
+ }
+ $keyValues = array_values($keyValues);
+ for ($i = 0; $i < $keyValuesCount; ++$i) {
+ if (!isset($whereList[$i])) {
+ $whereList[$i] = array();
+ }
+ $whereList[$i][$keyPosition] = $keyValues[$i];
+ }
+ }
+
+ $whereClause = null;
+ if (count($whereList)) {
+ $whereOrTerms = array();
+ $tableName = $this->_db->quoteTableAs($this->_name, null, true);
+ foreach ($whereList as $keyValueSets) {
+ $whereAndTerms = array();
+ foreach ($keyValueSets as $keyPosition => $keyValue) {
+ $type = $this->_metadata[$keyNames[$keyPosition]]['DATA_TYPE'];
+ $columnName = $this->_db->quoteIdentifier($keyNames[$keyPosition], true);
+ $whereAndTerms[] = $this->_db->quoteInto(
+ $tableName . '.' . $columnName . ' = ?',
+ $keyValue, $type);
+ }
+ $whereOrTerms[] = '(' . implode(' AND ', $whereAndTerms) . ')';
+ }
+ $whereClause = '(' . implode(' OR ', $whereOrTerms) . ')';
+ }
+
+ // issue ZF-5775 (empty where clause should return empty rowset)
+ if ($whereClause == null) {
+ $rowsetClass = $this->getRowsetClass();
+ if (!class_exists($rowsetClass)) {
+ Zend_Loader::loadClass($rowsetClass);
+ }
+ return new $rowsetClass(array('table' => $this, 'rowClass' => $this->getRowClass(), 'stored' => true));
+ }
+
+ return $this->fetchAll($whereClause);
+ }
+
+ /**
+ * Fetches all rows.
+ *
+ * Honors the Zend_Db_Adapter fetch mode.
+ *
+ * @param string|array|Zend_Db_Table_Select $where OPTIONAL An SQL WHERE clause or Zend_Db_Table_Select object.
+ * @param string|array $order OPTIONAL An SQL ORDER clause.
+ * @param int $count OPTIONAL An SQL LIMIT count.
+ * @param int $offset OPTIONAL An SQL LIMIT offset.
+ * @return Zend_Db_Table_Rowset_Abstract The row results per the Zend_Db_Adapter fetch mode.
+ */
+ public function fetchAll($where = null, $order = null, $count = null, $offset = null)
+ {
+ if (!($where instanceof Zend_Db_Table_Select)) {
+ $select = $this->select();
+
+ if ($where !== null) {
+ $this->_where($select, $where);
+ }
+
+ if ($order !== null) {
+ $this->_order($select, $order);
+ }
+
+ if ($count !== null || $offset !== null) {
+ $select->limit($count, $offset);
+ }
+
+ } else {
+ $select = $where;
+ }
+
+ $rows = $this->_fetch($select);
+
+ $data = array(
+ 'table' => $this,
+ 'data' => $rows,
+ 'readOnly' => $select->isReadOnly(),
+ 'rowClass' => $this->getRowClass(),
+ 'stored' => true
+ );
+
+ $rowsetClass = $this->getRowsetClass();
+ if (!class_exists($rowsetClass)) {
+ Zend_Loader::loadClass($rowsetClass);
+ }
+ return new $rowsetClass($data);
+ }
+
+ /**
+ * Fetches one row in an object of type Zend_Db_Table_Row_Abstract,
+ * or returns null if no row matches the specified criteria.
+ *
+ * @param string|array|Zend_Db_Table_Select $where OPTIONAL An SQL WHERE clause or Zend_Db_Table_Select object.
+ * @param string|array $order OPTIONAL An SQL ORDER clause.
+ * @param int $offset OPTIONAL An SQL OFFSET value.
+ * @return Zend_Db_Table_Row_Abstract|null The row results per the
+ * Zend_Db_Adapter fetch mode, or null if no row found.
+ */
+ public function fetchRow($where = null, $order = null, $offset = null)
+ {
+ if (!($where instanceof Zend_Db_Table_Select)) {
+ $select = $this->select();
+
+ if ($where !== null) {
+ $this->_where($select, $where);
+ }
+
+ if ($order !== null) {
+ $this->_order($select, $order);
+ }
+
+ $select->limit(1, ((is_numeric($offset)) ? (int) $offset : null));
+
+ } else {
+ $select = $where->limit(1, $where->getPart(Zend_Db_Select::LIMIT_OFFSET));
+ }
+
+ $rows = $this->_fetch($select);
+
+ if (count($rows) == 0) {
+ return null;
+ }
+
+ $data = array(
+ 'table' => $this,
+ 'data' => $rows[0],
+ 'readOnly' => $select->isReadOnly(),
+ 'stored' => true
+ );
+
+ $rowClass = $this->getRowClass();
+ if (!class_exists($rowClass)) {
+ Zend_Loader::loadClass($rowClass);
+ }
+ return new $rowClass($data);
+ }
+
+ /**
+ * Fetches a new blank row (not from the database).
+ *
+ * @return Zend_Db_Table_Row_Abstract
+ * @deprecated since 0.9.3 - use createRow() instead.
+ */
+ public function fetchNew()
+ {
+ return $this->createRow();
+ }
+
+ /**
+ * Fetches a new blank row (not from the database).
+ *
+ * @param array $data OPTIONAL data to populate in the new row.
+ * @param string $defaultSource OPTIONAL flag to force default values into new row
+ * @return Zend_Db_Table_Row_Abstract
+ */
+ public function createRow(array $data = array(), $defaultSource = null)
+ {
+ $cols = $this->_getCols();
+ $defaults = array_combine($cols, array_fill(0, count($cols), null));
+
+ // nothing provided at call-time, take the class value
+ if ($defaultSource == null) {
+ $defaultSource = $this->_defaultSource;
+ }
+
+ if (!in_array($defaultSource, array(self::DEFAULT_CLASS, self::DEFAULT_DB, self::DEFAULT_NONE))) {
+ $defaultSource = self::DEFAULT_NONE;
+ }
+
+ if ($defaultSource == self::DEFAULT_DB) {
+ foreach ($this->_metadata as $metadataName => $metadata) {
+ if (($metadata['DEFAULT'] != null) &&
+ ($metadata['NULLABLE'] !== true || ($metadata['NULLABLE'] === true && isset($this->_defaultValues[$metadataName]) && $this->_defaultValues[$metadataName] === true)) &&
+ (!(isset($this->_defaultValues[$metadataName]) && $this->_defaultValues[$metadataName] === false))) {
+ $defaults[$metadataName] = $metadata['DEFAULT'];
+ }
+ }
+ } elseif ($defaultSource == self::DEFAULT_CLASS && $this->_defaultValues) {
+ foreach ($this->_defaultValues as $defaultName => $defaultValue) {
+ if (array_key_exists($defaultName, $defaults)) {
+ $defaults[$defaultName] = $defaultValue;
+ }
+ }
+ }
+
+ $config = array(
+ 'table' => $this,
+ 'data' => $defaults,
+ 'readOnly' => false,
+ 'stored' => false
+ );
+
+ $rowClass = $this->getRowClass();
+ if (!class_exists($rowClass)) {
+ Zend_Loader::loadClass($rowClass);
+ }
+ $row = new $rowClass($config);
+ $row->setFromArray($data);
+ return $row;
+ }
+
+ /**
+ * Generate WHERE clause from user-supplied string or array
+ *
+ * @param string|array $where OPTIONAL An SQL WHERE clause.
+ * @return Zend_Db_Table_Select
+ */
+ protected function _where(Zend_Db_Table_Select $select, $where)
+ {
+ $where = (array) $where;
+
+ foreach ($where as $key => $val) {
+ // is $key an int?
+ if (is_int($key)) {
+ // $val is the full condition
+ $select->where($val);
+ } else {
+ // $key is the condition with placeholder,
+ // and $val is quoted into the condition
+ $select->where($key, $val);
+ }
+ }
+
+ return $select;
+ }
+
+ /**
+ * Generate ORDER clause from user-supplied string or array
+ *
+ * @param string|array $order OPTIONAL An SQL ORDER clause.
+ * @return Zend_Db_Table_Select
+ */
+ protected function _order(Zend_Db_Table_Select $select, $order)
+ {
+ if (!is_array($order)) {
+ $order = array($order);
+ }
+
+ foreach ($order as $val) {
+ $select->order($val);
+ }
+
+ return $select;
+ }
+
+ /**
+ * Support method for fetching rows.
+ *
+ * @param Zend_Db_Table_Select $select query options.
+ * @return array An array containing the row results in FETCH_ASSOC mode.
+ */
+ protected function _fetch(Zend_Db_Table_Select $select)
+ {
+ $stmt = $this->_db->query($select);
+ $data = $stmt->fetchAll(Zend_Db::FETCH_ASSOC);
+ return $data;
+ }
+
+ /**
+ * Get table gateway object from string
+ *
+ * @param string $tableName
+ * @param Zend_Db_Table_Abstract $referenceTable
+ * @throws Zend_Db_Table_Row_Exception
+ * @return Zend_Db_Table_Abstract
+ */
+ public static function getTableFromString($tableName, Zend_Db_Table_Abstract $referenceTable = null)
+ {
+ if ($referenceTable instanceof Zend_Db_Table_Abstract) {
+ $tableDefinition = $referenceTable->getDefinition();
+
+ if ($tableDefinition !== null && $tableDefinition->hasTableConfig($tableName)) {
+ return new Zend_Db_Table($tableName, $tableDefinition);
+ }
+ }
+
+ // assume the tableName is the class name
+ if (!class_exists($tableName)) {
+ try {
+ Zend_Loader::loadClass($tableName);
+ } catch (Zend_Exception $e) {
+ throw new Zend_Db_Table_Row_Exception($e->getMessage(), $e->getCode(), $e);
+ }
+ }
+
+ $options = array();
+
+ if ($referenceTable instanceof Zend_Db_Table_Abstract) {
+ $options['db'] = $referenceTable->getAdapter();
+ }
+
+ if (isset($tableDefinition) && $tableDefinition !== null) {
+ $options[Zend_Db_Table_Abstract::DEFINITION] = $tableDefinition;
+ }
+
+ return new $tableName($options);
+ }
+
+}