Table.php 46.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 49 50 51 52
    /**
     * @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;
    /**
53 54
     * @see Doctrine_Identifier constants
     * @var integer $identifierType                     the type of identifier this table uses
doctrine's avatar
doctrine committed
55 56 57 58 59 60 61
     */
    private $identifierType;
    /**
     * @var string $query                               cached simple query
     */
    private $query;
    /**
zYne's avatar
zYne committed
62
     * @var Doctrine_Connection $conn                   Doctrine_Connection object that created this table
doctrine's avatar
doctrine committed
63
     */
zYne's avatar
zYne committed
64
    private $conn;
doctrine's avatar
doctrine committed
65
    /**
zYne's avatar
zYne committed
66
     * @var string $name
doctrine's avatar
doctrine committed
67 68 69 70 71 72
     */
    private $name;
    /**
     * @var array $identityMap                          first level cache
     */
    private $identityMap        = array();
73
    /**
74
     * @var Doctrine_Table_Repository $repository       record repository
75
     */
doctrine's avatar
doctrine committed
76 77
    private $repository;
    /**
zYne's avatar
zYne committed
78 79
     * @var array $columns                  an array of column definitions,
     *                                      keys as column names and values as column definitions
lsmith's avatar
lsmith committed
80
     *
zYne's avatar
zYne committed
81
     *                                      the value array has three values:
lsmith's avatar
lsmith committed
82
     *
zYne's avatar
zYne committed
83 84 85 86 87 88
     *                                      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(
89 90
     *                                             'name' => array('string',  20, array('notnull' => true, 'default' => 'someone')),
     *                                             'age'  => array('integer', 11, array('notnull' => true))
zYne's avatar
zYne committed
91
     *                                              )
doctrine's avatar
doctrine committed
92
     */
zYne's avatar
zYne committed
93
    protected $columns          = array();
doctrine's avatar
doctrine committed
94
    /**
zYne's avatar
zYne committed
95 96 97 98 99 100
     * @var array $columnAliases            an array of column aliases
     *                                      keys as column aliases and values as column names
     */
    protected $columnAliases    = array();
    /**
     * @var array $bound                    bound relations
doctrine's avatar
doctrine committed
101 102 103
     */
    private $bound              = array();
    /**
zYne's avatar
zYne committed
104
     * @var array $boundAliases             bound relation aliases
doctrine's avatar
doctrine committed
105 106 107
     */
    private $boundAliases       = array();
    /**
zYne's avatar
zYne committed
108 109
     * @var integer $columnCount            cached column count, Doctrine_Record uses this column count in when
     *                                      determining its state
doctrine's avatar
doctrine committed
110 111
     */
    private $columnCount;
112
    /**
zYne's avatar
zYne committed
113
     * @var boolean $hasDefaultValues       whether or not this table has default values
114 115
     */
    private $hasDefaultValues;
zYne's avatar
zYne committed
116
    /**
117
     * @var array $options                  an array containing all options
zYne's avatar
zYne committed
118
     *
119
     *      -- name                         name of the component, for example component name of the GroupTable is 'Group'
zYne's avatar
zYne committed
120
     *
zYne's avatar
zYne committed
121 122
     *      -- parents                      the parent classes of this component
     *
123 124 125 126
     *      -- 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)
     *
127 128
     *      -- 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
129
     *
130 131 132
     *      -- 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
133
     *
134
     *      -- enumMap                      enum value arrays
zYne's avatar
zYne committed
135
     *
136 137
     *      -- 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
138
     *
zYne's avatar
zYne committed
139
     *      -- type                         table type (mysql example: INNODB)
zYne's avatar
zYne committed
140 141 142
     *
     *      -- charset                      character set
     *
143 144
     *      -- foreignKeys                  the foreign keys of this table
     *
zYne's avatar
zYne committed
145
     *      -- collation
zYne's avatar
zYne committed
146
     *
zYne's avatar
zYne committed
147
     *      -- indexes                      the index definitions of this table
zYne's avatar
zYne committed
148 149 150 151
     *
     *      -- treeImpl                     the tree implementation of this table (if any)
     *
     *      -- treeOptions                  the tree options
zYne's avatar
zYne committed
152 153 154 155 156 157
     */
    protected $options          = array('name'           => null,
                                        'tableName'      => null,
                                        'sequenceName'   => null,
                                        'inheritanceMap' => array(),
                                        'enumMap'        => array(),
zYne's avatar
zYne committed
158 159
                                        'engine'         => null,
                                        'charset'        => null,
zYne's avatar
zYne committed
160
                                        'collation'      => null,
zYne's avatar
zYne committed
161 162
                                        'treeImpl'       => null,
                                        'treeOptions'    => null,
zYne's avatar
zYne committed
163
                                        'indexes'        => array(),
zYne's avatar
zYne committed
164
                                        );
zYne's avatar
zYne committed
165 166 167 168
    /**
     * @var Doctrine_Tree $tree             tree object associated with this table
     */
    protected $tree;
doctrine's avatar
doctrine committed
169 170
    /**
     * the constructor
zYne's avatar
zYne committed
171 172
     * @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
173 174
     * @return void
     */
zYne's avatar
zYne committed
175
    public function __construct($name, Doctrine_Connection $conn, $allowExport)
