Table.php 38.9 KB
Newer Older
doctrine's avatar
doctrine committed
1
<?php
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 *  $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>.
 */
doctrine's avatar
doctrine committed
21 22 23
/**
 * Doctrine_Table   represents a database table
 *                  each Doctrine_Table holds the information of foreignKeys and associations
24
 *
doctrine's avatar
doctrine committed
25
 *
zYne's avatar
zYne committed
26 27 28 29 30 31 32 33
 * @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
 */
lsmith's avatar
lsmith committed
34 35
class Doctrine_Table extends Doctrine_Configurable implements Countable
{
doctrine's avatar
doctrine committed
36 37 38 39 40 41 42 43 44 45 46 47 48
    /**
     * @var array $data                                 temporary data which is then loaded into Doctrine_Record::$data
     */
    private $data             = array();
    /**
     * @var array $primaryKeys                          an array containing all primary key column names
     */
    private $primaryKeys      = array();
    /**
     * @var mixed $identifier
     */
    private $identifier;
    /**
49 50
     * @see Doctrine_Identifier constants
     * @var integer $identifierType                     the type of identifier this table uses
doctrine's avatar
doctrine committed
51 52 53 54 55 56 57
     */
    private $identifierType;
    /**
     * @var string $query                               cached simple query
     */
    private $query;
    /**
zYne's avatar
zYne committed
58
     * @var Doctrine_Connection $conn                   Doctrine_Connection object that created this table
doctrine's avatar
doctrine committed
59
     */
zYne's avatar
zYne committed
60
    private $conn;
doctrine's avatar
doctrine committed
61
    /**
zYne's avatar
zYne committed
62
     * @var string $name
doctrine's avatar
doctrine committed
63 64 65 66 67 68
     */
    private $name;
    /**
     * @var array $identityMap                          first level cache
     */
    private $identityMap        = array();
69
    /**
70
     * @var Doctrine_Table_Repository $repository       record repository
71
     */
doctrine's avatar
doctrine committed
72 73
    private $repository;
    /**
zYne's avatar
zYne committed
74 75
     * @var array $columns                  an array of column definitions,
     *                                      keys as column names and values as column definitions
lsmith's avatar
lsmith committed
76
     *
zYne's avatar
zYne committed
77
     *                                      the value array has three values:
lsmith's avatar
lsmith committed
78
     *
zYne's avatar
zYne committed
79 80 81 82 83 84
     *                                      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(
85 86
     *                                             'name' => array('string',  20, array('notnull' => true, 'default' => 'someone')),
     *                                             'age'  => array('integer', 11, array('notnull' => true))
zYne's avatar
zYne committed
87
     *                                              )
doctrine's avatar
doctrine committed
88
     */
zYne's avatar
zYne committed
89
    protected $columns          = array();
doctrine's avatar
doctrine committed
90
    /**
zYne's avatar
zYne committed
91 92 93 94
     * @var array $columnAliases            an array of column aliases
     *                                      keys as column aliases and values as column names
     */
    protected $columnAliases    = array();
doctrine's avatar
doctrine committed
95
    /**
zYne's avatar
zYne committed
96 97
     * @var integer $columnCount            cached column count, Doctrine_Record uses this column count in when
     *                                      determining its state
doctrine's avatar
doctrine committed
98 99
     */
    private $columnCount;
100
    /**
zYne's avatar
zYne committed
101
     * @var boolean $hasDefaultValues       whether or not this table has default values
102 103
     */
    private $hasDefaultValues;
zYne's avatar
zYne committed
104
    /**
105
     * @var array $options                  an array containing all options
zYne's avatar
zYne committed
106
     *
107
     *      -- name                         name of the component, for example component name of the GroupTable is 'Group'
zYne's avatar
zYne committed
108
     *
zYne's avatar
zYne committed
109 110
     *      -- parents                      the parent classes of this component
     *
111 112 113 114
     *      -- 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)
     *
115 116
     *      -- 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
zYne's avatar
zYne committed
117
     *
118 119 120
     *      -- 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
zYne's avatar
zYne committed
121
     *
122
     *      -- enumMap                      enum value arrays
zYne's avatar
zYne committed
123
     *
124 125
     *      -- inheritanceMap               inheritanceMap is used for inheritance mapping, keys representing columns and values
     *                                      the column values that should correspond to child classes
zYne's avatar
zYne committed
126
     *
zYne's avatar
zYne committed
127
     *      -- type                         table type (mysql example: INNODB)
zYne's avatar
zYne committed
128 129 130
     *
     *      -- charset                      character set
     *
131 132
     *      -- foreignKeys                  the foreign keys of this table
     *
zYne's avatar
zYne committed
133
     *      -- collation
zYne's avatar
zYne committed
134
     *
zYne's avatar
zYne committed
135
     *      -- indexes                      the index definitions of this table
zYne's avatar
zYne committed
136 137 138 139
     *
     *      -- treeImpl                     the tree implementation of this table (if any)
     *
     *      -- treeOptions                  the tree options
zYne's avatar
zYne committed
140 141
     */
    protected $options          = array('name'           => null,
142 143 144 145 146 147 148 149 150 151
        'tableName'      => null,
        'sequenceName'   => null,
        'inheritanceMap' => array(),
        'enumMap'        => array(),
        'engine'         => null,
        'charset'        => null,
        'collation'      => null,
        'treeImpl'       => null,
        'treeOptions'    => null,
        'indexes'        => array(),
152
        'parents'        => array(),
153
    );
zYne's avatar
zYne committed
154
    /**
155
     * @var Doctrine_Tree $tree                 tree object associated with this table
zYne's avatar
zYne committed
156 157
     */
    protected $tree;
zYne's avatar
zYne committed
158 159 160 161
    /**
     * @var Doctrine_Relation_Parser $_parser   relation parser object
     */
    protected $_parser;
doctrine's avatar
doctrine committed
162 163
    /**
     * the constructor
zYne's avatar
zYne committed
164 165
     * @throws Doctrine_Connection_Exception    if there are no opened connections
     * @throws Doctrine_Table_Exception         if there is already an instance of this table
doctrine's avatar
doctrine committed
166 167
     * @return void
     */
168
    public function __construct($name, Doctrine_Connection $conn)
lsmith's avatar
lsmith committed
169
    {
zYne's avatar
zYne committed
170
        $this->conn = $conn;
doctrine's avatar
doctrine committed
171

zYne's avatar
zYne committed
172
        $this->setParent($this->conn);
doctrine's avatar
doctrine committed
173

zYne's avatar
zYne committed
174
        $this->options['name'] = $name;
zYne's avatar
zYne committed
175
        $this->_parser = new Doctrine_Relation_Parser($this);
doctrine's avatar
doctrine committed
176

lsmith's avatar
lsmith committed
177
        if ( ! class_exists($name) || empty($name)) {
zYne's avatar
zYne committed
178
            throw new Doctrine_Exception("Couldn't find class " . $name);
lsmith's avatar
lsmith committed
179
        }
doctrine's avatar
doctrine committed
180 181 182 183 184 185 186 187 188
        $record = new $name($this);

        $names = array();

        $class = $name;

        // get parent classes

        do {
zYne's avatar
zYne committed
189 190 191
            if ($class == "Doctrine_Record") {
                break;                        
            }
doctrine's avatar
doctrine committed
192

lsmith's avatar
lsmith committed
193
            $name  = $class;
doctrine's avatar
doctrine committed
194
            $names[] = $name;
lsmith's avatar
lsmith committed
195
        } while ($class = get_parent_class($class));
doctrine's avatar
doctrine committed
196 197 198

        // reverse names
        $names = array_reverse($names);
199 200 201
        // save parents
        array_pop($names);
        $this->options['parents'] = $names;
doctrine's avatar
doctrine committed
202 203

        // create database table
lsmith's avatar
lsmith committed
204
        if (method_exists($record, 'setTableDefinition')) {
doctrine's avatar
doctrine committed
205 206
            $record->setTableDefinition();

207
            // set the table definition for the given tree implementation
zYne's avatar
zYne committed
208
            if ($this->isTree()) {
209
                $this->getTree()->setTableDefinition();
zYne's avatar
zYne committed
210 211
            }
            
doctrine's avatar
doctrine committed
212 213
            $this->columnCount = count($this->columns);

lsmith's avatar
lsmith committed
214
            if (isset($this->columns)) {
zYne's avatar
zYne committed
215
                // get the declaring class of setTableDefinition method
216
                $method    = new ReflectionMethod($this->options['name'], 'setTableDefinition');
doctrine's avatar
doctrine committed
217 218
                $class     = $method->getDeclaringClass();

219 220
                $this->options['declaringClass'] = $class;

lsmith's avatar
lsmith committed
221
                if ( ! isset($this->options['tableName'])) {
zYne's avatar
zYne committed
222
                    $this->options['tableName'] = Doctrine::tableize($class->getName());
lsmith's avatar
lsmith committed
223 224
                }
                switch (count($this->primaryKeys)) {
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
                case 0:
                    $this->columns = array_merge(array('id' =>
                        array('integer',
                            20,
                            array('autoincrement' => true,
                            'primary'       => true,
                        )
                    )
                ), $this->columns);

                    $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;
lsmith's avatar
lsmith committed
244

245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
                    } else {
                        foreach ($this->primaryKeys as $pk) {
                            $e = $this->columns[$pk][2];

                            $found = false;

                            foreach ($e as $option => $value) {
                                if ($found)
                                    break;

                                $e2 = explode(':', $option);

                                switch (strtolower($e2[0])) {
                                case 'autoincrement':
                                case 'autoinc':
                                    $this->identifierType = Doctrine_Identifier::AUTO_INCREMENT;
                                    $found = true;
                                    break;
                                case 'seq':
                                case 'sequence':
                                    $this->identifierType = Doctrine_Identifier::SEQUENCE;
                                    $found = true;

                                    if ($value) {
                                        $this->options['sequenceName'] = $value;
                                    } else {
                                        if (($sequence = $this->getAttribute(Doctrine::ATTR_DEFAULT_SEQUENCE)) !== null) {
                                            $this->options['sequenceName'] = $sequence;
                                        } else {
                                            $this->options['sequenceName'] = $this->conn->getSequenceName($this->options['tableName']);
                                        }
zYne's avatar
zYne committed
276
                                    }
277
                                    break;
278
                                }
doctrine's avatar
doctrine committed
279
                            }
280 281 282 283
                            if ( ! isset($this->identifierType)) {
                                $this->identifierType = Doctrine_Identifier::NORMAL;
                            }
                            $this->identifier = $pk;
doctrine's avatar
doctrine committed
284
                        }
285
                    }
zYne's avatar
zYne committed
286
                }
doctrine's avatar
doctrine committed
287 288
            }
        } else {
zYne's avatar
zYne committed
289
            throw new Doctrine_Table_Exception("Class '$name' has no table definition.");
doctrine's avatar
doctrine committed
290
        }
291

doctrine's avatar
doctrine committed
292 293
        $record->setUp();

294
        // if tree, set up tree
zYne's avatar
zYne committed
295
        if ($this->isTree()) {
296
            $this->getTree()->setUp();
zYne's avatar
zYne committed
297
        }
298
        $this->repository = new Doctrine_Table_Repository($this);
doctrine's avatar
doctrine committed
299
    }
