1
0
mirror of synced 2024-12-15 07:36:03 +03:00
doctrine2/lib/Doctrine/Table.php

1284 lines
42 KiB
PHP
Raw Normal View History

2006-05-30 12:42:10 +04:00
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
2006-05-30 12:42:10 +04:00
/**
* Doctrine_Table represents a database table
* each Doctrine_Table holds the information of foreignKeys and associations
*
2006-05-30 12:42:10 +04:00
*
2006-12-01 01:33:54 +03:00
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @package Doctrine
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version $Revision$
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
*/
2006-12-29 17:40:47 +03:00
class Doctrine_Table extends Doctrine_Configurable implements Countable
{
2006-05-30 12:42:10 +04:00
/**
* @var array $data temporary data which is then loaded into Doctrine_Record::$data
*/
private $data = array();
/**
* @var array $relations an array containing all the Doctrine_Relation objects for this table
*/
private $relations = array();
/**
* @var array $primaryKeys an array containing all primary key column names
*/
private $primaryKeys = array();
/**
* @var mixed $identifier
*/
private $identifier;
/**
* @see Doctrine_Identifier constants
* @var integer $identifierType the type of identifier this table uses
2006-05-30 12:42:10 +04:00
*/
private $identifierType;
/**
* @var string $query cached simple query
*/
private $query;
/**
2006-12-01 01:33:54 +03:00
* @var Doctrine_Connection $conn Doctrine_Connection object that created this table
2006-05-30 12:42:10 +04:00
*/
2006-12-01 01:33:54 +03:00
private $conn;
2006-05-30 12:42:10 +04:00
/**
2006-10-24 21:02:47 +04:00
* @var string $name
2006-05-30 12:42:10 +04:00
*/
private $name;
/**
* @var array $identityMap first level cache
*/
private $identityMap = array();
2006-06-01 15:58:05 +04:00
/**
* @var Doctrine_Table_Repository $repository record repository
2006-06-01 15:58:05 +04:00
*/
2006-05-30 12:42:10 +04:00
private $repository;
/**
2006-10-24 21:02:47 +04:00
* @var array $columns an array of column definitions,
* keys as column names and values as column definitions
2006-12-29 17:01:31 +03:00
*
2006-10-24 21:02:47 +04:00
* the value array has three values:
2006-12-29 17:01:31 +03:00
*
2006-10-24 21:02:47 +04:00
* the column type, eg. 'integer'
* the column length, eg. 11
* the column options/constraints/validators. eg array('notnull' => true)
*
* so the full columns array might look something like the following:
* array(
2006-10-27 00:53:59 +04:00
* 'name' => array('string', 20, array('notnull' => true, 'default' => 'someone')),
* 'age' => array('integer', 11, array('notnull' => true))
2006-10-24 21:02:47 +04:00
* )
2006-05-30 12:42:10 +04:00
*/
2006-10-24 21:02:47 +04:00
protected $columns = array();
2006-05-30 12:42:10 +04:00
/**
* @var array $bound bound relations
*/
private $bound = array();
/**
* @var array $boundAliases bound relation aliases
*/
private $boundAliases = array();
/**
* @var integer $columnCount cached column count, Doctrine_Record uses this column count in when
* determining its state
2006-05-30 12:42:10 +04:00
*/
private $columnCount;
/**
* @var array $parents the parent classes of this component
*/
private $parents = array();
/**
* @var boolean $hasDefaultValues whether or not this table has default values
*/
private $hasDefaultValues;
2006-10-24 21:02:47 +04:00
/**
2006-10-27 00:53:59 +04:00
* @var array $options an array containing all options
2006-10-24 21:02:47 +04:00
*
2006-10-27 00:53:59 +04:00
* -- name name of the component, for example component name of the GroupTable is 'Group'
2006-10-24 21:02:47 +04:00
*
* -- declaringClass name of the table definition declaring class (when using inheritance the class
* that defines the table structure can be any class in the inheritance hierarchy,
* hence we need reflection to check out which class actually calls setTableDefinition)
*
2006-10-27 00:53:59 +04:00
* -- tableName database table name, in most cases this is the same as component name but in some cases
* where one-table-multi-class inheritance is used this will be the name of the inherited table
2006-10-24 21:02:47 +04:00
*
2006-10-27 00:53:59 +04:00
* -- sequenceName Some databases need sequences instead of auto incrementation primary keys,
* you can set specific sequence for your table by calling setOption('sequenceName', $seqName)
* where $seqName is the name of the desired sequence
2006-10-24 21:02:47 +04:00
*
2006-10-27 00:53:59 +04:00
* -- enumMap enum value arrays
2006-10-24 21:02:47 +04:00
*
2006-10-27 00:53:59 +04:00
* -- inheritanceMap inheritanceMap is used for inheritance mapping, keys representing columns and values
* the column values that should correspond to child classes
2006-10-24 21:02:47 +04:00
*/
protected $options = array('name' => null,
'tableName' => null,
'sequenceName' => null,
'inheritanceMap' => array(),
'enumMap' => array(),
);
2006-06-18 02:46:03 +04:00
2006-05-30 12:42:10 +04:00
/**
* the constructor
2006-09-18 23:52:17 +04:00
* @throws Doctrine_Connection_Exception if there are no opened connections
* @throws Doctrine_Table_Exception if there is already an instance of this table
2006-05-30 12:42:10 +04:00
* @return void
*/
2006-12-29 17:40:47 +03:00
public function __construct($name, Doctrine_Connection $conn)
{
2006-12-01 01:33:54 +03:00
$this->conn = $conn;
2006-05-30 12:42:10 +04:00
2006-12-01 01:33:54 +03:00
$this->setParent($this->conn);
2006-05-30 12:42:10 +04:00
2006-10-24 21:02:47 +04:00
$this->options['name'] = $name;
2006-05-30 12:42:10 +04:00
2006-12-29 17:01:31 +03:00
if ( ! class_exists($name) || empty($name)) {
2006-05-30 12:42:10 +04:00
throw new Doctrine_Exception("Couldn't find class $name");
2006-12-29 17:01:31 +03:00
}
2006-05-30 12:42:10 +04:00
$record = new $name($this);
$names = array();
$class = $name;
// get parent classes
do {
2006-12-29 17:01:31 +03:00
if ($class == "Doctrine_Record")
2006-09-18 23:52:17 +04:00
break;
2006-05-30 12:42:10 +04:00
2006-12-29 17:01:31 +03:00
$name = $class;
2006-05-30 12:42:10 +04:00
$names[] = $name;
2006-12-29 17:01:31 +03:00
} while ($class = get_parent_class($class));
2006-05-30 12:42:10 +04:00
// reverse names
$names = array_reverse($names);
// create database table
2006-12-29 17:01:31 +03:00
if (method_exists($record, 'setTableDefinition')) {
2006-05-30 12:42:10 +04:00
$record->setTableDefinition();
$this->columnCount = count($this->columns);
2006-12-29 17:01:31 +03:00
if (isset($this->columns)) {
2006-09-18 23:52:17 +04:00
// get the declaring class of setTableDefinition method
$method = new ReflectionMethod($this->options['name'], 'setTableDefinition');
2006-05-30 12:42:10 +04:00
$class = $method->getDeclaringClass();
$this->options['declaringClass'] = $class;
2006-12-29 17:01:31 +03:00
if ( ! isset($this->options['tableName'])) {
2006-10-24 21:02:47 +04:00
$this->options['tableName'] = Doctrine::tableize($class->getName());
2006-12-29 17:01:31 +03:00
}
switch (count($this->primaryKeys)) {
case 0:
$this->columns = array_merge(array('id' =>
array('integer',
20,
array('autoincrement' => true,
'primary' => true
)
)
), $this->columns);
2006-12-30 00:46:14 +03:00
$this->primaryKeys[] = 'id';
$this->identifier = 'id';
$this->identifierType = Doctrine_Identifier::AUTO_INCREMENT;
$this->columnCount++;
break;
default:
if (count($this->primaryKeys) > 1) {
$this->identifier = $this->primaryKeys;
$this->identifierType = Doctrine_Identifier::COMPOSITE;
2006-12-30 00:46:14 +03:00
} else {
foreach ($this->primaryKeys as $pk) {
$e = $this->columns[$pk][2];
2006-12-30 00:46:14 +03:00
$found = false;
2006-12-30 00:46:14 +03:00
foreach ($e as $option => $value) {
if ($found)
break;
2006-12-30 00:46:14 +03:00
2007-01-10 23:36:29 +03:00
$e2 = explode(':', $option);
2006-12-30 00:46:14 +03:00
switch (strtolower($e2[0])) {
2007-01-10 23:36:29 +03:00
case 'autoincrement':
case 'autoinc':
$this->identifierType = Doctrine_Identifier::AUTO_INCREMENT;
$found = true;
break;
2007-01-10 23:36:29 +03:00
case 'seq':
case 'sequence':
$this->identifierType = Doctrine_Identifier::SEQUENCE;
$found = true;
2007-01-10 23:36:29 +03:00
if($value) {
$this->options['sequenceName'] = $value;
} else {
$this->options['sequenceName'] = $this->conn->getSequenceName($this->options['tableName']);
}
break;
2007-01-10 23:36:29 +03:00
}
}
if ( ! isset($this->identifierType)) {
$this->identifierType = Doctrine_Identifier::NORMAL;
}
$this->identifier = $pk;
2006-05-30 12:42:10 +04:00
}
}
2006-12-29 17:01:31 +03:00
};
if ($this->getAttribute(Doctrine::ATTR_CREATE_TABLES)) {
$this->export();
2006-05-30 12:42:10 +04:00
}
}
} else {
2006-10-20 22:21:42 +04:00
throw new Doctrine_Table_Exception("Class '$name' has no table definition.");
2006-05-30 12:42:10 +04:00
}
2006-05-30 12:42:10 +04:00
$record->setUp();
// save parents
array_pop($names);
$this->parents = $names;
$this->query = "SELECT ".implode(", ",array_keys($this->columns))." FROM ".$this->getTableName();
// check if an instance of this table is already initialized
2006-12-29 17:01:31 +03:00
if ( ! $this->conn->addTable($this)) {
2006-05-30 12:42:10 +04:00
throw new Doctrine_Table_Exception();
2006-12-29 17:01:31 +03:00
}
$this->repository = new Doctrine_Table_Repository($this);
2006-05-30 12:42:10 +04:00
}
/**
* export
* exports this table to database based on column and option definitions
*
* @throws Doctrine_Connection_Exception if some error other than Doctrine::ERR_ALREADY_EXISTS
* occurred during the create table operation
* @return boolean whether or not the export operation was successful
* false if table already existed in the database
*/
public function export() {
if (Doctrine::isValidClassname($this->options['declaringClass']->getName())) {
try {
$columns = array();
$primary = array();
foreach ($this->columns as $name => $column) {
$definition = $column[2];
$definition['type'] = $column[0];
$definition['length'] = $column[1];
if ($definition['type'] == 'enum' && isset($definition['default'])) {
$definition['default'] = $this->enumIndex($name, $definition['default']);
}
if ($definition['type'] == 'boolean' && isset($definition['default'])) {
$definition['default'] = (int) $definition['default'];
}
$columns[$name] = $definition;
if(isset($definition['primary']) && $definition['primary']) {
$primary[] = $name;
}
}
$options['primary'] = $primary;
$this->conn->export->createTable($this->options['tableName'], $columns, array_merge($this->options, $options));
} catch(Doctrine_Connection_Exception $e) {
// we only want to silence table already exists errors
if($e->getPortableCode !== Doctrine::ERR_ALREADY_EXISTS) {
throw $e;
}
}
}
}
2006-11-06 21:25:39 +03:00
/**
* createQuery
* creates a new Doctrine_Query object and adds the component name
* of this table as the query 'from' part
2006-12-29 17:01:31 +03:00
*
2006-11-06 21:25:39 +03:00
* @return Doctrine_Query
*/
2006-12-29 17:40:47 +03:00
public function createQuery()
{
2006-11-06 21:25:39 +03:00
return Doctrine_Query::create()->from($this->getComponentName());
}
2006-05-30 12:42:10 +04:00
/**
* getRepository
*
* @return Doctrine_Table_Repository
2006-05-30 12:42:10 +04:00
*/
2006-12-29 17:40:47 +03:00
public function getRepository()
{
2006-05-30 12:42:10 +04:00
return $this->repository;
}
2006-12-29 17:01:31 +03:00
2006-12-29 17:40:47 +03:00
public function setOption($name, $value)
{
2006-12-29 17:01:31 +03:00
switch ($name) {
case 'name':
case 'tableName':
break;
case 'enumMap':
case 'inheritanceMap':
if ( ! is_array($value)) {
throw new Doctrine_Table_Exception($name.' should be an array.');
}
break;
2006-10-24 21:02:47 +04:00
}
$this->options[$name] = $value;
}
2006-12-29 17:01:31 +03:00
2006-12-29 17:40:47 +03:00
public function usesInheritanceMap()
{
return ( ! empty($this->options['inheritanceMap']));
}
2006-12-29 17:40:47 +03:00
public function getOption($name)
{
2006-12-29 17:01:31 +03:00
if (isset($this->options[$name])) {
return $this->options[$name];
2006-12-29 17:01:31 +03:00
}
return null;
}
2006-05-30 12:42:10 +04:00
/**
* setColumn
2007-01-10 23:36:29 +03:00
*
2006-05-30 12:42:10 +04:00
* @param string $name
* @param string $type
* @param integer $length
* @param mixed $options
2007-01-10 23:36:29 +03:00
* @throws Doctrine_Table_Exception if trying use wrongly typed parameter
2006-05-30 12:42:10 +04:00
* @return void
*/
2006-12-24 01:48:16 +03:00
final public function setColumn($name, $type, $length = null, $options = array()) {
2006-12-29 17:01:31 +03:00
if (is_string($options)) {
$options = explode('|', $options);
2006-12-29 17:01:31 +03:00
}
2007-01-10 23:36:29 +03:00
2006-12-29 17:01:31 +03:00
foreach ($options as $k => $option) {
if (is_numeric($k)) {
if ( ! empty($option)) {
$options[$option] = true;
2006-12-29 17:01:31 +03:00
}
unset($options[$k]);
}
}
$name = strtolower($name);
2006-12-29 17:01:31 +03:00
if ($length == null)
2006-12-24 01:48:16 +03:00
$length = 2147483647;
2007-01-10 23:36:29 +03:00
if((string) (int) $length !== (string) $length) {
throw new Doctrine_Table_Exception('Invalid argument given for column length');
}
2006-12-24 01:48:16 +03:00
$this->columns[$name] = array($type, $length, $options);
2006-12-29 17:01:31 +03:00
if (isset($options['primary'])) {
2006-05-30 12:42:10 +04:00
$this->primaryKeys[] = $name;
}
2006-12-29 17:01:31 +03:00
if (isset($options['default'])) {
$this->hasDefaultValues = true;
}
}
/**
* hasDefaultValues
* returns true if this table has default values, otherwise false
*
* @return boolean
*/
2006-12-29 17:40:47 +03:00
public function hasDefaultValues()
{
return $this->hasDefaultValues;
2006-05-30 12:42:10 +04:00
}
/**
* getDefaultValueOf
* returns the default value(if any) for given column
*
* @param string $column
* @return mixed
*/
2006-12-29 17:40:47 +03:00
public function getDefaultValueOf($column)
{
$column = strtolower($column);
2006-12-29 17:01:31 +03:00
if ( ! isset($this->columns[$column])) {
throw new Doctrine_Table_Exception("Couldn't get default value. Column ".$column." doesn't exist.");
2006-12-29 17:01:31 +03:00
}
if (isset($this->columns[$column][2]['default'])) {
return $this->columns[$column][2]['default'];
2006-12-29 17:01:31 +03:00
} else {
return null;
2006-12-29 17:01:31 +03:00
}
}
2006-05-30 12:42:10 +04:00
/**
* @return mixed
*/
2006-12-29 17:40:47 +03:00
final public function getIdentifier()
{
2006-05-30 12:42:10 +04:00
return $this->identifier;
}
/**
* @return integer
*/
2006-12-29 17:40:47 +03:00
final public function getIdentifierType()
{
2006-05-30 12:42:10 +04:00
return $this->identifierType;
}
/**
* hasColumn
* @return boolean
*/
2006-12-29 17:40:47 +03:00
final public function hasColumn($name)
{
2006-05-30 12:42:10 +04:00
return isset($this->columns[$name]);
}
/**
* @param mixed $key
* @return void
*/
2006-12-29 17:40:47 +03:00
final public function setPrimaryKey($key)
{
2006-12-29 17:01:31 +03:00
switch (gettype($key)) {
case "array":
$this->primaryKeys = array_values($key);
break;
case "string":
$this->primaryKeys[] = $key;
break;
2006-12-29 17:01:31 +03:00
};
2006-05-30 12:42:10 +04:00
}
/**
* returns all primary keys
* @return array
*/
2006-12-29 17:40:47 +03:00
final public function getPrimaryKeys()
{
2006-05-30 12:42:10 +04:00
return $this->primaryKeys;
}
/**
* @return boolean
*/
2006-12-29 17:40:47 +03:00
final public function hasPrimaryKey($key)
{
2006-05-30 12:42:10 +04:00
return in_array($key,$this->primaryKeys);
}
/**
* @param $sequence
* @return void
*/
2006-12-29 17:40:47 +03:00
final public function setSequenceName($sequence)
{
2006-10-24 21:02:47 +04:00
$this->options['sequenceName'] = $sequence;
2006-05-30 12:42:10 +04:00
}
/**
* @return string sequence name
*/
2006-12-29 17:40:47 +03:00
final public function getSequenceName()
{
2006-10-24 21:02:47 +04:00
return $this->options['sequenceName'];
2006-05-30 12:42:10 +04:00
}
/**
* getParents
*/
2006-12-29 17:40:47 +03:00
final public function getParents()
{
2006-06-18 02:46:03 +04:00
return $this->parents;
}
/**
* @return boolean
*/
2006-12-29 17:40:47 +03:00
final public function hasInheritanceMap()
{
2006-10-24 21:02:47 +04:00
return (empty($this->options['inheritanceMap']));
2006-05-30 12:42:10 +04:00
}
/**
* @return array inheritance map (array keys as fields)
*/
2006-12-29 17:40:47 +03:00
final public function getInheritanceMap()
{
2006-10-24 21:02:47 +04:00
return $this->options['inheritanceMap'];
2006-05-30 12:42:10 +04:00
}
/**
* return all composite paths in the form [component1].[component2]. . .[componentN]
* @return array
*/
2006-12-29 17:40:47 +03:00
final public function getCompositePaths()
{
2006-05-30 12:42:10 +04:00
$array = array();
$name = $this->getComponentName();
2006-12-29 17:01:31 +03:00
foreach ($this->bound as $k=>$a) {
2006-05-30 12:42:10 +04:00
try {
$fk = $this->getRelation($k);
switch ($fk->getType()) {
case Doctrine_Relation::ONE_COMPOSITE:
case Doctrine_Relation::MANY_COMPOSITE:
$n = $fk->getTable()->getComponentName();
$array[] = $name.".".$n;
$e = $fk->getTable()->getCompositePaths();
if ( ! empty($e)) {
foreach ($e as $name) {
$array[] = $name.".".$n.".".$name;
}
}
break;
};
} catch(Doctrine_Table_Exception $e) {
2006-05-30 12:42:10 +04:00
}
}
return $array;
}
/**
* returns all bound relations
*
* @return array
*/
2006-12-29 17:40:47 +03:00
public function getBounds()
{
2006-05-30 12:42:10 +04:00
return $this->bound;
}
/**
* returns a bound relation array
*
* @param string $name
* @return array
*/
2006-12-29 17:40:47 +03:00
public function getBound($name)
{
2006-12-29 17:01:31 +03:00
if ( ! isset($this->bound[$name])) {
throw new Doctrine_Table_Exception('Unknown bound '.$name);
2006-12-29 17:01:31 +03:00
}
2006-05-30 12:42:10 +04:00
return $this->bound[$name];
}
/**
* returns a bound relation array
*
* @param string $name
* @return array
*/
2006-12-29 17:40:47 +03:00
public function getBoundForName($name, $component)
{
2006-12-29 17:01:31 +03:00
foreach ($this->bound as $k => $bound) {
$e = explode('.', $bound[0]);
2006-10-27 00:53:59 +04:00
2006-12-29 17:01:31 +03:00
if ($bound[3] == $name && $e[0] == $component) {
2006-05-30 12:42:10 +04:00
return $this->bound[$k];
}
}
throw new Doctrine_Table_Exception('Unknown bound '.$name);
2006-05-30 12:42:10 +04:00
}
/**
* returns the alias for given component name
*
* @param string $name
* @return string
*/
2006-12-29 17:40:47 +03:00
public function getAlias($name)
{
2006-12-29 17:01:31 +03:00
if (isset($this->boundAliases[$name])) {
2006-05-30 12:42:10 +04:00
return $this->boundAliases[$name];
2006-12-29 17:01:31 +03:00
}
2006-05-30 12:42:10 +04:00
return $name;
}
/**
* returns component name for given alias
*
2006-05-30 12:42:10 +04:00
* @param string $alias
* @return string
*/
2006-12-29 17:40:47 +03:00
public function getAliasName($alias)
{
2006-12-29 17:01:31 +03:00
if ($name = array_search($alias, $this->boundAliases)) {
2006-05-30 12:42:10 +04:00
return $name;
2006-12-29 17:01:31 +03:00
}
2006-11-11 22:51:51 +03:00
return $alias;
2006-05-30 12:42:10 +04:00
}
/**
* unbinds all relations
*
2006-05-30 12:42:10 +04:00
* @return void
*/
2006-12-29 17:40:47 +03:00
public function unbindAll()
{
2006-05-30 12:42:10 +04:00
$this->bound = array();
$this->relations = array();
$this->boundAliases = array();
}
/**
* unbinds a relation
* returns true on success, false on failure
*
* @param $name
* @return boolean
*/
2006-12-29 17:40:47 +03:00
public function unbind($name)
{
2006-12-29 17:01:31 +03:00
if ( ! isset($this->bound[$name])) {
2006-05-30 12:42:10 +04:00
return false;
2006-12-29 17:01:31 +03:00
}
2006-05-30 12:42:10 +04:00
unset($this->bound[$name]);
2006-12-29 17:01:31 +03:00
if (isset($this->relations[$name])) {
2006-05-30 12:42:10 +04:00
unset($this->relations[$name]);
2006-12-29 17:01:31 +03:00
}
if (isset($this->boundAliases[$name])) {
2006-05-30 12:42:10 +04:00
unset($this->boundAliases[$name]);
2006-12-29 17:01:31 +03:00
}
2006-05-30 12:42:10 +04:00
return true;
}
/**
* binds a relation
*
* @param string $name
* @param string $field
* @return void
*/
2006-12-29 17:40:47 +03:00
public function bind($name, $field, $type, $localKey)
{
2006-12-29 17:01:31 +03:00
if (isset($this->relations[$name])) {
unset($this->relations[$name]);
2006-12-29 17:01:31 +03:00
}
2006-05-30 12:42:10 +04:00
$e = explode(" as ",$name);
$name = $e[0];
2006-12-29 17:01:31 +03:00
if (isset($e[1])) {
2006-05-30 12:42:10 +04:00
$alias = $e[1];
$this->boundAliases[$name] = $alias;
2006-12-29 17:01:31 +03:00
} else {
2006-05-30 12:42:10 +04:00
$alias = $name;
2006-12-29 17:01:31 +03:00
}
2006-05-30 12:42:10 +04:00
$this->bound[$alias] = array($field, $type, $localKey, $name);
2006-05-30 12:42:10 +04:00
}
/**
* getComponentName
* @return string the component name
*/
2006-12-29 17:40:47 +03:00
public function getComponentName()
{
2006-10-24 21:02:47 +04:00
return $this->options['name'];
2006-05-30 12:42:10 +04:00
}
/**
2006-08-22 03:21:01 +04:00
* @return Doctrine_Connection
2006-05-30 12:42:10 +04:00
*/
2006-12-29 17:40:47 +03:00
public function getConnection()
{
2006-12-01 01:33:54 +03:00
return $this->conn;
2006-05-30 12:42:10 +04:00
}
/**
* hasRelatedComponent
* @return boolean
*/
2006-12-29 17:40:47 +03:00
final public function hasRelatedComponent($name, $component)
{
return (strpos($this->bound[$name][0], $component.'.') !== false);
}
/**
* @param string $name component name of which a foreign key object is bound
* @return boolean
*/
2006-12-29 17:40:47 +03:00
final public function hasRelation($name)
{
2006-12-29 17:01:31 +03:00
if (isset($this->bound[$name])) {
return true;
2006-12-29 17:01:31 +03:00
}
foreach ($this->bound as $k=>$v) {
if ($this->hasRelatedComponent($k, $name)) {
return true;
2006-12-29 17:01:31 +03:00
}
}
return false;
}
2006-05-30 12:42:10 +04:00
/**
* getRelation
*
2006-05-30 12:42:10 +04:00
* @param string $name component name of which a foreign key object is bound
* @return Doctrine_Relation
*/
2006-12-29 17:40:47 +03:00
final public function getRelation($name, $recursive = true)
{
2006-08-01 22:02:53 +04:00
$original = $name;
2006-12-29 17:01:31 +03:00
if (isset($this->relations[$name])) {
return $this->relations[$name];
}
if (isset($this->bound[$name])) {
2006-05-30 12:42:10 +04:00
$type = $this->bound[$name][1];
$local = $this->bound[$name][2];
list($component, $foreign) = explode(".",$this->bound[$name][0]);
$alias = $name;
$name = $this->bound[$alias][3];
2006-12-01 01:33:54 +03:00
$table = $this->conn->getTable($name);
2006-05-30 12:42:10 +04:00
2006-12-29 17:01:31 +03:00
if ($component == $this->options['name'] || in_array($component, $this->parents)) {
2006-05-30 12:42:10 +04:00
// ONE-TO-ONE
2006-12-29 17:01:31 +03:00
if ($type == Doctrine_Relation::ONE_COMPOSITE ||
2006-05-30 12:42:10 +04:00
$type == Doctrine_Relation::ONE_AGGREGATE) {
2007-01-05 00:08:56 +03:00
// tree structure parent relation found
2006-12-29 17:01:31 +03:00
if ( ! isset($local)) {
2006-05-30 12:42:10 +04:00
$local = $table->getIdentifier();
2006-12-29 17:01:31 +03:00
}
2006-10-23 20:19:47 +04:00
$relation = new Doctrine_Relation_LocalKey($table, $foreign, $local, $type, $alias);
2006-12-29 17:01:31 +03:00
} else {
2007-01-05 00:08:56 +03:00
// tree structure children relation found
if ( ! isset($local)) {
$tmp = $table->getIdentifier();
}
$local = $foreign;
$foreign = $tmp;
2006-10-23 20:19:47 +04:00
$relation = new Doctrine_Relation_ForeignKey($table, $foreign, $local, $type, $alias);
2006-12-29 17:01:31 +03:00
}
2006-10-23 20:19:47 +04:00
2006-12-29 17:01:31 +03:00
} elseif ($component == $name ||
2006-10-24 21:02:47 +04:00
($component == $alias)) { // && ($name == $this->options['name'] || in_array($name,$this->parents))
2006-09-19 00:11:21 +04:00
2007-01-05 00:08:56 +03:00
2006-12-29 17:01:31 +03:00
if ( ! isset($local)) {
2006-05-30 12:42:10 +04:00
$local = $this->identifier;
2006-12-29 17:01:31 +03:00
}
2006-05-30 12:42:10 +04:00
// ONE-TO-MANY or ONE-TO-ONE
$relation = new Doctrine_Relation_ForeignKey($table, $local, $foreign, $type, $alias);
2006-05-30 12:42:10 +04:00
} else {
// MANY-TO-MANY
// only aggregate relations allowed
2006-12-29 17:01:31 +03:00
if ($type != Doctrine_Relation::MANY_AGGREGATE)
throw new Doctrine_Table_Exception("Only aggregate relations are allowed for many-to-many relations");
2006-05-30 12:42:10 +04:00
2006-10-24 21:02:47 +04:00
$classes = array_merge($this->parents, array($this->options['name']));
2006-05-30 12:42:10 +04:00
2006-12-29 17:01:31 +03:00
foreach (array_reverse($classes) as $class) {
2006-05-30 12:42:10 +04:00
try {
$bound = $table->getBoundForName($class, $component);
2006-05-30 12:42:10 +04:00
break;
} catch(Doctrine_Table_Exception $exc) { }
2006-05-30 12:42:10 +04:00
}
2006-12-29 17:01:31 +03:00
if ( ! isset($bound)) {
throw new Doctrine_Table_Exception("Couldn't map many-to-many relation for "
. $this->options['name'] . " and $name. Components use different join tables.");
2006-12-29 17:01:31 +03:00
}
if ( ! isset($local)) {
2006-05-30 12:42:10 +04:00
$local = $this->identifier;
2006-12-29 17:01:31 +03:00
}
$e2 = explode('.', $bound[0]);
$fields = explode('-', $e2[1]);
2006-05-30 12:42:10 +04:00
2006-12-29 17:01:31 +03:00
if ($e2[0] != $component)
throw new Doctrine_Table_Exception($e2[0] . ' doesn\'t match ' . $component);
2006-05-30 12:42:10 +04:00
2006-12-01 01:33:54 +03:00
$associationTable = $this->conn->getTable($e2[0]);
2006-05-30 12:42:10 +04:00
2006-12-29 17:01:31 +03:00
if (count($fields) > 1) {
2006-05-30 12:42:10 +04:00
// SELF-REFERENCING THROUGH JOIN TABLE
$this->relations[$e2[0]] = new Doctrine_Relation_ForeignKey($associationTable, $local, $fields[0],Doctrine_Relation::MANY_COMPOSITE, $e2[0]);
$relation = new Doctrine_Relation_Association_Self($table, $associationTable, $fields[0], $fields[1], $type, $alias);
2006-05-30 12:42:10 +04:00
} else {
// auto initialize a new one-to-one relationship for association table
$associationTable->bind($this->getComponentName(), $associationTable->getComponentName(). '.' .$e2[1], Doctrine_Relation::ONE_AGGREGATE, $this->getIdentifier());
$associationTable->bind($table->getComponentName(), $associationTable->getComponentName(). '.' .$foreign, Doctrine_Relation::ONE_AGGREGATE, $table->getIdentifier());
2006-05-30 12:42:10 +04:00
// NORMAL MANY-TO-MANY RELATIONSHIP
$this->relations[$e2[0]] = new Doctrine_Relation_ForeignKey($associationTable, $local, $e2[1], Doctrine_Relation::MANY_COMPOSITE, $e2[0]);
2006-05-30 12:42:10 +04:00
$relation = new Doctrine_Relation_Association($table, $associationTable, $e2[1], $foreign, $type, $alias);
2006-05-30 12:42:10 +04:00
}
}
2006-10-20 22:21:42 +04:00
2006-05-30 12:42:10 +04:00
$this->relations[$alias] = $relation;
return $this->relations[$alias];
}
2006-10-20 22:21:42 +04:00
// load all relations
$this->getRelations();
2006-12-29 17:01:31 +03:00
if ($recursive) {
return $this->getRelation($original, false);
} else {
2006-12-29 17:01:31 +03:00
throw new Doctrine_Table_Exception($this->options['name'] . " doesn't have a relation to " . $original);
}
2006-05-30 12:42:10 +04:00
}
/**
* returns an array containing all foreign key objects
*
* @return array
*/
2006-12-29 17:40:47 +03:00
final public function getRelations()
{
2006-05-30 12:42:10 +04:00
$a = array();
2006-12-29 17:01:31 +03:00
foreach ($this->bound as $k=>$v) {
$this->getRelation($k);
2006-05-30 12:42:10 +04:00
}
return $this->relations;
}
/**
* sets the database table name
*
* @param string $name database table name
* @return void
*/
2006-12-29 17:40:47 +03:00
final public function setTableName($name)
{
2006-10-24 21:02:47 +04:00
$this->options['tableName'] = $name;
2006-05-30 12:42:10 +04:00
}
/**
* returns the database table name
*
* @return string
*/
2006-12-29 17:40:47 +03:00
final public function getTableName()
{
return $this->options['tableName'];
2006-05-30 12:42:10 +04:00
}
/**
* create
* creates a new record
*
* @param $array an array where keys are field names and values representing field values
* @return Doctrine_Record
*/
public function create(array $array = array()) {
$this->data = $array;
2006-11-06 21:34:10 +03:00
$record = new $this->options['name']($this, true);
2006-05-30 12:42:10 +04:00
$this->data = array();
return $record;
}
/**
* finds a record by its identifier
*
* @param $id database row id
2006-10-17 21:21:21 +04:00
* @return Doctrine_Record|false a record for given database identifier
2006-05-30 12:42:10 +04:00
*/
2006-12-29 17:40:47 +03:00
public function find($id)
{
2006-12-29 17:01:31 +03:00
if ($id !== null) {
if ( ! is_array($id)) {
2006-05-30 12:42:10 +04:00
$id = array($id);
2006-12-29 17:01:31 +03:00
} else {
2006-05-30 12:42:10 +04:00
$id = array_values($id);
2006-12-29 17:01:31 +03:00
}
2006-05-30 12:42:10 +04:00
$query = $this->query." WHERE ".implode(" = ? AND ",$this->primaryKeys)." = ?";
$query = $this->applyInheritance($query);
2006-06-03 13:10:43 +04:00
2006-10-24 21:02:47 +04:00
$params = array_merge($id, array_values($this->options['inheritanceMap']));
2006-05-30 12:42:10 +04:00
2006-12-01 01:33:54 +03:00
$stmt = $this->conn->execute($query,$params);
2006-06-03 13:10:43 +04:00
$this->data = $stmt->fetch(PDO::FETCH_ASSOC);
2006-05-30 12:42:10 +04:00
2006-12-29 17:01:31 +03:00
if ($this->data === false)
return false;
2006-12-29 17:01:31 +03:00
2006-10-15 23:19:20 +04:00
return $this->getRecord();
2006-05-30 12:42:10 +04:00
}
2006-10-15 23:19:20 +04:00
return false;
2006-05-30 12:42:10 +04:00
}
/**
* applyInheritance
* @param $where query where part to be modified
* @return string query where part with column aggregation inheritance added
*/
2006-12-29 17:40:47 +03:00
final public function applyInheritance($where)
{
2006-12-29 17:01:31 +03:00
if ( ! empty($this->options['inheritanceMap'])) {
2006-05-30 12:42:10 +04:00
$a = array();
2006-12-29 17:01:31 +03:00
foreach ($this->options['inheritanceMap'] as $field => $value) {
2006-05-30 12:42:10 +04:00
$a[] = $field." = ?";
}
$i = implode(" AND ",$a);
$where .= " AND $i";
}
return $where;
}
/**
* findAll
* returns a collection of records
*
* @return Doctrine_Collection
*/
2006-12-29 17:40:47 +03:00
public function findAll()
{
2006-12-01 01:33:54 +03:00
$graph = new Doctrine_Query($this->conn);
2006-10-24 21:02:47 +04:00
$users = $graph->query("FROM ".$this->options['name']);
2006-05-30 12:42:10 +04:00
return $users;
}
/**
* findByDql
* finds records with given DQL where clause
2006-05-30 12:42:10 +04:00
* returns a collection of records
*
* @param string $dql DQL after WHERE clause
2006-05-30 12:42:10 +04:00
* @param array $params query parameters
* @return Doctrine_Collection
*/
public function findBySql($dql, array $params = array()) {
2006-12-01 01:33:54 +03:00
$q = new Doctrine_Query($this->conn);
2006-10-24 21:02:47 +04:00
$users = $q->query("FROM ".$this->options['name']." WHERE ".$dql, $params);
2006-05-30 12:42:10 +04:00
return $users;
}
2006-08-17 13:42:18 +04:00
public function findByDql($dql, array $params = array()) {
return $this->findBySql($dql, $params);
}
2006-05-30 12:42:10 +04:00
/**
* clear
* clears the first level cache (identityMap)
*
* @return void
*/
2006-12-29 17:40:47 +03:00
public function clear()
{
2006-05-30 12:42:10 +04:00
$this->identityMap = array();
}
/**
* getRecord
* first checks if record exists in identityMap, if not
* returns a new record
*
* @return Doctrine_Record
*/
2006-12-29 17:40:47 +03:00
public function getRecord()
{
2006-09-03 23:20:02 +04:00
$this->data = array_change_key_case($this->data, CASE_LOWER);
2006-05-30 12:42:10 +04:00
$key = $this->getIdentifier();
2006-12-29 17:01:31 +03:00
if ( ! is_array($key)) {
2006-05-30 12:42:10 +04:00
$key = array($key);
2006-12-29 17:01:31 +03:00
}
foreach ($key as $k) {
if ( ! isset($this->data[$k])) {
2006-08-22 23:34:40 +04:00
throw new Doctrine_Exception("Primary key value for $k wasn't found");
2006-12-29 17:01:31 +03:00
}
2006-05-30 12:42:10 +04:00
$id[] = $this->data[$k];
}
2006-06-01 15:58:05 +04:00
2006-05-30 12:42:10 +04:00
$id = implode(' ', $id);
2006-12-29 17:01:31 +03:00
if (isset($this->identityMap[$id])) {
2006-05-30 12:42:10 +04:00
$record = $this->identityMap[$id];
2006-12-29 17:01:31 +03:00
} else {
2006-10-24 21:02:47 +04:00
$record = new $this->options['name']($this);
2006-05-30 12:42:10 +04:00
$this->identityMap[$id] = $record;
}
$this->data = array();
return $record;
}
/**
* @param $id database row id
* @throws Doctrine_Find_Exception
*/
2006-12-29 17:40:47 +03:00
final public function getProxy($id = null)
{
2006-12-29 17:01:31 +03:00
if ($id !== null) {
2006-05-30 12:42:10 +04:00
$query = "SELECT ".implode(", ",$this->primaryKeys)." FROM ".$this->getTableName()." WHERE ".implode(" = ? && ",$this->primaryKeys)." = ?";
$query = $this->applyInheritance($query);
2006-10-24 21:02:47 +04:00
$params = array_merge(array($id), array_values($this->options['inheritanceMap']));
2006-05-30 12:42:10 +04:00
2006-12-01 01:33:54 +03:00
$this->data = $this->conn->execute($query,$params)->fetch(PDO::FETCH_ASSOC);
2006-05-30 12:42:10 +04:00
2006-12-29 17:01:31 +03:00
if ($this->data === false)
return false;
2006-05-30 12:42:10 +04:00
}
return $this->getRecord();
}
/**
* count
*
* @return integer
*/
2006-12-29 17:40:47 +03:00
public function count()
{
2006-12-01 01:33:54 +03:00
$a = $this->conn->getDBH()->query("SELECT COUNT(1) FROM ".$this->options['tableName'])->fetch(PDO::FETCH_NUM);
return current($a);
}
2006-05-30 12:42:10 +04:00
/**
* @return Doctrine_Query a Doctrine_Query object
*/
2006-12-29 17:40:47 +03:00
public function getQueryObject()
{
2006-08-22 03:21:01 +04:00
$graph = new Doctrine_Query($this->getConnection());
2006-05-30 12:42:10 +04:00
$graph->load($this->getComponentName());
return $graph;
}
/**
* execute
* @param string $query
* @param array $array
* @param integer $limit
* @param integer $offset
*/
public function execute($query, array $array = array(), $limit = null, $offset = null) {
$coll = new Doctrine_Collection($this);
2006-12-01 01:33:54 +03:00
$query = $this->conn->modifyLimitQuery($query,$limit,$offset);
2006-12-29 17:01:31 +03:00
if ( ! empty($array)) {
2006-12-01 01:33:54 +03:00
$stmt = $this->conn->getDBH()->prepare($query);
2006-05-30 12:42:10 +04:00
$stmt->execute($array);
} else {
2006-12-01 01:33:54 +03:00
$stmt = $this->conn->getDBH()->query($query);
2006-05-30 12:42:10 +04:00
}
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt->closeCursor();
2006-12-29 17:01:31 +03:00
foreach ($data as $row) {
2006-05-30 12:42:10 +04:00
$this->data = $row;
$record = $this->getRecord();
$coll->add($record);
}
return $coll;
}
2006-06-18 02:46:03 +04:00
/**
* sets enumerated value array for given field
*
* @param string $field
* @param array $values
* @return void
*/
2006-12-29 17:40:47 +03:00
final public function setEnumValues($field, array $values)
{
2006-10-24 21:02:47 +04:00
$this->options['enumMap'][strtolower($field)] = $values;
2006-06-18 02:46:03 +04:00
}
2006-06-20 01:31:22 +04:00
/**
* @param string $field
* @return array
*/
2006-12-29 17:40:47 +03:00
final public function getEnumValues($field)
{
2006-12-29 17:01:31 +03:00
if (isset($this->options['enumMap'][$field])) {
2006-10-24 21:02:47 +04:00
return $this->options['enumMap'][$field];
2006-12-29 17:01:31 +03:00
} else {
2006-06-20 01:31:22 +04:00
return array();
2006-12-29 17:01:31 +03:00
}
2006-06-20 01:31:22 +04:00
}
2006-06-18 02:46:03 +04:00
/**
* enumValue
*
* @param string $field
* @param integer $index
* @return mixed
2006-06-18 02:46:03 +04:00
*/
2006-12-29 17:40:47 +03:00
final public function enumValue($field, $index)
{
if ($index instanceof Doctrine_Null)
return $index;
2006-10-24 21:02:47 +04:00
return isset($this->options['enumMap'][$field][$index]) ? $this->options['enumMap'][$field][$index] : $index;
2006-06-18 02:46:03 +04:00
}
/**
* invokeSet
*
* @param mixed $value
*/
2006-12-29 17:40:47 +03:00
public function invokeSet(Doctrine_Record $record, $name, $value)
{
2006-12-29 17:01:31 +03:00
if ( ! ($this->getAttribute(Doctrine::ATTR_ACCESSORS) & Doctrine::ACCESSOR_SET)) {
2006-12-24 01:48:16 +03:00
return $value;
2006-12-29 17:01:31 +03:00
}
2006-12-24 01:48:16 +03:00
$prefix = $this->getAttribute(Doctrine::ATTR_ACCESSOR_PREFIX_SET);
if (!$prefix)
$prefix = 'set';
$method = $prefix . $name;
2006-12-29 17:01:31 +03:00
if (method_exists($record, $method)) {
return $record->$method($value);
}
return $value;
}
/**
* invokeGet
*
* @param mixed $value
*/
2006-12-29 17:40:47 +03:00
public function invokeGet(Doctrine_Record $record, $name, $value)
{
2006-12-29 17:01:31 +03:00
if ( ! ($this->getAttribute(Doctrine::ATTR_ACCESSORS) & Doctrine::ACCESSOR_GET)) {
return $value;
2006-12-29 17:01:31 +03:00
}
2006-12-24 01:48:16 +03:00
$prefix = $this->getAttribute(Doctrine::ATTR_ACCESSOR_PREFIX_GET);
if (!$prefix)
$prefix = 'get';
2006-12-24 01:48:16 +03:00
$method = $prefix . $name;
2006-12-29 17:01:31 +03:00
if (method_exists($record, $method)) {
return $record->$method($value);
}
return $value;
}
2006-06-18 02:46:03 +04:00
/**
* enumIndex
*
* @param string $field
* @param mixed $value
* @return mixed
2006-06-18 02:46:03 +04:00
*/
2006-12-29 17:40:47 +03:00
final public function enumIndex($field, $value)
{
2006-12-29 17:01:31 +03:00
if ( ! isset($this->options['enumMap'][$field])) {
$values = array();
2006-12-29 17:01:31 +03:00
} else {
2006-10-24 21:02:47 +04:00
$values = $this->options['enumMap'][$field];
2006-12-29 17:01:31 +03:00
}
return array_search($value, $values);
2006-06-18 02:46:03 +04:00
}
2006-05-30 12:42:10 +04:00
/**
* getDefinitionOf
*
* @return string ValueWrapper class name on success, false on failure
*/
2006-12-29 17:40:47 +03:00
public function getValueWrapperOf($column)
{
2006-12-29 17:01:31 +03:00
if (isset($this->columns[$column][2]['wrapper'])) {
return $this->columns[$column][2]['wrapper'];
2006-12-29 17:01:31 +03:00
}
return false;
}
/**
* getColumnCount
*
* @return integer the number of columns in this table
2006-05-30 12:42:10 +04:00
*/
2006-12-29 17:40:47 +03:00
final public function getColumnCount()
{
return $this->columnCount;
2006-05-30 12:42:10 +04:00
}
2006-06-18 02:46:03 +04:00
2006-05-30 12:42:10 +04:00
/**
* returns all columns and their definitions
*
* @return array
*/
2006-12-29 17:40:47 +03:00
final public function getColumns()
{
2006-05-30 12:42:10 +04:00
return $this->columns;
}
/**
* returns an array containing all the column names
*
* @return array
*/
2006-12-29 17:40:47 +03:00
public function getColumnNames()
{
2006-05-30 12:42:10 +04:00
return array_keys($this->columns);
}
2006-12-29 14:03:19 +03:00
2006-06-18 02:46:03 +04:00
/**
* getDefinitionOf
2006-06-25 22:34:53 +04:00
*
* @return mixed array on success, false on failure
2006-06-18 02:46:03 +04:00
*/
2006-12-29 17:40:47 +03:00
public function getDefinitionOf($column)
{
2006-12-29 17:01:31 +03:00
if (isset($this->columns[$column])) {
2006-06-18 02:46:03 +04:00
return $this->columns[$column];
2006-12-29 17:01:31 +03:00
}
2006-06-25 22:34:53 +04:00
return false;
2006-06-18 02:46:03 +04:00
}
2006-06-03 13:10:43 +04:00
/**
* getTypeOf
2006-06-25 22:34:53 +04:00
*
* @return mixed string on success, false on failure
2006-06-03 13:10:43 +04:00
*/
2006-12-29 17:40:47 +03:00
public function getTypeOf($column)
{
2006-12-29 17:01:31 +03:00
if (isset($this->columns[$column])) {
return $this->columns[$column][0];
2006-12-29 17:01:31 +03:00
}
2006-06-25 22:34:53 +04:00
return false;
2006-06-03 13:10:43 +04:00
}
2006-05-30 12:42:10 +04:00
/**
* setData
* doctrine uses this function internally
* users are strongly discouraged to use this function
*
* @param array $data internal data
* @return void
*/
2006-12-29 17:40:47 +03:00
public function setData(array $data)
{
2006-05-30 12:42:10 +04:00
$this->data = $data;
}
/**
* returns the maximum primary key value
*
* @return integer
*/
2006-12-29 17:40:47 +03:00
final public function getMaxIdentifier()
{
2006-05-30 12:42:10 +04:00
$sql = "SELECT MAX(".$this->getIdentifier().") FROM ".$this->getTableName();
2006-12-01 01:33:54 +03:00
$stmt = $this->conn->getDBH()->query($sql);
2006-05-30 12:42:10 +04:00
$data = $stmt->fetch(PDO::FETCH_NUM);
return isset($data[0])?$data[0]:1;
}
/**
* returns simple cached query
*
* @return string
*/
2006-12-29 17:40:47 +03:00
final public function getQuery()
{
2006-05-30 12:42:10 +04:00
return $this->query;
}
/**
* returns internal data, used by Doctrine_Record instances
2006-05-30 12:42:10 +04:00
* when retrieving data from database
*
* @return array
*/
2006-12-29 17:40:47 +03:00
final public function getData()
{
2006-05-30 12:42:10 +04:00
return $this->data;
}
/**
* returns a string representation of this object
*
* @return string
*/
2006-12-29 17:40:47 +03:00
public function __toString()
{
2006-05-30 12:42:10 +04:00
return Doctrine_Lib::getTableAsString($this);
}
}