lsmith's avatar
lsmith committed
176
    {
zYne's avatar
zYne committed
177
        $this->conn = $conn;
doctrine's avatar
doctrine committed
178

zYne's avatar
zYne committed
179
        $this->setParent($this->conn);
doctrine's avatar
doctrine committed
180

zYne's avatar
zYne committed
181
        $this->options['name'] = $name;
doctrine's avatar
doctrine committed
182

lsmith's avatar
lsmith committed
183
        if ( ! class_exists($name) || empty($name)) {
doctrine's avatar
doctrine committed
184
            throw new Doctrine_Exception("Couldn't find class $name");
lsmith's avatar
lsmith committed
185
        }
doctrine's avatar
doctrine committed
186 187 188 189 190 191 192 193 194
        $record = new $name($this);

        $names = array();

        $class = $name;

        // get parent classes

        do {
lsmith's avatar
lsmith committed
195
            if ($class == "Doctrine_Record")
zYne's avatar
zYne committed
196
                break;
doctrine's avatar
doctrine committed
197

lsmith's avatar
lsmith committed
198
            $name  = $class;
doctrine's avatar
doctrine committed
199
            $names[] = $name;
lsmith's avatar
lsmith committed
200
        } while ($class = get_parent_class($class));
doctrine's avatar
doctrine committed
201 202 203 204 205

        // reverse names
        $names = array_reverse($names);

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

209 210 211 212
            // set the table definition for the given tree implementation
            if($this->isTree())
                $this->getTree()->setTableDefinition();

doctrine's avatar
doctrine committed
213 214
            $this->columnCount = count($this->columns);

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

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

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

236 237 238 239 240 241 242 243 244
                        $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
245

246 247
                        } else {
                            foreach ($this->primaryKeys as $pk) {
zYne's avatar
zYne committed
248
                                $e = $this->columns[$pk][2];
lsmith's avatar
lsmith committed
249

250
                                $found = false;
lsmith's avatar
lsmith committed
251

252 253 254
                                foreach ($e as $option => $value) {
                                    if ($found)
                                        break;
lsmith's avatar
lsmith committed
255

zYne's avatar
zYne committed
256
                                    $e2 = explode(':', $option);
lsmith's avatar
lsmith committed
257

258
                                    switch (strtolower($e2[0])) {
zYne's avatar
zYne committed
259 260
                                        case 'autoincrement':
                                        case 'autoinc':
261 262 263
                                            $this->identifierType = Doctrine_Identifier::AUTO_INCREMENT;
                                            $found = true;
                                            break;
zYne's avatar
zYne committed
264 265
                                        case 'seq':
                                        case 'sequence':
266 267
                                            $this->identifierType = Doctrine_Identifier::SEQUENCE;
                                            $found = true;
zYne's avatar
zYne committed
268 269 270 271 272 273
                                            
                                            if($value) {
                                                $this->options['sequenceName'] = $value;
                                            } else {
                                                $this->options['sequenceName'] = $this->conn->getSequenceName($this->options['tableName']);
                                            }
274
                                            break;
zYne's avatar
zYne committed
275
                                    }
276 277 278 279 280
                                }
                                if ( ! isset($this->identifierType)) {
                                    $this->identifierType = Doctrine_Identifier::NORMAL;
                                }
                                $this->identifier = $pk;
doctrine's avatar
doctrine committed
281 282
                            }
                        }
lsmith's avatar
lsmith committed
283
                };
zYne's avatar
zYne committed
284 285 286 287 288 289 290 291
                /**
                            if ( ! isset($definition['values'])) {
                                throw new Doctrine_Table_Exception('No values set for enum column ' . $name);
                            }

                            if ( ! is_array($definition['values'])) {
                                throw new Doctrine_Table_Exception('Enum column values should be specified as an array.');
                            }
lsmith's avatar
lsmith committed
292

zYne's avatar
zYne committed
293
                */
lsmith's avatar
lsmith committed
294
                if ($this->getAttribute(Doctrine::ATTR_CREATE_TABLES)) {
295
                    $this->export();
doctrine's avatar
doctrine committed
296 297 298 299
                }

            }
        } else {
zYne's avatar
zYne committed
300
            throw new Doctrine_Table_Exception("Class '$name' has no table definition.");
doctrine's avatar
doctrine committed
301
        }
302

doctrine's avatar
doctrine committed
303 304
        $record->setUp();

305
        // if tree, set up tree
zYne's avatar
zYne committed
306
        if ($this->isTree()) {
307
            $this->getTree()->setUp();
zYne's avatar
zYne committed
308
        }
309

doctrine's avatar
doctrine committed
310 311
        // save parents
        array_pop($names);
zYne's avatar
zYne committed
312
        $this->options['parents']   = $names;
doctrine's avatar
doctrine committed
313

zYne's avatar
zYne committed
314
        $this->query     = 'SELECT ' . implode(', ', array_keys($this->columns)) . ' FROM ' . $this->getTableName();
doctrine's avatar
doctrine committed
315

zYne's avatar
zYne committed
316

317
        $this->repository = new Doctrine_Table_Repository($this);
doctrine's avatar
doctrine committed
318
    }
319 320 321 322 323 324 325 326 327
    /**
     * 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
328 329
    public function export() 
    {
zYne's avatar
zYne committed
330 331 332
        if ( ! Doctrine::isValidClassname($this->options['declaringClass']->getName())) {
            throw new Doctrine_Table_Exception('Class name not valid.');
        }
333

zYne's avatar
zYne committed
334 335 336 337 338
        try {
            $columns = array();
            $primary = array();

            foreach ($this->columns as $name => $column) {
zYne's avatar
zYne committed
339 340 341
                $definition = $column[2];
                $definition['type'] = $column[0];
                $definition['length'] = $column[1];
zYne's avatar
zYne committed
342 343 344 345 346 347 348 349 350 351 352 353

                switch ($definition['type']) {
                    case 'enum':
                        if (isset($definition['default'])) {
                            $definition['default'] = $this->enumIndex($name, $definition['default']);
                        }
                        break;
                    case 'boolean':
                        if (isset($definition['default'])) {
                            $definition['default'] = (int) $definition['default'];
                        }
                        break;
354
                }
zYne's avatar
zYne committed
355 356 357 358 359 360
                $columns[$name] = $definition;
                
                if(isset($definition['primary']) && $definition['primary']) {
                    $primary[] = $name;
                }
            }
zYne's avatar
zYne committed
361 362 363 364 365 366 367 368
            /**
            foreach ($this->getRelations() as $name => $relation) {
                $fk = $relation->toArray();
                $fk['foreignTable'] = $relation->getTable()->getTableName();

                $options['foreignKeys'][] = $fk;
            }  */

zYne's avatar
zYne committed
369 370 371 372 373 374 375
            $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;
376 377 378
            }
        }
    }
zYne's avatar
zYne committed
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
    /**
     * 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()
    {
    	try {
        	$this->conn->beginTransaction();

            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
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422
    /** 
     * __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]);
    }
423 424 425 426 427 428 429 430 431 432 433
    /**
     * addForeignKey
     *
     * adds a foreignKey to this table
     *
     * @return void
     */
    public function addForeignKey(array $definition)
    {
        $this->options['foreignKeys'][] = $definition;
    }
zYne's avatar
zYne committed
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
    /**
     * addIndex
     * 
     * adds an index to this table
     *
     * @return void
     */
    public function addIndex($index, array $definition)
    {
    	$index = $this->conn->getIndexName($index);
        $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];
        }
        
        return false;
    }