300 301 302 303 304 305 306 307 308
    /**
     * 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
     */
zYne's avatar
zYne committed
309 310
    public function export() 
    {
zYne's avatar
zYne committed
311 312 313
        if ( ! Doctrine::isValidClassname($this->options['declaringClass']->getName())) {
            throw new Doctrine_Table_Exception('Class name not valid.');
        }
314

zYne's avatar
zYne committed
315 316 317 318 319
        try {
            $columns = array();
            $primary = array();

            foreach ($this->columns as $name => $column) {
zYne's avatar
zYne committed
320 321 322
                $definition = $column[2];
                $definition['type'] = $column[0];
                $definition['length'] = $column[1];
zYne's avatar
zYne committed
323 324

                switch ($definition['type']) {
325 326 327 328 329 330 331
                case 'enum':
                    if (isset($definition['default'])) {
                        $definition['default'] = $this->enumIndex($name, $definition['default']);
                    }
                    break;
                case 'boolean':
                    if (isset($definition['default'])) {
zYne's avatar
zYne committed
332
                        $definition['default'] = $this->conn->convertBooleans($definition['default']);
333 334
                    }
                    break;
335
                }
zYne's avatar
zYne committed
336
                $columns[$name] = $definition;
337

zYne's avatar
zYne committed
338 339 340 341
                if(isset($definition['primary']) && $definition['primary']) {
                    $primary[] = $name;
                }
            }
zYne's avatar
zYne committed
342

zYne's avatar
zYne committed
343 344 345 346 347
            if ($this->getAttribute(Doctrine::ATTR_EXPORT) & Doctrine::EXPORT_CONSTRAINTS) {

                foreach ($this->getRelations() as $name => $relation) {
                    $fk = $relation->toArray();
                    $fk['foreignTable'] = $relation->getTable()->getTableName();
348

349 350 351 352
                    if ($relation->getTable() === $this && in_array($relation->getLocal(), $primary)) {
                        continue;                                                                                 	
                    }

zYne's avatar
zYne committed
353
                    if ($relation->hasConstraint()) {
354

zYne's avatar
zYne committed
355 356 357 358 359 360
                        $options['foreignKeys'][] = $fk;
                    } elseif ($relation instanceof Doctrine_Relation_LocalKey) {
                        $options['foreignKeys'][] = $fk;
                    }
                }
            }
zYne's avatar
zYne committed
361

zYne's avatar
zYne committed
362 363 364 365 366 367 368
            $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;
369 370 371
            }
        }
    }
zYne's avatar
zYne committed
372 373 374 375 376 377 378 379 380
    /**
     * exportConstraints
     * exports the constraints of this table into database based on option definitions
     *
     * @throws Doctrine_Connection_Exception    if something went wrong on db level
     * @return void
     */
    public function exportConstraints()
    {
381 382
        try {
            $this->conn->beginTransaction();
zYne's avatar
zYne committed
383 384 385 386 387 388 389 390 391 392 393

            foreach ($this->options['index'] as $index => $definition) {
                $this->conn->export->createIndex($this->options['tableName'], $index, $definition);
            }
            $this->conn->commit();
        } catch(Doctrine_Connection_Exception $e) {
            $this->conn->rollback();

            throw $e;
        }
    }
zYne's avatar
zYne committed
394 395 396 397 398 399 400 401 402 403 404
    /**
     * getRelationParser
     * return the relation parser associated with this table
     *
     * @return Doctrine_Relation_Parser     relation parser object
     */
    public function getRelationParser()
    {
        return $this->_parser;
    }
    /**
zYne's avatar
zYne committed
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
     * __get
     * an alias for getOption
     *
     * @param string $option
     */
    public function __get($option)
    {
        if (isset($this->options[$option])) {
            return $this->options[$option];
        }
        return null;
    }
    /**
     * __isset
     *
     * @param string $option
     */
    public function __isset($option) 
    {
        return isset($this->options[$option]);
    }
426 427 428 429 430 431 432 433 434 435 436
    /**
     * addForeignKey
     *
     * adds a foreignKey to this table
     *
     * @return void
     */
    public function addForeignKey(array $definition)
    {
        $this->options['foreignKeys'][] = $definition;
    }
zYne's avatar
zYne committed
437 438 439 440 441 442 443 444 445
    /**
     * addIndex
     * 
     * adds an index to this table
     *
     * @return void
     */
    public function addIndex($index, array $definition)
    {
446
        $index = $this->conn->getIndexName($index);
zYne's avatar
zYne committed
447 448 449 450 451 452 453 454 455 456 457 458
        $this->options['indexes'][$index] = $definition;
    }
    /**
     * getIndex
     *
     * @return array|boolean        array on success, FALSE on failure
     */
    public function getIndex($index) 
    {
        if (isset($this->options['indexes'][$index])) {
            return $this->options['indexes'][$index];
        }
459

zYne's avatar
zYne committed
460 461
        return false;
    }
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
    public function bind($args, $type)
    {
    	$options = array();
        $options['type'] = $type;
        
        // the following is needed for backwards compatibility
        if (is_string($args[1])) {
            if ( ! isset($args[2])) {
                $args[2] = array();
            } elseif (is_string($args[2])) {
                $args[2] = (array) $args[2];
            }

            $classes = array_merge($this->options['parents'], array($this->getComponentName()));


            $e = explode('.', $args[1]);
            if (in_array($e[0], $classes)) {
                $options['local'] = $e[1];
            } else {
                $e2 = explode(' as ', $args[0]);
                if ($e[0] !== $e2[0] && ( ! isset($e2[1]) || $e[0] !== $e2[1])) {
                    $options['refClass'] = $e[0];
                }

                $options['foreign'] = $e[1];
            }

            $options = array_merge($args[2], $options);

            $this->_parser->bind($args[0], $options);
        } else {
            $options = array_merge($args[1], $options);
            $this->_parser->bind($args[0], $options);
        }
    }
    /**
     * getRelation
     *
     * @param string $alias      relation alias
     */
    public function getRelation($alias, $recursive = true)
    {
        return $this->_parser->getRelation($alias, $recursive);
    }
    /**
     * getRelations
     * returns an array containing all relation objects
     *
     * @return array        an array of Doctrine_Relation objects
     */
    public function getRelations()
    {
        return $this->_parser->getRelations();
    }