zYne's avatar
zYne committed
459 460 461 462
    /**
     * 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
463
     *
zYne's avatar
zYne committed
464 465
     * @return Doctrine_Query
     */
lsmith's avatar
lsmith committed
466 467
    public function createQuery()
    {
zYne's avatar
zYne committed
468 469
        return Doctrine_Query::create()->from($this->getComponentName());
    }
doctrine's avatar
doctrine committed
470
    /**
471 472 473
     * getRepository
     *
     * @return Doctrine_Table_Repository
doctrine's avatar
doctrine committed
474
     */
lsmith's avatar
lsmith committed
475 476
    public function getRepository()
    {
doctrine's avatar
doctrine committed
477 478
        return $this->repository;
    }
lsmith's avatar
lsmith committed
479

lsmith's avatar
lsmith committed
480 481
    public function setOption($name, $value)
    {
lsmith's avatar
lsmith committed
482
        switch ($name) {
483 484 485 486 487
            case 'name':
            case 'tableName':
                break;
            case 'enumMap':
            case 'inheritanceMap':
zYne's avatar
zYne committed
488
            case 'index':
zYne's avatar
zYne committed
489
            case 'treeOptions':
490
                if ( ! is_array($value)) {
zYne's avatar
zYne committed
491
                    throw new Doctrine_Table_Exception($name . ' should be an array.');
492 493
                }
                break;
zYne's avatar
zYne committed
494 495 496
        }
        $this->options[$name] = $value;
    }
lsmith's avatar
lsmith committed
497 498
    public function getOption($name)
    {
lsmith's avatar
lsmith committed
499
        if (isset($this->options[$name])) {
500
            return $this->options[$name];
lsmith's avatar
lsmith committed
501
        }
502 503
        return null;
    }
zYne's avatar
zYne committed
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521
    /**
     * 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];
        }
        
        return $alias;
    }
doctrine's avatar
doctrine committed
522 523
    /**
     * setColumn
zYne's avatar
zYne committed
524
     *
doctrine's avatar
doctrine committed
525 526 527 528
     * @param string $name
     * @param string $type
     * @param integer $length
     * @param mixed $options
zYne's avatar
zYne committed
529
     * @throws Doctrine_Table_Exception     if trying use wrongly typed parameter
doctrine's avatar
doctrine committed
530 531
     * @return void
     */
zYne's avatar
zYne committed
532 533
    public function setColumn($name, $type, $length = null, $options = array())
    {
lsmith's avatar
lsmith committed
534
        if (is_string($options)) {
535
            $options = explode('|', $options);
lsmith's avatar
lsmith committed
536
        }
zYne's avatar
zYne committed
537

lsmith's avatar
lsmith committed
538 539 540
        foreach ($options as $k => $option) {
            if (is_numeric($k)) {
                if ( ! empty($option)) {
541
                    $options[$option] = true;
lsmith's avatar
lsmith committed
542
                }
543 544 545
                unset($options[$k]);
            }
        }
lsmith's avatar
lsmith committed
546

zYne's avatar
zYne committed
547 548 549 550 551 552 553 554 555 556
        $name  = strtolower($name);
        $parts = explode(' as ', $name);
        
        if (count($parts) > 1) {
            $this->columnAliases[$parts[1]] = $parts[0];
            $name = $parts[0];
        }


        if ($length == null) {
zYne's avatar
zYne committed
557
            $length = 2147483647;
zYne's avatar
zYne committed
558 559 560
        }

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

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

lsmith's avatar
lsmith committed
566
        if (isset($options['primary'])) {
doctrine's avatar
doctrine committed
567 568
            $this->primaryKeys[] = $name;
        }
lsmith's avatar
lsmith committed
569
        if (isset($options['default'])) {
570 571 572 573 574 575 576 577 578
            $this->hasDefaultValues = true;
        }
    }
    /**
     * hasDefaultValues
     * returns true if this table has default values, otherwise false
     *
     * @return boolean
     */
lsmith's avatar
lsmith committed
579 580
    public function hasDefaultValues()
    {
581
        return $this->hasDefaultValues;
doctrine's avatar
doctrine committed
582
    }
zYne's avatar
zYne committed
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
    /**
     * 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
602 603 604
    /**
     * @return mixed
     */
lsmith's avatar
lsmith committed
605 606
    final public function getIdentifier()
    {
doctrine's avatar
doctrine committed
607 608 609 610 611
        return $this->identifier;
    }
    /**
     * @return integer
     */
lsmith's avatar
lsmith committed
612 613
    final public function getIdentifierType()
    {
doctrine's avatar
doctrine committed
614 615 616 617 618 619
        return $this->identifierType;
    }
    /**
     * hasColumn
     * @return boolean
     */
lsmith's avatar
lsmith committed
620 621
    final public function hasColumn($name)
    {
doctrine's avatar
doctrine committed
622 623 624 625 626 627
        return isset($this->columns[$name]);
    }
    /**
     * @param mixed $key
     * @return void
     */
lsmith's avatar
lsmith committed
628 629
    final public function setPrimaryKey($key)
    {
lsmith's avatar
lsmith committed
630
        switch (gettype($key)) {
631 632 633 634 635 636
            case "array":
                $this->primaryKeys = array_values($key);
                break;
            case "string":
                $this->primaryKeys[] = $key;
                break;
lsmith's avatar
lsmith committed
637
        };
doctrine's avatar
doctrine committed
638 639 640 641 642
    }
    /**
     * returns all primary keys
     * @return array
     */
lsmith's avatar
lsmith committed
643 644
    final public function getPrimaryKeys()
    {
doctrine's avatar
doctrine committed
645 646 647 648 649
        return $this->primaryKeys;
    }
    /**
     * @return boolean
     */
lsmith's avatar
lsmith committed
650 651
    final public function hasPrimaryKey($key)
    {
doctrine's avatar
doctrine committed
652 653 654 655 656 657 658
        return in_array($key,$this->primaryKeys);
    }
    /**
     * returns all bound relations
     *
     * @return array
     */
lsmith's avatar
lsmith committed
659 660
    public function getBounds()
    {
doctrine's avatar
doctrine committed
661 662 663 664 665 666 667 668
        return $this->bound;
    }
    /**
     * returns a bound relation array
     *
     * @param string $name
     * @return array
     */