zYne's avatar
zYne committed
517 518 519 520
    /**
     * createQuery
     * creates a new Doctrine_Query object and adds the component name
     * of this table as the query 'from' part
lsmith's avatar
lsmith committed
521
     *
zYne's avatar
zYne committed
522 523
     * @return Doctrine_Query
     */
lsmith's avatar
lsmith committed
524 525
    public function createQuery()
    {
zYne's avatar
zYne committed
526 527
        return Doctrine_Query::create()->from($this->getComponentName());
    }
doctrine's avatar
doctrine committed
528
    /**
529 530 531
     * getRepository
     *
     * @return Doctrine_Table_Repository
doctrine's avatar
doctrine committed
532
     */
lsmith's avatar
lsmith committed
533 534
    public function getRepository()
    {
doctrine's avatar
doctrine committed
535 536
        return $this->repository;
    }
zYne's avatar
zYne committed
537 538 539 540 541 542 543 544 545 546
    /**
     * setOption
     * sets an option and returns this object in order to 
     * allow flexible method chaining
     *
     * @see Doctrine_Table::$_options   for available options
     * @param string $name              the name of the option to set
     * @param mixed $value              the value of the option
     * @return Doctrine_Table           this object
     */
lsmith's avatar
lsmith committed
547 548
    public function setOption($name, $value)
    {
lsmith's avatar
lsmith committed
549
        switch ($name) {
550 551 552 553 554 555 556 557 558 559 560
        case 'name':
        case 'tableName':
            break;
        case 'enumMap':
        case 'inheritanceMap':
        case 'index':
        case 'treeOptions':
            if ( ! is_array($value)) {
                throw new Doctrine_Table_Exception($name . ' should be an array.');
            }
            break;
zYne's avatar
zYne committed
561 562 563
        }
        $this->options[$name] = $value;
    }
zYne's avatar
zYne committed
564 565 566 567 568 569 570
    /**
     * getOption
     * returns the value of given option
     *
     * @param string $name  the name of the option
     * @return mixed        the value of given option
     */
lsmith's avatar
lsmith committed
571 572
    public function getOption($name)
    {
lsmith's avatar
lsmith committed
573
        if (isset($this->options[$name])) {
574
            return $this->options[$name];
lsmith's avatar
lsmith committed
575
        }
576 577
        return null;
    }
zYne's avatar
zYne committed
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
    /**
     * getColumnName
     *
     * returns a column name for column alias
     * if the actual name for the alias cannot be found
     * this method returns the given alias
     *
     * @param string $alias         column alias
     * @return string               column name
     */
    public function getColumnName($alias)
    {
        if(isset($this->columnAliases[$alias])) {
            return $this->columnAliases[$alias];
        }
593

zYne's avatar
zYne committed
594 595
        return $alias;
    }
doctrine's avatar
doctrine committed
596 597
    /**
     * setColumn
zYne's avatar
zYne committed
598
     *
doctrine's avatar
doctrine committed
599 600 601 602
     * @param string $name
     * @param string $type
     * @param integer $length
     * @param mixed $options
zYne's avatar
zYne committed
603
     * @throws Doctrine_Table_Exception     if trying use wrongly typed parameter
doctrine's avatar
doctrine committed
604 605
     * @return void
     */
zYne's avatar
zYne committed
606 607
    public function setColumn($name, $type, $length = null, $options = array())
    {
lsmith's avatar
lsmith committed
608
        if (is_string($options)) {
609
            $options = explode('|', $options);
lsmith's avatar
lsmith committed
610
        }
zYne's avatar
zYne committed
611

lsmith's avatar
lsmith committed
612 613 614
        foreach ($options as $k => $option) {
            if (is_numeric($k)) {
                if ( ! empty($option)) {
615
                    $options[$option] = true;
lsmith's avatar
lsmith committed
616
                }
617 618 619
                unset($options[$k]);
            }
        }
lsmith's avatar
lsmith committed
620

zYne's avatar
zYne committed
621 622
        $name  = strtolower($name);
        $parts = explode(' as ', $name);
623

zYne's avatar
zYne committed
624 625 626 627 628 629 630
        if (count($parts) > 1) {
            $this->columnAliases[$parts[1]] = $parts[0];
            $name = $parts[0];
        }


        if ($length == null) {
zYne's avatar
zYne committed
631
            $length = 2147483647;
zYne's avatar
zYne committed
632 633 634
        }

        if ((string) (int) $length !== (string) $length) {
zYne's avatar
zYne committed
635 636
            throw new Doctrine_Table_Exception('Invalid argument given for column length');
        }
zYne's avatar
zYne committed
637

zYne's avatar
zYne committed
638
        $this->columns[$name] = array($type, $length, $options);
639

lsmith's avatar
lsmith committed
640
        if (isset($options['primary'])) {
doctrine's avatar
doctrine committed
641 642
            $this->primaryKeys[] = $name;
        }
lsmith's avatar
lsmith committed
643
        if (isset($options['default'])) {
644 645 646 647 648 649 650 651 652
            $this->hasDefaultValues = true;
        }
    }
    /**
     * hasDefaultValues
     * returns true if this table has default values, otherwise false
     *
     * @return boolean
     */
lsmith's avatar
lsmith committed
653 654
    public function hasDefaultValues()
    {
655
        return $this->hasDefaultValues;
doctrine's avatar
doctrine committed
656
    }
zYne's avatar
zYne committed
657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675
    /**
     * getDefaultValueOf
     * returns the default value(if any) for given column
     *
     * @param string $column
     * @return mixed
     */
    public function getDefaultValueOf($column)
    {
        $column = strtolower($column);
        if ( ! isset($this->columns[$column])) {
            throw new Doctrine_Table_Exception("Couldn't get default value. Column ".$column." doesn't exist.");
        }
        if (isset($this->columns[$column][2]['default'])) {
            return $this->columns[$column][2]['default'];
        } else {
            return null;
        }
    }
doctrine's avatar
doctrine committed
676 677 678
    /**
     * @return mixed
     */
zYne's avatar
zYne committed
679
    public function getIdentifier()
lsmith's avatar
lsmith committed
680
    {
doctrine's avatar
doctrine committed
681 682 683 684 685
        return $this->identifier;
    }
    /**
     * @return integer
     */
zYne's avatar
zYne committed
686
    public function getIdentifierType()
lsmith's avatar
lsmith committed
687
    {
doctrine's avatar
doctrine committed
688 689 690 691 692 693
        return $this->identifierType;
    }
    /**
     * hasColumn
     * @return boolean
     */
zYne's avatar
zYne committed
694
    public function hasColumn($name)
lsmith's avatar
lsmith committed
695
    {
doctrine's avatar
doctrine committed
696 697 698 699 700 701
        return isset($this->columns[$name]);
    }
    /**
     * @param mixed $key
     * @return void
     */
zYne's avatar
zYne committed
702
    public function setPrimaryKey($key)
lsmith's avatar
lsmith committed
703
    {
lsmith's avatar
lsmith committed
704
        switch (gettype($key)) {
705 706 707 708 709 710
        case "array":
            $this->primaryKeys = array_values($key);
            break;
        case "string":
            $this->primaryKeys[] = $key;
            break;
lsmith's avatar
lsmith committed
711
        };
doctrine's avatar
doctrine committed
712 713 714 715 716
    }
    /**
     * returns all primary keys
     * @return array
     */
zYne's avatar
zYne committed
717
    public function getPrimaryKeys()
lsmith's avatar
lsmith committed
718
    {
doctrine's avatar
doctrine committed
719 720 721 722 723
        return $this->primaryKeys;
    }
    /**
     * @return boolean
     */
zYne's avatar
zYne committed
724
    public function hasPrimaryKey($key)
lsmith's avatar
lsmith committed
725
    {
doctrine's avatar
doctrine committed
726 727 728
        return in_array($key,$this->primaryKeys);
    }
    /**
zYne's avatar
zYne committed
729
     * @return Doctrine_Connection
doctrine's avatar
doctrine committed
730
     */
lsmith's avatar
lsmith committed
731 732
    public function getConnection()
    {
zYne's avatar
zYne committed
733
        return $this->conn;
doctrine's avatar
doctrine committed
734
    }
735
    /**
doctrine's avatar
doctrine committed
736 737 738 739 740 741 742
     * 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()) {
743
        $this->data         = $array;
chtito's avatar
chtito committed
744
        $record = new $this->options['name']($this, true);
doctrine's avatar
doctrine committed
745 746 747 748 749 750 751
        $this->data         = array();
        return $record;
    }
    /**
     * finds a record by its identifier
     *
     * @param $id                       database row id
zYne's avatar
zYne committed
752
     * @return Doctrine_Record|false    a record for given database identifier
doctrine's avatar
doctrine committed
753
     */
lsmith's avatar
lsmith committed
754 755
    public function find($id)
    {
lsmith's avatar
lsmith committed
756 757
        if ($id !== null) {
            if ( ! is_array($id)) {
doctrine's avatar
doctrine committed
758
                $id = array($id);
lsmith's avatar
lsmith committed
759
            } else {
doctrine's avatar
doctrine committed
760
                $id = array_values($id);
lsmith's avatar
lsmith committed
761
            }
doctrine's avatar
doctrine committed
762

zYne's avatar
zYne committed
763 764
            $query  = 'SELECT ' . implode(', ', array_keys($this->columns)) . ' FROM ' . $this->getTableName() 
                    . ' WHERE ' . implode(' = ? AND ', $this->primaryKeys) . ' = ?';
doctrine's avatar
doctrine committed
765
            $query  = $this->applyInheritance($query);
doctrine's avatar
doctrine committed
766

zYne's avatar
zYne committed
767
            $params = array_merge($id, array_values($this->options['inheritanceMap']));
doctrine's avatar
doctrine committed
768

zYne's avatar
zYne committed
769
            $stmt  = $this->conn->execute($query, $params);
doctrine's avatar
doctrine committed
770 771

            $this->data = $stmt->fetch(PDO::FETCH_ASSOC);
doctrine's avatar
doctrine committed
772

lsmith's avatar
lsmith committed
773
            if ($this->data === false)
774
                return false;
lsmith's avatar
lsmith committed
775

pookey's avatar
pookey committed
776
            return $this->getRecord();
doctrine's avatar
doctrine committed
777
        }
pookey's avatar
pookey committed
778
        return false;
doctrine's avatar
doctrine committed
779 780 781 782 783 784
    }
    /**
     * applyInheritance
     * @param $where                    query where part to be modified
     * @return string                   query where part with column aggregation inheritance added
     */