lsmith's avatar
lsmith committed
669 670
    public function getBound($name)
    {
lsmith's avatar
lsmith committed
671
        if ( ! isset($this->bound[$name])) {
672
            throw new Doctrine_Table_Exception('Unknown bound '.$name);
lsmith's avatar
lsmith committed
673
        }
doctrine's avatar
doctrine committed
674 675 676 677 678 679 680 681
        return $this->bound[$name];
    }
    /**
     * returns a bound relation array
     *
     * @param string $name
     * @return array
     */
lsmith's avatar
lsmith committed
682 683
    public function getBoundForName($name, $component)
    {
lsmith's avatar
lsmith committed
684
        foreach ($this->bound as $k => $bound) {
685
            $e = explode('.', $bound['field']);
686

zYne's avatar
zYne committed
687
            if ($bound['class'] == $name && $e[0] == $component) {
doctrine's avatar
doctrine committed
688 689 690
                return $this->bound[$k];
            }
        }
zYne's avatar
zYne committed
691
        throw new Doctrine_Table_Exception('Unknown bound ' . $name);
doctrine's avatar
doctrine committed
692 693 694 695 696 697 698
    }
    /**
     * returns the alias for given component name
     *
     * @param string $name
     * @return string
     */
lsmith's avatar
lsmith committed
699 700
    public function getAlias($name)
    {
lsmith's avatar
lsmith committed
701
        if (isset($this->boundAliases[$name])) {
doctrine's avatar
doctrine committed
702
            return $this->boundAliases[$name];
lsmith's avatar
lsmith committed
703
        }
doctrine's avatar
doctrine committed
704 705 706 707
        return $name;
    }
    /**
     * returns component name for given alias
708
     *
doctrine's avatar
doctrine committed
709 710 711
     * @param string $alias
     * @return string
     */
lsmith's avatar
lsmith committed
712 713
    public function getAliasName($alias)
    {
lsmith's avatar
lsmith committed
714
        if ($name = array_search($alias, $this->boundAliases)) {
doctrine's avatar
doctrine committed
715
            return $name;
lsmith's avatar
lsmith committed
716
        }
zYne's avatar
zYne committed
717
        return $alias;
doctrine's avatar
doctrine committed
718 719 720
    }
    /**
     * unbinds all relations
721
     *
doctrine's avatar
doctrine committed
722 723
     * @return void
     */
lsmith's avatar
lsmith committed
724 725
    public function unbindAll()
    {
doctrine's avatar
doctrine committed
726 727 728 729 730 731 732 733 734 735 736
        $this->bound        = array();
        $this->relations    = array();
        $this->boundAliases = array();
    }
    /**
     * unbinds a relation
     * returns true on success, false on failure
     *
     * @param $name
     * @return boolean
     */
lsmith's avatar
lsmith committed
737 738
    public function unbind($name)
    {
lsmith's avatar
lsmith committed
739
        if ( ! isset($this->bound[$name])) {
doctrine's avatar
doctrine committed
740
            return false;
lsmith's avatar
lsmith committed
741
        }
doctrine's avatar
doctrine committed
742 743
        unset($this->bound[$name]);

lsmith's avatar
lsmith committed
744
        if (isset($this->relations[$name])) {
doctrine's avatar
doctrine committed
745
            unset($this->relations[$name]);
lsmith's avatar
lsmith committed
746 747
        }
        if (isset($this->boundAliases[$name])) {
doctrine's avatar
doctrine committed
748
            unset($this->boundAliases[$name]);
lsmith's avatar
lsmith committed
749
        }
doctrine's avatar
doctrine committed
750 751 752 753 754 755 756 757 758
        return true;
    }
    /**
     * binds a relation
     *
     * @param string $name
     * @param string $field
     * @return void
     */
zYne's avatar
zYne committed
759
    public function bind($name, $field, $type, $options = null)
lsmith's avatar
lsmith committed
760
    {
lsmith's avatar
lsmith committed
761
        if (isset($this->relations[$name])) {
762
            unset($this->relations[$name]);
lsmith's avatar
lsmith committed
763
        }
764 765 766 767

        $lower = strtolower($name);

        if (isset($this->columns[$lower])) {
zYne's avatar
zYne committed
768
            throw new Doctrine_Table_Exception("Couldn't bind relation. Column with name " . $lower . ' already exists!');
769 770
        }

771 772
        $e    = explode(' as ', $name);
        $name = $e[0];
doctrine's avatar
doctrine committed
773

lsmith's avatar
lsmith committed
774
        if (isset($e[1])) {
doctrine's avatar
doctrine committed
775 776
            $alias = $e[1];
            $this->boundAliases[$name] = $alias;
lsmith's avatar
lsmith committed
777
        } else {
doctrine's avatar
doctrine committed
778
            $alias = $name;
lsmith's avatar
lsmith committed
779
        }
doctrine's avatar
doctrine committed
780

781 782
        $this->bound[$alias] = array('field'    => $field,
                                     'type'     => $type,
zYne's avatar
zYne committed
783
                                     'class'    => $name,
784
                                     'alias'    => $alias);
zYne's avatar
zYne committed
785 786 787 788 789 790 791 792 793 794
        if ($options !== null) {
            $opt = array();
            if (is_string($options)) {
                $opt['local'] = $options;
            } else {
                $opt = (array) $options;
            }

            $this->bound[$alias] = array_merge($this->bound[$alias], $opt);
        }
doctrine's avatar
doctrine committed
795 796
    }
    /**
zYne's avatar
zYne committed
797
     * @return Doctrine_Connection
doctrine's avatar
doctrine committed
798
     */
lsmith's avatar
lsmith committed
799 800
    public function getConnection()
    {
zYne's avatar
zYne committed
801
        return $this->conn;
doctrine's avatar
doctrine committed
802
    }
803 804 805 806
    /**
     * hasRelatedComponent
     * @return boolean
     */
lsmith's avatar
lsmith committed
807 808
    final public function hasRelatedComponent($name, $component)
    {
809
         return (strpos($this->bound[$name]['field'], $component . '.') !== false);
810 811 812 813 814
    }
    /**
     * @param string $name              component name of which a foreign key object is bound
     * @return boolean
     */
lsmith's avatar
lsmith committed
815 816
    final public function hasRelation($name)
    {
lsmith's avatar
lsmith committed
817
        if (isset($this->bound[$name])) {
818
            return true;
lsmith's avatar
lsmith committed
819 820 821
        }
        foreach ($this->bound as $k=>$v) {
            if ($this->hasRelatedComponent($k, $name)) {
822
                return true;
lsmith's avatar
lsmith committed
823
            }
824 825 826
        }
        return false;
    }