lsmith's avatar
lsmith committed
785 786
    final public function applyInheritance($where)
    {
lsmith's avatar
lsmith committed
787
        if ( ! empty($this->options['inheritanceMap'])) {
doctrine's avatar
doctrine committed
788
            $a = array();
lsmith's avatar
lsmith committed
789
            foreach ($this->options['inheritanceMap'] as $field => $value) {
zYne's avatar
zYne committed
790
                $a[] = $field . ' = ?';
doctrine's avatar
doctrine committed
791
            }
zYne's avatar
zYne committed
792 793
            $i = implode(' AND ', $a);
            $where .= ' AND ' . $i;
doctrine's avatar
doctrine committed
794 795 796 797 798 799 800 801 802
        }
        return $where;
    }
    /**
     * findAll
     * returns a collection of records
     *
     * @return Doctrine_Collection
     */
lsmith's avatar
lsmith committed
803 804
    public function findAll()
    {
zYne's avatar
zYne committed
805
        $graph = new Doctrine_Query($this->conn);
zYne's avatar
zYne committed
806
        $users = $graph->query("FROM ".$this->options['name']);
doctrine's avatar
doctrine committed
807 808 809
        return $users;
    }
    /**
810 811
     * findByDql
     * finds records with given DQL where clause
doctrine's avatar
doctrine committed
812 813
     * returns a collection of records
     *
814
     * @param string $dql               DQL after WHERE clause
doctrine's avatar
doctrine committed
815 816 817
     * @param array $params             query parameters
     * @return Doctrine_Collection
     */
818
    public function findBySql($dql, array $params = array()) {
zYne's avatar
zYne committed
819
        $q = new Doctrine_Query($this->conn);
zYne's avatar
zYne committed
820
        $users = $q->query("FROM ".$this->options['name']." WHERE ".$dql, $params);
doctrine's avatar
doctrine committed
821 822
        return $users;
    }
823

824 825 826
    public function findByDql($dql, array $params = array()) {
        return $this->findBySql($dql, $params);
    }
doctrine's avatar
doctrine committed
827 828 829 830 831 832
    /**
     * clear
     * clears the first level cache (identityMap)
     *
     * @return void
     */
lsmith's avatar
lsmith committed
833 834
    public function clear()
    {
doctrine's avatar
doctrine committed
835 836 837 838 839 840 841 842 843
        $this->identityMap = array();
    }
    /**
     * getRecord
     * first checks if record exists in identityMap, if not
     * returns a new record
     *
     * @return Doctrine_Record
     */
lsmith's avatar
lsmith committed
844 845
    public function getRecord()
    {
zYne's avatar
zYne committed
846 847 848 849 850 851 852
    	if ( ! empty($this->data)) {
            $this->data = array_change_key_case($this->data, CASE_LOWER);
    
            $key = $this->getIdentifier();
    
            if ( ! is_array($key)) {
                $key = array($key);
lsmith's avatar
lsmith committed
853
            }
zYne's avatar
zYne committed
854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872
    
            foreach ($key as $k) {
                if ( ! isset($this->data[$k])) {
                    throw new Doctrine_Table_Exception("Primary key value for $k wasn't found");
                }
                $id[] = $this->data[$k];
            }
    
            $id = implode(' ', $id);
    
            if (isset($this->identityMap[$id])) {
                $record = $this->identityMap[$id];
                $record->hydrate($this->data);
            } else {
                $recordName = $this->getClassnameToReturn();
                $record = new $recordName($this);
                $this->identityMap[$id] = $record;
            }
            $this->data = array();
lsmith's avatar
lsmith committed
873
        } else {
874
            $recordName = $this->getClassnameToReturn();
zYne's avatar
zYne committed
875
            $record = new $recordName($this, true);
doctrine's avatar
doctrine committed
876
        }
zYne's avatar
zYne committed
877

doctrine's avatar
doctrine committed
878 879 880

        return $record;
    }
881

882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897
    /**
     * Get the classname to return. Most often this is just the options['name']
     *
     * Check the subclasses option and the inheritanceMap for each subclass to see 
     * if all the maps in a subclass is met. If this is the case return that 
     * subclass name. If no subclasses match or if there are no subclasses defined 
     * return the name of the class for this tables record.
     *
     * @todo this function could use reflection to check the first time it runs 
     * if the subclassing option is not set. 
     *
     * @return string The name of the class to create
     *
     */ 
    public function getClassnameToReturn()
    {
898
        if (!isset($this->options['subclasses'])) {
899 900
            return $this->options['name'];
        }
901
        foreach ($this->options['subclasses'] as $subclass) {
902
            $table = $this->conn->getTable($subclass);
903
            $inheritanceMap = $table->getOption('inheritanceMap');
904 905 906 907 908 909 910
            $nomatch = false;
            foreach ($inheritanceMap as $key => $value) {
                if (!isset($this->data[$key]) || $this->data[$key] != $value) {
                    $nomatch = true;
                    break;
                }
            }
zYne's avatar
zYne committed
911
            if ( ! $nomatch) {
912 913 914 915 916
                return $table->getComponentName();
            }
        }
        return $this->options['name'];
    }
917

doctrine's avatar
doctrine committed
918 919 920 921
    /**
     * @param $id                       database row id
     * @throws Doctrine_Find_Exception
     */
lsmith's avatar
lsmith committed
922 923
    final public function getProxy($id = null)
    {
lsmith's avatar
lsmith committed
924
        if ($id !== null) {
zYne's avatar
zYne committed
925
            $query = 'SELECT ' . implode(', ',$this->primaryKeys) 
926 927
                . ' FROM ' . $this->getTableName() 
                . ' WHERE ' . implode(' = ? && ',$this->primaryKeys).' = ?';
doctrine's avatar
doctrine committed
928
            $query = $this->applyInheritance($query);
929

zYne's avatar
zYne committed
930
            $params = array_merge(array($id), array_values($this->options['inheritanceMap']));
doctrine's avatar
doctrine committed
931

zYne's avatar
zYne committed
932
            $this->data = $this->conn->execute($query,$params)->fetch(PDO::FETCH_ASSOC);
doctrine's avatar
doctrine committed
933

lsmith's avatar
lsmith committed
934
            if ($this->data === false)
935
                return false;
doctrine's avatar
doctrine committed
936 937 938
        }
        return $this->getRecord();
    }
939 940
    /**
     * count
941
     *
942 943
     * @return integer
     */
lsmith's avatar
lsmith committed
944 945
    public function count()
    {
zYne's avatar
zYne committed
946
        $a = $this->conn->getDBH()->query("SELECT COUNT(1) FROM ".$this->options['tableName'])->fetch(PDO::FETCH_NUM);
947 948
        return current($a);
    }
doctrine's avatar
doctrine committed
949 950 951
    /**
     * @return Doctrine_Query                           a Doctrine_Query object
     */
lsmith's avatar
lsmith committed
952 953
    public function getQueryObject()
    {
zYne's avatar
zYne committed
954
        $graph = new Doctrine_Query($this->getConnection());
doctrine's avatar
doctrine committed
955 956 957 958 959 960 961 962 963 964 965 966
        $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);
zYne's avatar
zYne committed
967
        $query = $this->conn->modifyLimitQuery($query,$limit,$offset);
lsmith's avatar
lsmith committed
968
        if ( ! empty($array)) {
zYne's avatar
zYne committed
969
            $stmt = $this->conn->getDBH()->prepare($query);
doctrine's avatar
doctrine committed
970 971
            $stmt->execute($array);
        } else {
zYne's avatar
zYne committed
972
            $stmt = $this->conn->getDBH()->query($query);
doctrine's avatar
doctrine committed
973 974 975 976
        }
        $data = $stmt->fetchAll(PDO::FETCH_ASSOC);
        $stmt->closeCursor();

lsmith's avatar
lsmith committed
977
        foreach ($data as $row) {
doctrine's avatar
doctrine committed
978 979 980 981 982 983
            $this->data = $row;
            $record = $this->getRecord();
            $coll->add($record);
        }
        return $coll;
    }
doctrine's avatar
doctrine committed
984 985 986 987
    /**
     * @param string $field
     * @return array
     */
lsmith's avatar
lsmith committed
988 989
    final public function getEnumValues($field)
    {
zYne's avatar
zYne committed
990 991
        if (isset($this->columns[$field][2]['values'])) {
            return $this->columns[$field][2]['values'];
lsmith's avatar
lsmith committed
992
        } else {
doctrine's avatar
doctrine committed
993
            return array();
lsmith's avatar
lsmith committed
994
        }
doctrine's avatar
doctrine committed
995
    }
doctrine's avatar
doctrine committed
996 997
    /**
     * enumValue
998 999 1000 1001
     *
     * @param string $field
     * @param integer $index
     * @return mixed
doctrine's avatar
doctrine committed
1002
     */
zYne's avatar
zYne committed
1003
    public function enumValue($field, $index)
lsmith's avatar
lsmith committed
1004
    {
1005
        if ($index instanceof Doctrine_Null)
1006
            return $index;
1007

zYne's avatar
zYne committed
1008
        return isset($this->columns[$field][2]['values'][$index]) ? $this->columns[$field][2]['values'][$index] : $index;
zYne's avatar
zYne committed
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018
    }
    /**
     * enumIndex
     *
     * @param string $field
     * @param mixed $value
     * @return mixed
     */
    public function enumIndex($field, $value)
    {
pookey's avatar
pookey committed
1019
        $values = $this->getEnumValues($field);
zYne's avatar
zYne committed
1020 1021

        return array_search($value, $values);
doctrine's avatar
doctrine committed
1022
    }
1023 1024 1025 1026 1027
    /**
     * invokeSet
     *
     * @param mixed $value
     */
lsmith's avatar
lsmith committed
1028 1029
    public function invokeSet(Doctrine_Record $record, $name, $value)
    {
lsmith's avatar
lsmith committed
1030
        if ( ! ($this->getAttribute(Doctrine::ATTR_ACCESSORS) & Doctrine::ACCESSOR_SET)) {
zYne's avatar
zYne committed
1031
            return $value;
lsmith's avatar
lsmith committed
1032
        }
zYne's avatar
zYne committed
1033 1034
        $prefix = $this->getAttribute(Doctrine::ATTR_ACCESSOR_PREFIX_SET);
        if (!$prefix)
1035
            $prefix = 'set';
1036

1037
        $method = $prefix . $name;
1038

lsmith's avatar
lsmith committed
1039
        if (method_exists($record, $method)) {
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
            return $record->$method($value);
        }

        return $value;
    }
    /**
     * invokeGet
     *
     * @param mixed $value
     */
lsmith's avatar
lsmith committed
1050 1051
    public function invokeGet(Doctrine_Record $record, $name, $value)
    {
lsmith's avatar
lsmith committed
1052
        if ( ! ($this->getAttribute(Doctrine::ATTR_ACCESSORS) & Doctrine::ACCESSOR_GET)) {
1053
            return $value;
lsmith's avatar
lsmith committed
1054
        }
zYne's avatar
zYne committed
1055 1056
        $prefix = $this->getAttribute(Doctrine::ATTR_ACCESSOR_PREFIX_GET);
        if (!$prefix)
1057
            $prefix = 'get';
zYne's avatar
zYne committed
1058

1059
        $method = $prefix . $name;
1060

lsmith's avatar
lsmith committed
1061
        if (method_exists($record, $method)) {
1062 1063 1064 1065 1066
            return $record->$method($value);
        }

        return $value;
    }
zYne's avatar
zYne committed
1067

doctrine's avatar
doctrine committed
1068
    /**
zYne's avatar
zYne committed
1069
     * getDefinitionOf
1070
     *
zYne's avatar
zYne committed
1071
     * @return string       ValueWrapper class name on success, false on failure
1072
     */