doctrine's avatar
doctrine committed
827
    /**
828 829
     * getRelation
     *
doctrine's avatar
doctrine committed
830 831 832
     * @param string $name              component name of which a foreign key object is bound
     * @return Doctrine_Relation
     */
833
    public function getRelation($name, $recursive = true)
lsmith's avatar
lsmith committed
834
    {
lsmith's avatar
lsmith committed
835 836 837 838
        if (isset($this->relations[$name])) {
            return $this->relations[$name];
        }
        if (isset($this->bound[$name])) {
doctrine's avatar
doctrine committed
839

840 841 842 843 844
            $definition = $this->bound[$name];

            list($component, $definition['foreign']) = explode('.', $definition['field']);
            unset($definition['field']);

zYne's avatar
zYne committed
845
            $definition['table'] = $this->conn->getTable($definition['class'], false);
doctrine's avatar
doctrine committed
846

847
            if ($component == $this->options['name'] || in_array($component, $this->options['parents'])) {
zYne's avatar
zYne committed
848

doctrine's avatar
doctrine committed
849
                // ONE-TO-ONE
850 851
                if ($definition['type'] == Doctrine_Relation::ONE_COMPOSITE ||
                    $definition['type'] == Doctrine_Relation::ONE_AGGREGATE) {
zYne's avatar
zYne committed
852 853
                    // tree structure parent relation found

854 855 856
                    if ( ! isset($definition['local'])) {
                        $definition['local']   = $definition['foreign'];
                        $definition['foreign'] = $definition['table']->getIdentifier();
lsmith's avatar
lsmith committed
857
                    }
858 859 860

                    $relation = new Doctrine_Relation_LocalKey($definition);

lsmith's avatar
lsmith committed
861
                } else {
zYne's avatar
zYne committed
862 863
                    // tree structure children relation found

864 865
                    if ( ! isset($definition['local'])) {
                        $tmp = $definition['table']->getIdentifier();
zYne's avatar
zYne committed
866 867
                        
                        $definition['local'] = $tmp;
zYne's avatar
zYne committed
868
                    }
zYne's avatar
zYne committed
869 870

                    //$definition['foreign'] = $tmp;  
zYne's avatar
zYne committed
871

872
                    $relation = new Doctrine_Relation_ForeignKey($definition);
lsmith's avatar
lsmith committed
873
                }
zYne's avatar
zYne committed
874

zYne's avatar
zYne committed
875
            } elseif ($component == $definition['class'] ||
876
                     ($component == $definition['alias'])) {     //  && ($name == $this->options['name'] || in_array($name,$this->parents))
zYne's avatar
zYne committed
877

878 879
                if ( ! isset($defintion['local'])) {
                    $definition['local'] = $this->identifier;
lsmith's avatar
lsmith committed
880
                }
doctrine's avatar
doctrine committed
881
                // ONE-TO-MANY or ONE-TO-ONE
882
                $relation = new Doctrine_Relation_ForeignKey($definition);
doctrine's avatar
doctrine committed
883 884 885 886 887

            } else {
                // MANY-TO-MANY
                // only aggregate relations allowed

888
                if ($definition['type'] != Doctrine_Relation::MANY_AGGREGATE) {
889
                    throw new Doctrine_Table_Exception("Only aggregate relations are allowed for many-to-many relations");
zYne's avatar
zYne committed
890
                }
doctrine's avatar
doctrine committed
891

zYne's avatar
zYne committed
892
                $classes = array_merge($this->options['parents'], array($this->options['name']));
doctrine's avatar
doctrine committed
893

lsmith's avatar
lsmith committed
894
                foreach (array_reverse($classes) as $class) {
doctrine's avatar
doctrine committed
895
                    try {
896
                        $bound = $definition['table']->getBoundForName($class, $component);
doctrine's avatar
doctrine committed
897
                        break;
898
                    } catch(Doctrine_Table_Exception $exc) { }
doctrine's avatar
doctrine committed
899
                }
lsmith's avatar
lsmith committed
900
                if ( ! isset($bound)) {
901 902
                    throw new Doctrine_Table_Exception("Couldn't map many-to-many relation for "
                                                      . $this->options['name'] . " and $name. Components use different join tables.");
lsmith's avatar
lsmith committed
903
                }
904 905
                if ( ! isset($definition['local'])) {
                    $definition['local'] = $this->identifier;
lsmith's avatar
lsmith committed
906
                }
907
                $e2     = explode('.', $bound['field']);
908
                $fields = explode('-', $e2[1]);
doctrine's avatar
doctrine committed
909

910
                if ($e2[0] != $component) {
911
                    throw new Doctrine_Table_Exception($e2[0] . ' doesn\'t match ' . $component);
912
                }
zYne's avatar
zYne committed
913
                $associationTable = $this->conn->getTable($e2[0], false);
doctrine's avatar
doctrine committed
914

lsmith's avatar
lsmith committed
915
                if (count($fields) > 1) {
doctrine's avatar
doctrine committed
916
                    // SELF-REFERENCING THROUGH JOIN TABLE
917

918 919 920 921
                    $def['table']   = $associationTable;
                    $def['local']   = $this->identifier;
                    $def['foreign'] = $fields[0];
                    $def['alias']   = $e2[0];
zYne's avatar
zYne committed
922
                    $def['class']   = $e2[0];
923 924 925 926 927 928 929 930
                    $def['type']    = Doctrine_Relation::MANY_COMPOSITE;

                    $this->relations[$e2[0]] = new Doctrine_Relation_ForeignKey($def);

                    $definition['assocTable'] = $associationTable;
                    $definition['local']      = $fields[0];
                    $definition['foreign']    = $fields[1];
                    $relation = new Doctrine_Relation_Association_Self($definition);
doctrine's avatar
doctrine committed
931
                } else {
932 933
                    if($definition['table'] === $this) {

zYne's avatar
zYne committed
934
                    } else {
935 936 937 938 939 940 941 942 943 944
                        // auto initialize a new one-to-one relationships for association table
                        $associationTable->bind($this->getComponentName(),  
                                                $associationTable->getComponentName(). '.' . $e2[1], 
                                                Doctrine_Relation::ONE_AGGREGATE
                                                );

                        $associationTable->bind($definition['table']->getComponentName(),
                                                $associationTable->getComponentName(). '.' . $definition['foreign'],
                                                Doctrine_Relation::ONE_AGGREGATE
                                                );
zYne's avatar
zYne committed
945 946
    
                        // NORMAL MANY-TO-MANY RELATIONSHIP
947 948 949 950 951
                        
                        $def['table']   = $associationTable;
                        $def['foreign'] = $e2[1];
                        $def['local']   = $definition['local'];
                        $def['alias']   = $e2[0];
zYne's avatar
zYne committed
952
                        $def['class']   = $e2[0];
953 954
                        $def['type']    = Doctrine_Relation::MANY_COMPOSITE;
                        $this->relations[$e2[0]] = new Doctrine_Relation_ForeignKey($def);
zYne's avatar
zYne committed
955
    
956 957 958
                        $definition['local']      = $e2[1];
                        $definition['assocTable'] = $associationTable;
                        $relation = new Doctrine_Relation_Association($definition);
zYne's avatar
zYne committed
959
                    }
doctrine's avatar
doctrine committed
960 961
                }
            }
zYne's avatar
zYne committed
962

963 964 965
            $this->relations[$name] = $relation;

            return $this->relations[$name];
doctrine's avatar
doctrine committed
966
        }
zYne's avatar
zYne committed
967

968 969
        // load all relations
        $this->getRelations();
lsmith's avatar
lsmith committed
970 971

        if ($recursive) {
972
            return $this->getRelation($name, false);
973
        } else {
974
            throw new Doctrine_Table_Exception($this->options['name'] . " doesn't have a relation to " . $name);
975
        }
976

doctrine's avatar
doctrine committed
977 978 979 980 981 982
    }
    /**
     * returns an array containing all foreign key objects
     *
     * @return array
     */
lsmith's avatar
lsmith committed
983 984
    final public function getRelations()
    {
doctrine's avatar
doctrine committed
985
        $a = array();
zYne's avatar
zYne committed
986
        foreach ($this->bound as $k => $v) {
987
            $this->getRelation($k);
doctrine's avatar
doctrine committed
988 989 990 991 992 993 994 995 996 997 998 999
        }

        return $this->relations;
    }
    /**
     * 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()) {
1000
        $this->data         = $array;
chtito's avatar
chtito committed
1001
        $record = new $this->options['name']($this, true);
doctrine's avatar
doctrine committed
1002 1003 1004 1005 1006 1007 1008
        $this->data         = array();
        return $record;
    }
    /**
     * finds a record by its identifier
     *
     * @param $id                       database row id
zYne's avatar
zYne committed
1009
     * @return Doctrine_Record|false    a record for given database identifier
doctrine's avatar
doctrine committed
1010
     */
lsmith's avatar
lsmith committed
1011 1012
    public function find($id)
    {
lsmith's avatar
lsmith committed
1013 1014
        if ($id !== null) {
            if ( ! is_array($id)) {
doctrine's avatar
doctrine committed
1015
                $id = array($id);
lsmith's avatar
lsmith committed
1016
            } else {
doctrine's avatar
doctrine committed
1017
                $id = array_values($id);
lsmith's avatar
lsmith committed
1018
            }
doctrine's avatar
doctrine committed
1019

zYne's avatar
zYne committed
1020
            $query  = $this->query . ' WHERE ' . implode(' = ? AND ', $this->primaryKeys) . ' = ?';
doctrine's avatar
doctrine committed
1021
            $query  = $this->applyInheritance($query);
doctrine's avatar
doctrine committed
1022

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

zYne's avatar
zYne committed
1025
            $stmt  = $this->conn->execute($query, $params);
doctrine's avatar
doctrine committed
1026 1027

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

lsmith's avatar
lsmith committed
1029
            if ($this->data === false)
1030
                return false;
lsmith's avatar
lsmith committed
1031

pookey's avatar
pookey committed
1032
            return $this->getRecord();
doctrine's avatar
doctrine committed
1033
        }
pookey's avatar
pookey committed
1034
        return false;
doctrine's avatar
doctrine committed
1035 1036 1037 1038 1039 1040
    }
    /**
     * applyInheritance
     * @param $where                    query where part to be modified
     * @return string                   query where part with column aggregation inheritance added
     */
lsmith's avatar
lsmith committed
1041 1042
    final public function applyInheritance($where)
    {
lsmith's avatar
lsmith committed
1043
        if ( ! empty($this->options['inheritanceMap'])) {
doctrine's avatar
doctrine committed
1044
            $a = array();
lsmith's avatar
lsmith committed
1045
            foreach ($this->options['inheritanceMap'] as $field => $value) {
zYne's avatar
zYne committed
1046
                $a[] = $field . ' = ?';
doctrine's avatar
doctrine committed
1047
            }
zYne's avatar
zYne committed
1048 1049
            $i = implode(' AND ', $a);
            $where .= ' AND ' . $i;
doctrine's avatar
doctrine committed
1050 1051 1052 1053 1054 1055 1056 1057 1058
        }
        return $where;
    }
    /**
     * findAll
     * returns a collection of records
     *
     * @return Doctrine_Collection
     */
lsmith's avatar
lsmith committed
1059 1060
    public function findAll()
    {
zYne's avatar
zYne committed
1061
        $graph = new Doctrine_Query($this->conn);
zYne's avatar
zYne committed
1062
        $users = $graph->query("FROM ".$this->options['name']);
doctrine's avatar
doctrine committed
1063 1064 1065
        return $users;
    }
    /**
1066 1067
     * findByDql
     * finds records with given DQL where clause
doctrine's avatar
doctrine committed
1068 1069
     * returns a collection of records
     *
1070
     * @param string $dql               DQL after WHERE clause
doctrine's avatar
doctrine committed
1071 1072 1073
     * @param array $params             query parameters
     * @return Doctrine_Collection
     */
1074
    public function findBySql($dql, array $params = array()) {
zYne's avatar
zYne committed
1075
        $q = new Doctrine_Query($this->conn);
zYne's avatar
zYne committed
1076
        $users = $q->query("FROM ".$this->options['name']." WHERE ".$dql, $params);
doctrine's avatar
doctrine committed
1077 1078
        return $users;
    }
1079

1080 1081 1082
    public function findByDql($dql, array $params = array()) {
        return $this->findBySql($dql, $params);
    }
doctrine's avatar
doctrine committed
1083 1084 1085 1086 1087 1088
    /**
     * clear
     * clears the first level cache (identityMap)
     *
     * @return void
     */