zYne's avatar
zYne committed
1073
    public function getValueWrapperOf($column)
lsmith's avatar
lsmith committed
1074
    {
zYne's avatar
zYne committed
1075 1076 1077 1078
        if (isset($this->columns[$column][2]['wrapper'])) {
            return $this->columns[$column][2]['wrapper'];
        }
        return false;
1079 1080
    }
    /**
zYne's avatar
zYne committed
1081
     * getColumnCount
1082
     *
zYne's avatar
zYne committed
1083
     * @return integer      the number of columns in this table
doctrine's avatar
doctrine committed
1084
     */
zYne's avatar
zYne committed
1085
    final public function getColumnCount()
lsmith's avatar
lsmith committed
1086
    {
zYne's avatar
zYne committed
1087
        return $this->columnCount;
doctrine's avatar
doctrine committed
1088
    }
zYne's avatar
zYne committed
1089

doctrine's avatar
doctrine committed
1090 1091 1092 1093 1094
    /**
     * returns all columns and their definitions
     *
     * @return array
     */
zYne's avatar
zYne committed
1095
    final public function getColumns()
lsmith's avatar
lsmith committed
1096
    {
doctrine's avatar
doctrine committed
1097 1098 1099 1100 1101 1102 1103
        return $this->columns;
    }
    /**
     * returns an array containing all the column names
     *
     * @return array
     */
lsmith's avatar
lsmith committed
1104 1105
    public function getColumnNames()
    {
doctrine's avatar
doctrine committed
1106 1107
        return array_keys($this->columns);
    }
zYne's avatar
zYne committed
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
    /**
     * getDefinitionOf
     *
     * @return mixed        array on success, false on failure
     */
    public function getDefinitionOf($column)
    {
        if (isset($this->columns[$column])) {
            return $this->columns[$column];
        }
        return false;
    }
    /**
     * getTypeOf
     *
     * @return mixed        string on success, false on failure
     */
    public function getTypeOf($column)
    {
        if (isset($this->columns[$column])) {
            return $this->columns[$column][0];
        }
        return false;
    }
doctrine's avatar
doctrine committed
1132 1133 1134 1135 1136 1137 1138 1139
    /**
     * setData
     * doctrine uses this function internally
     * users are strongly discouraged to use this function
     *
     * @param array $data               internal data
     * @return void
     */
lsmith's avatar
lsmith committed
1140 1141
    public function setData(array $data)
    {
doctrine's avatar
doctrine committed
1142 1143 1144 1145 1146 1147 1148
        $this->data = $data;
    }
    /**
     * returns the maximum primary key value
     *
     * @return integer
     */
lsmith's avatar
lsmith committed
1149 1150
    final public function getMaxIdentifier()
    {
doctrine's avatar
doctrine committed
1151
        $sql  = "SELECT MAX(".$this->getIdentifier().") FROM ".$this->getTableName();
zYne's avatar
zYne committed
1152
        $stmt = $this->conn->getDBH()->query($sql);
doctrine's avatar
doctrine committed
1153 1154 1155 1156 1157 1158 1159 1160
        $data = $stmt->fetch(PDO::FETCH_NUM);
        return isset($data[0])?$data[0]:1;
    }
    /**
     * returns simple cached query
     *
     * @return string
     */
lsmith's avatar
lsmith committed
1161 1162
    final public function getQuery()
    {
doctrine's avatar
doctrine committed
1163 1164 1165
        return $this->query;
    }
    /**
1166
     * returns internal data, used by Doctrine_Record instances
doctrine's avatar
doctrine committed
1167 1168 1169 1170
     * when retrieving data from database
     *
     * @return array
     */
lsmith's avatar
lsmith committed
1171 1172
    final public function getData()
    {
doctrine's avatar
doctrine committed
1173 1174
        return $this->data;
    }
zYne's avatar
zYne committed
1175 1176 1177 1178 1179 1180 1181 1182
    /**
     * getter for associated tree
     *
     * @return mixed  if tree return instance of Doctrine_Tree, otherwise returns false
     */    
    public function getTree() {
        if (isset($this->options['treeImpl'])) {
            if ( ! $this->tree) {
1183
                $options = isset($this->options['treeOptions']) ? $this->options['treeOptions'] : array();
zYne's avatar
zYne committed
1184
                $this->tree = Doctrine_Tree::factory($this, 
1185 1186 1187
                    $this->options['treeImpl'], 
                    $options
                );
zYne's avatar
zYne committed
1188 1189 1190 1191 1192
            }
            return $this->tree;
        }
        return false;
    }
zYne's avatar
zYne committed
1193 1194 1195 1196 1197 1198 1199 1200
    public function getComponentName() 
    {
        return $this->options['name'];
    }
    public function getTableName()
    {
        return $this->options['tableName'];
    }
zYne's avatar
zYne committed
1201
    public function setTableName($tableName)
zYne's avatar
zYne committed
1202
    {
zYne's avatar
zYne committed
1203
        $this->options['tableName'] = $tableName;	
zYne's avatar
zYne committed
1204
    }
zYne's avatar
zYne committed
1205 1206 1207
    /**
     * determine if table acts as tree
     *
1208
     * @return mixed  if tree return true, otherwise returns false
zYne's avatar
zYne committed
1209 1210 1211 1212
     */    
    public function isTree() {
        return ( ! is_null($this->options['treeImpl'])) ? true : false;
    }
doctrine's avatar
doctrine committed
1213 1214 1215 1216 1217
    /**
     * returns a string representation of this object
     *
     * @return string
     */
lsmith's avatar
lsmith committed
1218 1219
    public function __toString()
    {
doctrine's avatar
doctrine committed
1220 1221 1222
        return Doctrine_Lib::getTableAsString($this);
    }
}