lsmith's avatar
lsmith committed
1089 1090
    public function clear()
    {
doctrine's avatar
doctrine committed
1091 1092 1093 1094 1095 1096 1097 1098 1099
        $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
1100 1101
    public function getRecord()
    {
zYne's avatar
zYne committed
1102 1103
        $this->data = array_change_key_case($this->data, CASE_LOWER);

doctrine's avatar
doctrine committed
1104 1105
        $key = $this->getIdentifier();

lsmith's avatar
lsmith committed
1106
        if ( ! is_array($key)) {
doctrine's avatar
doctrine committed
1107
            $key = array($key);
lsmith's avatar
lsmith committed
1108 1109 1110
        }
        foreach ($key as $k) {
            if ( ! isset($this->data[$k])) {
1111
                throw new Doctrine_Exception("Primary key value for $k wasn't found");
lsmith's avatar
lsmith committed
1112
            }
doctrine's avatar
doctrine committed
1113 1114
            $id[] = $this->data[$k];
        }
1115

doctrine's avatar
doctrine committed
1116 1117
        $id = implode(' ', $id);

lsmith's avatar
lsmith committed
1118
        if (isset($this->identityMap[$id])) {
doctrine's avatar
doctrine committed
1119
            $record = $this->identityMap[$id];
lsmith's avatar
lsmith committed
1120
        } else {
zYne's avatar
zYne committed
1121
            $record = new $this->options['name']($this);
doctrine's avatar
doctrine committed
1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
            $this->identityMap[$id] = $record;
        }
        $this->data = array();

        return $record;
    }
    /**
     * @param $id                       database row id
     * @throws Doctrine_Find_Exception
     */
lsmith's avatar
lsmith committed
1132 1133
    final public function getProxy($id = null)
    {
lsmith's avatar
lsmith committed
1134
        if ($id !== null) {
zYne's avatar
zYne committed
1135 1136 1137
            $query = 'SELECT ' . implode(', ',$this->primaryKeys) 
                   . ' FROM ' . $this->getTableName() 
                   . ' WHERE ' . implode(' = ? && ',$this->primaryKeys).' = ?';
doctrine's avatar
doctrine committed
1138
            $query = $this->applyInheritance($query);
1139

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

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

lsmith's avatar
lsmith committed
1144
            if ($this->data === false)
1145
                return false;
doctrine's avatar
doctrine committed
1146 1147 1148
        }
        return $this->getRecord();
    }
1149 1150
    /**
     * count
1151
     *
1152 1153
     * @return integer
     */
lsmith's avatar
lsmith committed
1154 1155
    public function count()
    {
zYne's avatar
zYne committed
1156
        $a = $this->conn->getDBH()->query("SELECT COUNT(1) FROM ".$this->options['tableName'])->fetch(PDO::FETCH_NUM);
1157 1158
        return current($a);
    }
doctrine's avatar
doctrine committed
1159 1160 1161
    /**
     * @return Doctrine_Query                           a Doctrine_Query object
     */
lsmith's avatar
lsmith committed
1162 1163
    public function getQueryObject()
    {
zYne's avatar
zYne committed
1164
        $graph = new Doctrine_Query($this->getConnection());
doctrine's avatar
doctrine committed
1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176
        $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
1177
        $query = $this->conn->modifyLimitQuery($query,$limit,$offset);
lsmith's avatar
lsmith committed
1178
        if ( ! empty($array)) {
zYne's avatar
zYne committed
1179
            $stmt = $this->conn->getDBH()->prepare($query);
doctrine's avatar
doctrine committed
1180 1181
            $stmt->execute($array);
        } else {
zYne's avatar
zYne committed
1182
            $stmt = $this->conn->getDBH()->query($query);
doctrine's avatar
doctrine committed
1183 1184 1185 1186
        }
        $data = $stmt->fetchAll(PDO::FETCH_ASSOC);
        $stmt->closeCursor();

lsmith's avatar
lsmith committed
1187
        foreach ($data as $row) {
doctrine's avatar
doctrine committed
1188 1189 1190 1191 1192 1193
            $this->data = $row;
            $record = $this->getRecord();
            $coll->add($record);
        }
        return $coll;
    }
doctrine's avatar
doctrine committed
1194 1195 1196 1197
    /**
     * @param string $field
     * @return array
     */
lsmith's avatar
lsmith committed
1198 1199
    final public function getEnumValues($field)
    {
zYne's avatar
zYne committed
1200 1201
        if (isset($this->columns[$field][2]['values'])) {
            return $this->columns[$field][2]['values'];
lsmith's avatar
lsmith committed
1202
        } else {
doctrine's avatar
doctrine committed
1203
            return array();
lsmith's avatar
lsmith committed
1204
        }
doctrine's avatar
doctrine committed
1205
    }
doctrine's avatar
doctrine committed
1206 1207
    /**
     * enumValue
1208 1209 1210 1211
     *
     * @param string $field
     * @param integer $index
     * @return mixed
doctrine's avatar
doctrine committed
1212
     */
zYne's avatar
zYne committed
1213
    public function enumValue($field, $index)
lsmith's avatar
lsmith committed
1214
    {
1215
        if ($index instanceof Doctrine_Null)
1216
            return $index;
1217

zYne's avatar
zYne committed
1218
        return isset($this->columns[$field][2]['values'][$index]) ? $this->columns[$field][2]['values'][$index] : $index;
zYne's avatar
zYne committed
1219 1220 1221 1222 1223 1224 1225 1226 1227 1228
    }
    /**
     * enumIndex
     *
     * @param string $field
     * @param mixed $value
     * @return mixed
     */
    public function enumIndex($field, $value)
    {
pookey's avatar
pookey committed
1229
        $values = $this->getEnumValues($field);
zYne's avatar
zYne committed
1230 1231

        return array_search($value, $values);
doctrine's avatar
doctrine committed
1232
    }
1233 1234 1235 1236 1237
    /**
     * invokeSet
     *
     * @param mixed $value
     */
lsmith's avatar
lsmith committed
1238 1239
    public function invokeSet(Doctrine_Record $record, $name, $value)
    {
lsmith's avatar
lsmith committed
1240
        if ( ! ($this->getAttribute(Doctrine::ATTR_ACCESSORS) & Doctrine::ACCESSOR_SET)) {
zYne's avatar
zYne committed
1241
            return $value;
lsmith's avatar
lsmith committed
1242
        }
zYne's avatar
zYne committed
1243 1244
        $prefix = $this->getAttribute(Doctrine::ATTR_ACCESSOR_PREFIX_SET);
        if (!$prefix)
1245
            $prefix = 'set';
1246

1247
        $method = $prefix . $name;
1248

lsmith's avatar
lsmith committed
1249
        if (method_exists($record, $method)) {
1250 1251 1252 1253 1254 1255 1256 1257 1258 1259
            return $record->$method($value);
        }

        return $value;
    }
    /**
     * invokeGet
     *
     * @param mixed $value
     */
lsmith's avatar
lsmith committed
1260 1261
    public function invokeGet(Doctrine_Record $record, $name, $value)
    {
lsmith's avatar
lsmith committed
1262
        if ( ! ($this->getAttribute(Doctrine::ATTR_ACCESSORS) & Doctrine::ACCESSOR_GET)) {
1263
            return $value;
lsmith's avatar
lsmith committed
1264
        }
zYne's avatar
zYne committed
1265 1266
        $prefix = $this->getAttribute(Doctrine::ATTR_ACCESSOR_PREFIX_GET);
        if (!$prefix)
1267
            $prefix = 'get';
zYne's avatar
zYne committed
1268

1269
        $method = $prefix . $name;
1270

lsmith's avatar
lsmith committed
1271
        if (method_exists($record, $method)) {
1272 1273 1274 1275 1276
            return $record->$method($value);
        }

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

doctrine's avatar
doctrine committed
1278
    /**
zYne's avatar
zYne committed
1279
     * getDefinitionOf
1280
     *
zYne's avatar
zYne committed
1281
     * @return string       ValueWrapper class name on success, false on failure
1282
     */
zYne's avatar
zYne committed
1283
    public function getValueWrapperOf($column)
lsmith's avatar
lsmith committed
1284
    {
zYne's avatar
zYne committed
1285 1286 1287 1288
        if (isset($this->columns[$column][2]['wrapper'])) {
            return $this->columns[$column][2]['wrapper'];
        }
        return false;
1289 1290
    }
    /**
zYne's avatar
zYne committed
1291
     * getColumnCount
1292
     *
zYne's avatar
zYne committed
1293
     * @return integer      the number of columns in this table
doctrine's avatar
doctrine committed
1294
     */
zYne's avatar
zYne committed
1295
    final public function getColumnCount()
lsmith's avatar
lsmith committed
1296
    {
zYne's avatar
zYne committed
1297
        return $this->columnCount;
doctrine's avatar
doctrine committed
1298
    }
zYne's avatar
zYne committed
1299

doctrine's avatar
doctrine committed
1300 1301 1302 1303 1304
    /**
     * returns all columns and their definitions
     *
     * @return array
     */
zYne's avatar
zYne committed
1305
    final public function getColumns()
lsmith's avatar
lsmith committed
1306
    {
doctrine's avatar
doctrine committed
1307 1308 1309 1310 1311 1312 1313
        return $this->columns;
    }
    /**
     * returns an array containing all the column names
     *
     * @return array
     */
lsmith's avatar
lsmith committed
1314 1315
    public function getColumnNames()
    {
doctrine's avatar
doctrine committed
1316 1317
        return array_keys($this->columns);
    }
zYne's avatar
zYne committed
1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342

    /**
     * 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
1343 1344 1345 1346 1347 1348 1349 1350
    /**
     * 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
1351 1352
    public function setData(array $data)
    {
doctrine's avatar
doctrine committed
1353 1354 1355 1356 1357 1358 1359
        $this->data = $data;
    }
    /**
     * returns the maximum primary key value
     *
     * @return integer
     */
lsmith's avatar
lsmith committed
1360 1361
    final public function getMaxIdentifier()
    {
doctrine's avatar
doctrine committed
1362
        $sql  = "SELECT MAX(".$this->getIdentifier().") FROM ".$this->getTableName();
zYne's avatar
zYne committed
1363
        $stmt = $this->conn->getDBH()->query($sql);
doctrine's avatar
doctrine committed
1364 1365 1366 1367 1368 1369 1370 1371
        $data = $stmt->fetch(PDO::FETCH_NUM);
        return isset($data[0])?$data[0]:1;
    }
    /**
     * returns simple cached query
     *
     * @return string
     */
lsmith's avatar
lsmith committed
1372 1373
    final public function getQuery()
    {
doctrine's avatar
doctrine committed
1374 1375 1376
        return $this->query;
    }
    /**
1377
     * returns internal data, used by Doctrine_Record instances
doctrine's avatar
doctrine committed
1378 1379 1380 1381
     * when retrieving data from database
     *
     * @return array
     */
lsmith's avatar
lsmith committed
1382 1383
    final public function getData()
    {
doctrine's avatar
doctrine committed
1384 1385
        return $this->data;
    }
zYne's avatar
zYne committed
1386 1387 1388 1389 1390 1391 1392 1393
    /**
     * 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) {
1394
                $options = isset($this->options['treeOptions']) ? $this->options['treeOptions'] : array();
zYne's avatar
zYne committed
1395 1396
                $this->tree = Doctrine_Tree::factory($this, 
                                                     $this->options['treeImpl'], 
1397
                                                     $options
zYne's avatar
zYne committed
1398 1399 1400 1401 1402 1403
                                                     );
            }
            return $this->tree;
        }
        return false;
    }
zYne's avatar
zYne committed
1404 1405 1406 1407 1408 1409 1410 1411
    public function getComponentName() 
    {
        return $this->options['name'];
    }
    public function getTableName()
    {
        return $this->options['tableName'];
    }
zYne's avatar
zYne committed
1412
    public function setTableName($tableName)
zYne's avatar
zYne committed
1413
    {
zYne's avatar
zYne committed
1414
        $this->options['tableName'] = $tableName;	
zYne's avatar
zYne committed
1415
    }
zYne's avatar
zYne committed
1416 1417 1418
    /**
     * determine if table acts as tree
     *
1419
     * @return mixed  if tree return true, otherwise returns false
zYne's avatar
zYne committed
1420 1421 1422 1423
     */    
    public function isTree() {
        return ( ! is_null($this->options['treeImpl'])) ? true : false;
    }
doctrine's avatar
doctrine committed
1424 1425 1426 1427 1428
    /**
     * returns a string representation of this object
     *
     * @return string
     */
lsmith's avatar
lsmith committed
1429 1430
    public function __toString()
    {
doctrine's avatar
doctrine committed
1431 1432 1433
        return Doctrine_Lib::getTableAsString($this);
    }
}