Table.php 42 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 95 96 97 98 99 100 101 102
    /**
     * @var array $bound                                bound relations
     */
    private $bound              = array();
    /**
     * @var array $boundAliases                         bound relation aliases
     */
    private $boundAliases       = array();
    /**
103 104
     * @var integer $columnCount                        cached column count, Doctrine_Record uses this column count in when
     *                                                  determining its state
doctrine's avatar
doctrine committed
105 106 107 108 109 110
     */
    private $columnCount;
    /**
     * @var array $parents                              the parent classes of this component
     */
    private $parents            = array();
111 112 113 114
    /**
     * @var boolean $hasDefaultValues                   whether or not this table has default values
     */
    private $hasDefaultValues;
zYne's avatar
zYne committed
115
    /**
116
     * @var array $options                  an array containing all options
zYne's avatar
zYne committed
117
     *
118
     *      -- name                         name of the component, for example component name of the GroupTable is 'Group'
zYne's avatar
zYne committed
119
     *
120 121 122 123
     *      -- 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)
     *
124 125
     *      -- 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
126
     *
127 128 129
     *      -- 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
130
     *
131
     *      -- enumMap                      enum value arrays
zYne's avatar
zYne committed
132
     *
133 134
     *      -- 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
135 136 137 138 139 140
     *
     *      -- engine                       database engine (mysql example: INNODB)
     *
     *      -- charset                      character set
     *
     *      -- collation
zYne's avatar
zYne committed
141 142 143 144 145 146
     */
    protected $options          = array('name'           => null,
                                        'tableName'      => null,
                                        'sequenceName'   => null,
                                        'inheritanceMap' => array(),
                                        'enumMap'        => array(),
zYne's avatar
zYne committed
147 148 149
                                        'engine'         => null,
                                        'charset'        => null,
                                        'collation'      => null
zYne's avatar
zYne committed
150
                                        );
doctrine's avatar
doctrine committed
151

doctrine's avatar
doctrine committed
152 153
    /**
     * the constructor
zYne's avatar
zYne committed
154 155
     * @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
156 157
     * @return void
     */
lsmith's avatar
lsmith committed
158 159
    public function __construct($name, Doctrine_Connection $conn)
    {
zYne's avatar
zYne committed
160
        $this->conn = $conn;
doctrine's avatar
doctrine committed
161

zYne's avatar
zYne committed
162
        $this->setParent($this->conn);
doctrine's avatar
doctrine committed
163

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

lsmith's avatar
lsmith committed
166
        if ( ! class_exists($name) || empty($name)) {
doctrine's avatar
doctrine committed
167
            throw new Doctrine_Exception("Couldn't find class $name");
lsmith's avatar
lsmith committed
168
        }
doctrine's avatar
doctrine committed
169 170 171 172 173 174 175 176 177
        $record = new $name($this);

        $names = array();

        $class = $name;

        // get parent classes

        do {
lsmith's avatar
lsmith committed
178
            if ($class == "Doctrine_Record")
zYne's avatar
zYne committed
179
                break;
doctrine's avatar
doctrine committed
180

lsmith's avatar
lsmith committed
181
            $name  = $class;
doctrine's avatar
doctrine committed
182
            $names[] = $name;
lsmith's avatar
lsmith committed
183
        } while ($class = get_parent_class($class));
doctrine's avatar
doctrine committed
184 185 186 187 188

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

        // create database table
lsmith's avatar
lsmith committed
189
        if (method_exists($record, 'setTableDefinition')) {
doctrine's avatar
doctrine committed
190 191 192 193
            $record->setTableDefinition();

            $this->columnCount = count($this->columns);

lsmith's avatar
lsmith committed
194
            if (isset($this->columns)) {
zYne's avatar
zYne committed
195
                // get the declaring class of setTableDefinition method
196
                $method    = new ReflectionMethod($this->options['name'], 'setTableDefinition');
doctrine's avatar
doctrine committed
197 198
                $class     = $method->getDeclaringClass();

199 200
                $this->options['declaringClass'] = $class;

lsmith's avatar
lsmith committed
201
                if ( ! isset($this->options['tableName'])) {
zYne's avatar
zYne committed
202
                    $this->options['tableName'] = Doctrine::tableize($class->getName());
lsmith's avatar
lsmith committed
203 204
                }
                switch (count($this->primaryKeys)) {
205 206 207 208 209 210 211 212 213
                    case 0:
                        $this->columns = array_merge(array('id' =>
                                                        array('integer',
                                                              20,
                                                              array('autoincrement' => true,
                                                                    'primary'       => true
                                                                    )
                                                              )
                                                        ), $this->columns);
lsmith's avatar
lsmith committed
214

215 216 217 218 219 220 221 222 223
                        $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
224

225 226 227
                        } else {
                            foreach ($this->primaryKeys as $pk) {
                                $e = $this->columns[$pk][2];
lsmith's avatar
lsmith committed
228

229
                                $found = false;
lsmith's avatar
lsmith committed
230

231 232 233
                                foreach ($e as $option => $value) {
                                    if ($found)
                                        break;
lsmith's avatar
lsmith committed
234

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

237
                                    switch (strtolower($e2[0])) {
zYne's avatar
zYne committed
238 239
                                        case 'autoincrement':
                                        case 'autoinc':
240 241 242
                                            $this->identifierType = Doctrine_Identifier::AUTO_INCREMENT;
                                            $found = true;
                                            break;
zYne's avatar
zYne committed
243 244
                                        case 'seq':
                                        case 'sequence':
245 246
                                            $this->identifierType = Doctrine_Identifier::SEQUENCE;
                                            $found = true;
zYne's avatar
zYne committed
247 248 249 250 251 252
                                            
                                            if($value) {
                                                $this->options['sequenceName'] = $value;
                                            } else {
                                                $this->options['sequenceName'] = $this->conn->getSequenceName($this->options['tableName']);
                                            }
253
                                            break;
zYne's avatar
zYne committed
254
                                    }
255 256 257 258 259
                                }
                                if ( ! isset($this->identifierType)) {
                                    $this->identifierType = Doctrine_Identifier::NORMAL;
                                }
                                $this->identifier = $pk;
doctrine's avatar
doctrine committed
260 261
                            }
                        }
lsmith's avatar
lsmith committed
262 263 264
                };

                if ($this->getAttribute(Doctrine::ATTR_CREATE_TABLES)) {
265
                    $this->export();
doctrine's avatar
doctrine committed
266 267 268 269
                }

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

doctrine's avatar
doctrine committed
273 274 275 276 277 278 279 280 281
        $record->setUp();

        // save parents
        array_pop($names);
        $this->parents   = $names;

        $this->query     = "SELECT ".implode(", ",array_keys($this->columns))." FROM ".$this->getTableName();

        // check if an instance of this table is already initialized
lsmith's avatar
lsmith committed
282
        if ( ! $this->conn->addTable($this)) {
doctrine's avatar
doctrine committed
283
            throw new Doctrine_Table_Exception();
lsmith's avatar
lsmith committed
284
        }
285
        $this->repository = new Doctrine_Table_Repository($this);
doctrine's avatar
doctrine committed
286
    }
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
    /**
     * export
     * exports this table to database based on column and option definitions
     *
     * @throws Doctrine_Connection_Exception    if some error other than Doctrine::ERR_ALREADY_EXISTS
     *                                          occurred during the create table operation
     * @return boolean                          whether or not the export operation was successful
     *                                          false if table already existed in the database
     */
    public function export() {
        if (Doctrine::isValidClassname($this->options['declaringClass']->getName())) {
            try {
                $columns = array();
                $primary = array();
                foreach ($this->columns as $name => $column) {
                    $definition = $column[2];
                    $definition['type'] = $column[0];
                    $definition['length'] = $column[1];

                    if ($definition['type'] == 'enum' && isset($definition['default'])) {
                        $definition['default'] = $this->enumIndex($name, $definition['default']);
                    }
                    if ($definition['type'] == 'boolean' && isset($definition['default'])) {
                        $definition['default'] = (int) $definition['default'];
                    }
                    $columns[$name] = $definition;
                    
                    if(isset($definition['primary']) && $definition['primary']) {
                        $primary[] = $name;
                    }
                }
                $options['primary'] = $primary;

                $this->conn->export->createTable($this->options['tableName'], $columns, array_merge($this->options, $options));
            } catch(Doctrine_Connection_Exception $e) {
                // we only want to silence table already exists errors
zYne's avatar
zYne committed
323
                if($e->getPortableCode() !== Doctrine::ERR_ALREADY_EXISTS) {
324 325 326 327 328
                    throw $e;
                }
            }
        }
    }
zYne's avatar
zYne committed
329 330 331 332
    /**
     * 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
333
     *
zYne's avatar
zYne committed
334 335
     * @return Doctrine_Query
     */
lsmith's avatar
lsmith committed
336 337
    public function createQuery()
    {
zYne's avatar
zYne committed
338 339
        return Doctrine_Query::create()->from($this->getComponentName());
    }
doctrine's avatar
doctrine committed
340
    /**
341 342 343
     * getRepository
     *
     * @return Doctrine_Table_Repository
doctrine's avatar
doctrine committed
344
     */
lsmith's avatar
lsmith committed
345 346
    public function getRepository()
    {
doctrine's avatar
doctrine committed
347 348
        return $this->repository;
    }
lsmith's avatar
lsmith committed
349

lsmith's avatar
lsmith committed
350 351
    public function setOption($name, $value)
    {
lsmith's avatar
lsmith committed
352
        switch ($name) {
353 354 355 356 357 358 359 360 361
            case 'name':
            case 'tableName':
                break;
            case 'enumMap':
            case 'inheritanceMap':
                if ( ! is_array($value)) {
                    throw new Doctrine_Table_Exception($name.' should be an array.');
                }
                break;
zYne's avatar
zYne committed
362 363 364
        }
        $this->options[$name] = $value;
    }
lsmith's avatar
lsmith committed
365

lsmith's avatar
lsmith committed
366 367
    public function usesInheritanceMap()
    {
368 369
        return ( ! empty($this->options['inheritanceMap']));
    }
lsmith's avatar
lsmith committed
370 371
    public function getOption($name)
    {
lsmith's avatar
lsmith committed
372
        if (isset($this->options[$name])) {
373
            return $this->options[$name];
lsmith's avatar
lsmith committed
374
        }
375 376
        return null;
    }
doctrine's avatar
doctrine committed
377 378
    /**
     * setColumn
zYne's avatar
zYne committed
379
     *
doctrine's avatar
doctrine committed
380 381 382 383
     * @param string $name
     * @param string $type
     * @param integer $length
     * @param mixed $options
zYne's avatar
zYne committed
384
     * @throws Doctrine_Table_Exception     if trying use wrongly typed parameter
doctrine's avatar
doctrine committed
385 386
     * @return void
     */
zYne's avatar
zYne committed
387
    final public function setColumn($name, $type, $length = null, $options = array()) {
lsmith's avatar
lsmith committed
388
        if (is_string($options)) {
389
            $options = explode('|', $options);
lsmith's avatar
lsmith committed
390
        }
zYne's avatar
zYne committed
391

lsmith's avatar
lsmith committed
392 393 394
        foreach ($options as $k => $option) {
            if (is_numeric($k)) {
                if ( ! empty($option)) {
395
                    $options[$option] = true;
lsmith's avatar
lsmith committed
396
                }
397 398 399
                unset($options[$k]);
            }
        }
400
        $name = strtolower($name);
lsmith's avatar
lsmith committed
401 402

        if ($length == null)
zYne's avatar
zYne committed
403
            $length = 2147483647;
zYne's avatar
zYne committed
404 405 406 407
            
        if((string) (int) $length !== (string) $length) {
            throw new Doctrine_Table_Exception('Invalid argument given for column length');
        }
zYne's avatar
zYne committed
408 409

        $this->columns[$name] = array($type, $length, $options);
410

lsmith's avatar
lsmith committed
411
        if (isset($options['primary'])) {
doctrine's avatar
doctrine committed
412 413
            $this->primaryKeys[] = $name;
        }
lsmith's avatar
lsmith committed
414
        if (isset($options['default'])) {
415 416 417 418 419 420 421 422 423
            $this->hasDefaultValues = true;
        }
    }
    /**
     * hasDefaultValues
     * returns true if this table has default values, otherwise false
     *
     * @return boolean
     */
lsmith's avatar
lsmith committed
424 425
    public function hasDefaultValues()
    {
426
        return $this->hasDefaultValues;
doctrine's avatar
doctrine committed
427
    }
428 429 430 431 432 433 434
    /**
     * getDefaultValueOf
     * returns the default value(if any) for given column
     *
     * @param string $column
     * @return mixed
     */
lsmith's avatar
lsmith committed
435 436
    public function getDefaultValueOf($column)
    {
437
        $column = strtolower($column);
lsmith's avatar
lsmith committed
438
        if ( ! isset($this->columns[$column])) {
439
            throw new Doctrine_Table_Exception("Couldn't get default value. Column ".$column." doesn't exist.");
lsmith's avatar
lsmith committed
440 441
        }
        if (isset($this->columns[$column][2]['default'])) {
442
            return $this->columns[$column][2]['default'];
lsmith's avatar
lsmith committed
443
        } else {
444
            return null;
lsmith's avatar
lsmith committed
445
        }
446
    }
doctrine's avatar
doctrine committed
447 448 449
    /**
     * @return mixed
     */
lsmith's avatar
lsmith committed
450 451
    final public function getIdentifier()
    {
doctrine's avatar
doctrine committed
452 453 454 455 456
        return $this->identifier;
    }
    /**
     * @return integer
     */
lsmith's avatar
lsmith committed
457 458
    final public function getIdentifierType()
    {
doctrine's avatar
doctrine committed
459 460 461 462 463 464
        return $this->identifierType;
    }
    /**
     * hasColumn
     * @return boolean
     */
lsmith's avatar
lsmith committed
465 466
    final public function hasColumn($name)
    {
doctrine's avatar
doctrine committed
467 468 469 470 471 472
        return isset($this->columns[$name]);
    }
    /**
     * @param mixed $key
     * @return void
     */
lsmith's avatar
lsmith committed
473 474
    final public function setPrimaryKey($key)
    {
lsmith's avatar
lsmith committed
475
        switch (gettype($key)) {
476 477 478 479 480 481
            case "array":
                $this->primaryKeys = array_values($key);
                break;
            case "string":
                $this->primaryKeys[] = $key;
                break;
lsmith's avatar
lsmith committed
482
        };
doctrine's avatar
doctrine committed
483 484 485 486 487
    }
    /**
     * returns all primary keys
     * @return array
     */
lsmith's avatar
lsmith committed
488 489
    final public function getPrimaryKeys()
    {
doctrine's avatar
doctrine committed
490 491 492 493 494
        return $this->primaryKeys;
    }
    /**
     * @return boolean
     */
lsmith's avatar
lsmith committed
495 496
    final public function hasPrimaryKey($key)
    {
doctrine's avatar
doctrine committed
497 498 499 500 501 502
        return in_array($key,$this->primaryKeys);
    }
    /**
     * @param $sequence
     * @return void
     */
lsmith's avatar
lsmith committed
503 504
    final public function setSequenceName($sequence)
    {
zYne's avatar
zYne committed
505
        $this->options['sequenceName'] = $sequence;
doctrine's avatar
doctrine committed
506 507 508 509
    }
    /**
     * @return string   sequence name
     */
lsmith's avatar
lsmith committed
510 511
    final public function getSequenceName()
    {
zYne's avatar
zYne committed
512
        return $this->options['sequenceName'];
doctrine's avatar
doctrine committed
513
    }
514 515 516
    /**
     * getParents
     */
lsmith's avatar
lsmith committed
517 518
    final public function getParents()
    {
doctrine's avatar
doctrine committed
519
        return $this->parents;
520 521 522 523
    }
    /**
     * @return boolean
     */
lsmith's avatar
lsmith committed
524 525
    final public function hasInheritanceMap()
    {
zYne's avatar
zYne committed
526
        return (empty($this->options['inheritanceMap']));
doctrine's avatar
doctrine committed
527 528 529 530
    }
    /**
     * @return array        inheritance map (array keys as fields)
     */
lsmith's avatar
lsmith committed
531 532
    final public function getInheritanceMap()
    {
zYne's avatar
zYne committed
533
        return $this->options['inheritanceMap'];
doctrine's avatar
doctrine committed
534 535 536 537 538
    }
    /**
     * return all composite paths in the form [component1].[component2]. . .[componentN]
     * @return array
     */
lsmith's avatar
lsmith committed
539 540
    final public function getCompositePaths()
    {
doctrine's avatar
doctrine committed
541 542
        $array = array();
        $name  = $this->getComponentName();
lsmith's avatar
lsmith committed
543
        foreach ($this->bound as $k=>$a) {
doctrine's avatar
doctrine committed
544
            try {
545 546 547 548 549 550 551 552 553 554 555 556 557 558
                $fk = $this->getRelation($k);
                switch ($fk->getType()) {
                    case Doctrine_Relation::ONE_COMPOSITE:
                    case Doctrine_Relation::MANY_COMPOSITE:
                        $n = $fk->getTable()->getComponentName();
                        $array[] = $name.".".$n;
                        $e = $fk->getTable()->getCompositePaths();
                        if ( ! empty($e)) {
                            foreach ($e as $name) {
                                $array[] = $name.".".$n.".".$name;
                            }
                        }
                        break;
                };
559
            } catch(Doctrine_Table_Exception $e) {
560

doctrine's avatar
doctrine committed
561 562 563 564 565 566 567 568 569
            }
        }
        return $array;
    }
    /**
     * returns all bound relations
     *
     * @return array
     */
lsmith's avatar
lsmith committed
570 571
    public function getBounds()
    {
doctrine's avatar
doctrine committed
572 573 574 575 576 577 578 579
        return $this->bound;
    }
    /**
     * returns a bound relation array
     *
     * @param string $name
     * @return array
     */
lsmith's avatar
lsmith committed
580 581
    public function getBound($name)
    {
lsmith's avatar
lsmith committed
582
        if ( ! isset($this->bound[$name])) {
583
            throw new Doctrine_Table_Exception('Unknown bound '.$name);
lsmith's avatar
lsmith committed
584
        }
doctrine's avatar
doctrine committed
585 586 587 588 589 590 591 592
        return $this->bound[$name];
    }
    /**
     * returns a bound relation array
     *
     * @param string $name
     * @return array
     */
lsmith's avatar
lsmith committed
593 594
    public function getBoundForName($name, $component)
    {
595

lsmith's avatar
lsmith committed
596
        foreach ($this->bound as $k => $bound) {
597
            $e = explode('.', $bound[0]);
598

lsmith's avatar
lsmith committed
599
            if ($bound[3] == $name && $e[0] == $component) {
doctrine's avatar
doctrine committed
600 601 602
                return $this->bound[$k];
            }
        }
603
        throw new Doctrine_Table_Exception('Unknown bound '.$name);
doctrine's avatar
doctrine committed
604 605 606 607 608 609 610
    }
    /**
     * returns the alias for given component name
     *
     * @param string $name
     * @return string
     */
lsmith's avatar
lsmith committed
611 612
    public function getAlias($name)
    {
lsmith's avatar
lsmith committed
613
        if (isset($this->boundAliases[$name])) {
doctrine's avatar
doctrine committed
614
            return $this->boundAliases[$name];
lsmith's avatar
lsmith committed
615
        }
doctrine's avatar
doctrine committed
616 617 618 619
        return $name;
    }
    /**
     * returns component name for given alias
620
     *
doctrine's avatar
doctrine committed
621 622 623
     * @param string $alias
     * @return string
     */
lsmith's avatar
lsmith committed
624 625
    public function getAliasName($alias)
    {
lsmith's avatar
lsmith committed
626
        if ($name = array_search($alias, $this->boundAliases)) {
doctrine's avatar
doctrine committed
627
            return $name;
lsmith's avatar
lsmith committed
628
        }
zYne's avatar
zYne committed
629
        return $alias;
doctrine's avatar
doctrine committed
630 631 632
    }
    /**
     * unbinds all relations
633
     *
doctrine's avatar
doctrine committed
634 635
     * @return void
     */
lsmith's avatar
lsmith committed
636 637
    public function unbindAll()
    {
doctrine's avatar
doctrine committed
638 639 640 641 642 643 644 645 646 647 648
        $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
649 650
    public function unbind($name)
    {
lsmith's avatar
lsmith committed
651
        if ( ! isset($this->bound[$name])) {
doctrine's avatar
doctrine committed
652
            return false;
lsmith's avatar
lsmith committed
653
        }
doctrine's avatar
doctrine committed
654 655
        unset($this->bound[$name]);

lsmith's avatar
lsmith committed
656
        if (isset($this->relations[$name])) {
doctrine's avatar
doctrine committed
657
            unset($this->relations[$name]);
lsmith's avatar
lsmith committed
658 659
        }
        if (isset($this->boundAliases[$name])) {
doctrine's avatar
doctrine committed
660
            unset($this->boundAliases[$name]);
lsmith's avatar
lsmith committed
661
        }
doctrine's avatar
doctrine committed
662 663 664 665 666 667 668 669 670
        return true;
    }
    /**
     * binds a relation
     *
     * @param string $name
     * @param string $field
     * @return void
     */
lsmith's avatar
lsmith committed
671 672
    public function bind($name, $field, $type, $localKey)
    {
lsmith's avatar
lsmith committed
673
        if (isset($this->relations[$name])) {
674
            unset($this->relations[$name]);
lsmith's avatar
lsmith committed
675
        }
doctrine's avatar
doctrine committed
676 677 678
        $e          = explode(" as ",$name);
        $name       = $e[0];

lsmith's avatar
lsmith committed
679
        if (isset($e[1])) {
doctrine's avatar
doctrine committed
680 681
            $alias = $e[1];
            $this->boundAliases[$name] = $alias;
lsmith's avatar
lsmith committed
682
        } else {
doctrine's avatar
doctrine committed
683
            $alias = $name;
lsmith's avatar
lsmith committed
684
        }
doctrine's avatar
doctrine committed
685

686
        $this->bound[$alias] = array($field, $type, $localKey, $name);
doctrine's avatar
doctrine committed
687 688 689 690 691
    }
    /**
     * getComponentName
     * @return string                   the component name
     */
lsmith's avatar
lsmith committed
692 693
    public function getComponentName()
    {
zYne's avatar
zYne committed
694
        return $this->options['name'];
doctrine's avatar
doctrine committed
695 696
    }
    /**
zYne's avatar
zYne committed
697
     * @return Doctrine_Connection
doctrine's avatar
doctrine committed
698
     */
lsmith's avatar
lsmith committed
699 700
    public function getConnection()
    {
zYne's avatar
zYne committed
701
        return $this->conn;
doctrine's avatar
doctrine committed
702
    }
703 704 705 706
    /**
     * hasRelatedComponent
     * @return boolean
     */
lsmith's avatar
lsmith committed
707 708
    final public function hasRelatedComponent($name, $component)
    {
709 710 711 712 713 714
         return (strpos($this->bound[$name][0], $component.'.') !== false);
    }
    /**
     * @param string $name              component name of which a foreign key object is bound
     * @return boolean
     */
lsmith's avatar
lsmith committed
715 716
    final public function hasRelation($name)
    {
lsmith's avatar
lsmith committed
717
        if (isset($this->bound[$name])) {
718
            return true;
lsmith's avatar
lsmith committed
719 720 721
        }
        foreach ($this->bound as $k=>$v) {
            if ($this->hasRelatedComponent($k, $name)) {
722
                return true;
lsmith's avatar
lsmith committed
723
            }
724 725 726
        }
        return false;
    }
doctrine's avatar
doctrine committed
727
    /**
728 729
     * getRelation
     *
doctrine's avatar
doctrine committed
730 731 732
     * @param string $name              component name of which a foreign key object is bound
     * @return Doctrine_Relation
     */
lsmith's avatar
lsmith committed
733 734
    final public function getRelation($name, $recursive = true)
    {
735 736
        $original = $name;

lsmith's avatar
lsmith committed
737 738 739 740
        if (isset($this->relations[$name])) {
            return $this->relations[$name];
        }
        if (isset($this->bound[$name])) {
doctrine's avatar
doctrine committed
741 742 743 744 745 746
            $type       = $this->bound[$name][1];
            $local      = $this->bound[$name][2];
            list($component, $foreign) = explode(".",$this->bound[$name][0]);
            $alias      = $name;
            $name       = $this->bound[$alias][3];

zYne's avatar
zYne committed
747
            $table      = $this->conn->getTable($name);
doctrine's avatar
doctrine committed
748

lsmith's avatar
lsmith committed
749
            if ($component == $this->options['name'] || in_array($component, $this->parents)) {
doctrine's avatar
doctrine committed
750
                // ONE-TO-ONE
lsmith's avatar
lsmith committed
751
                if ($type == Doctrine_Relation::ONE_COMPOSITE ||
doctrine's avatar
doctrine committed
752
                   $type == Doctrine_Relation::ONE_AGGREGATE) {
zYne's avatar
zYne committed
753 754
                    // tree structure parent relation found

lsmith's avatar
lsmith committed
755
                    if ( ! isset($local)) {
doctrine's avatar
doctrine committed
756
                        $local = $table->getIdentifier();
lsmith's avatar
lsmith committed
757
                    }
zYne's avatar
zYne committed
758
                    $relation = new Doctrine_Relation_LocalKey($table, $foreign, $local, $type, $alias);
lsmith's avatar
lsmith committed
759
                } else {
zYne's avatar
zYne committed
760 761 762 763 764 765 766 767
                    // tree structure children relation found

                    if ( ! isset($local)) {
                        $tmp = $table->getIdentifier();
                    }
                    $local   = $foreign;
                    $foreign = $tmp;

zYne's avatar
zYne committed
768
                    $relation = new Doctrine_Relation_ForeignKey($table, $foreign, $local, $type, $alias);
lsmith's avatar
lsmith committed
769
                }
zYne's avatar
zYne committed
770

lsmith's avatar
lsmith committed
771
            } elseif ($component == $name ||
zYne's avatar
zYne committed
772
                    ($component == $alias)) {     //  && ($name == $this->options['name'] || in_array($name,$this->parents))
zYne's avatar
zYne committed
773

zYne's avatar
zYne committed
774

lsmith's avatar
lsmith committed
775
                if ( ! isset($local)) {
doctrine's avatar
doctrine committed
776
                    $local = $this->identifier;
lsmith's avatar
lsmith committed
777
                }
doctrine's avatar
doctrine committed
778
                // ONE-TO-MANY or ONE-TO-ONE
779
                $relation = new Doctrine_Relation_ForeignKey($table, $local, $foreign, $type, $alias);
doctrine's avatar
doctrine committed
780 781 782 783 784

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

lsmith's avatar
lsmith committed
785
                if ($type != Doctrine_Relation::MANY_AGGREGATE)
786
                    throw new Doctrine_Table_Exception("Only aggregate relations are allowed for many-to-many relations");
doctrine's avatar
doctrine committed
787

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

lsmith's avatar
lsmith committed
790
                foreach (array_reverse($classes) as $class) {
doctrine's avatar
doctrine committed
791
                    try {
792
                        $bound = $table->getBoundForName($class, $component);
doctrine's avatar
doctrine committed
793
                        break;
794
                    } catch(Doctrine_Table_Exception $exc) { }
doctrine's avatar
doctrine committed
795
                }
lsmith's avatar
lsmith committed
796
                if ( ! isset($bound)) {
797 798
                    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
799 800
                }
                if ( ! isset($local)) {
doctrine's avatar
doctrine committed
801
                    $local = $this->identifier;
lsmith's avatar
lsmith committed
802
                }
803 804
                $e2     = explode('.', $bound[0]);
                $fields = explode('-', $e2[1]);
doctrine's avatar
doctrine committed
805

lsmith's avatar
lsmith committed
806
                if ($e2[0] != $component)
807
                    throw new Doctrine_Table_Exception($e2[0] . ' doesn\'t match ' . $component);
doctrine's avatar
doctrine committed
808

zYne's avatar
zYne committed
809
                $associationTable = $this->conn->getTable($e2[0]);
doctrine's avatar
doctrine committed
810

lsmith's avatar
lsmith committed
811
                if (count($fields) > 1) {
doctrine's avatar
doctrine committed
812
                    // SELF-REFERENCING THROUGH JOIN TABLE
813
                    $this->relations[$e2[0]] = new Doctrine_Relation_ForeignKey($associationTable, $local, $fields[0],Doctrine_Relation::MANY_COMPOSITE, $e2[0]);
814

815
                    $relation = new Doctrine_Relation_Association_Self($table, $associationTable, $fields[0], $fields[1], $type, $alias);
doctrine's avatar
doctrine committed
816
                } else {
817 818

                    // auto initialize a new one-to-one relationship for association table
819 820
                    $associationTable->bind($this->getComponentName(),  $associationTable->getComponentName(). '.' .$e2[1], Doctrine_Relation::ONE_AGGREGATE, $this->getIdentifier());
                    $associationTable->bind($table->getComponentName(), $associationTable->getComponentName(). '.' .$foreign, Doctrine_Relation::ONE_AGGREGATE, $table->getIdentifier());
821

doctrine's avatar
doctrine committed
822
                    // NORMAL MANY-TO-MANY RELATIONSHIP
823
                    $this->relations[$e2[0]] = new Doctrine_Relation_ForeignKey($associationTable, $local, $e2[1], Doctrine_Relation::MANY_COMPOSITE, $e2[0]);
doctrine's avatar
doctrine committed
824

825
                    $relation = new Doctrine_Relation_Association($table, $associationTable, $e2[1], $foreign, $type, $alias);
doctrine's avatar
doctrine committed
826 827 828
                }

            }
zYne's avatar
zYne committed
829

doctrine's avatar
doctrine committed
830 831 832
            $this->relations[$alias] = $relation;
            return $this->relations[$alias];
        }
zYne's avatar
zYne committed
833

834 835
        // load all relations
        $this->getRelations();
lsmith's avatar
lsmith committed
836 837

        if ($recursive) {
838 839
            return $this->getRelation($original, false);
        } else {
lsmith's avatar
lsmith committed
840
            throw new Doctrine_Table_Exception($this->options['name'] . " doesn't have a relation to " . $original);
841
        }
doctrine's avatar
doctrine committed
842 843 844 845 846 847
    }
    /**
     * returns an array containing all foreign key objects
     *
     * @return array
     */
lsmith's avatar
lsmith committed
848 849
    final public function getRelations()
    {
doctrine's avatar
doctrine committed
850
        $a = array();
lsmith's avatar
lsmith committed
851
        foreach ($this->bound as $k=>$v) {
852
            $this->getRelation($k);
doctrine's avatar
doctrine committed
853 854 855 856 857 858 859 860 861 862
        }

        return $this->relations;
    }
    /**
     * sets the database table name
     *
     * @param string $name              database table name
     * @return void
     */
lsmith's avatar
lsmith committed
863 864
    final public function setTableName($name)
    {
zYne's avatar
zYne committed
865
        $this->options['tableName'] = $name;
doctrine's avatar
doctrine committed
866 867 868 869 870 871 872
    }

    /**
     * returns the database table name
     *
     * @return string
     */
lsmith's avatar
lsmith committed
873 874
    final public function getTableName()
    {
875
        return $this->options['tableName'];
doctrine's avatar
doctrine committed
876 877 878 879 880 881 882 883 884
    }
    /**
     * 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()) {
885
        $this->data         = $array;
chtito's avatar
chtito committed
886
        $record = new $this->options['name']($this, true);
doctrine's avatar
doctrine committed
887 888 889 890 891 892 893
        $this->data         = array();
        return $record;
    }
    /**
     * finds a record by its identifier
     *
     * @param $id                       database row id
zYne's avatar
zYne committed
894
     * @return Doctrine_Record|false    a record for given database identifier
doctrine's avatar
doctrine committed
895
     */
lsmith's avatar
lsmith committed
896 897
    public function find($id)
    {
lsmith's avatar
lsmith committed
898 899
        if ($id !== null) {
            if ( ! is_array($id)) {
doctrine's avatar
doctrine committed
900
                $id = array($id);
lsmith's avatar
lsmith committed
901
            } else {
doctrine's avatar
doctrine committed
902
                $id = array_values($id);
lsmith's avatar
lsmith committed
903
            }
doctrine's avatar
doctrine committed
904 905 906

            $query  = $this->query." WHERE ".implode(" = ? AND ",$this->primaryKeys)." = ?";
            $query  = $this->applyInheritance($query);
doctrine's avatar
doctrine committed
907

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

zYne's avatar
zYne committed
910
            $stmt  = $this->conn->execute($query,$params);
doctrine's avatar
doctrine committed
911 912

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

lsmith's avatar
lsmith committed
914
            if ($this->data === false)
915
                return false;
lsmith's avatar
lsmith committed
916

pookey's avatar
pookey committed
917
            return $this->getRecord();
doctrine's avatar
doctrine committed
918
        }
pookey's avatar
pookey committed
919
        return false;
doctrine's avatar
doctrine committed
920 921 922 923 924 925
    }
    /**
     * applyInheritance
     * @param $where                    query where part to be modified
     * @return string                   query where part with column aggregation inheritance added
     */
lsmith's avatar
lsmith committed
926 927
    final public function applyInheritance($where)
    {
lsmith's avatar
lsmith committed
928
        if ( ! empty($this->options['inheritanceMap'])) {
doctrine's avatar
doctrine committed
929
            $a = array();
lsmith's avatar
lsmith committed
930
            foreach ($this->options['inheritanceMap'] as $field => $value) {
doctrine's avatar
doctrine committed
931 932 933 934 935 936 937 938 939 940 941 942 943
                $a[] = $field." = ?";
            }
            $i = implode(" AND ",$a);
            $where .= " AND $i";
        }
        return $where;
    }
    /**
     * findAll
     * returns a collection of records
     *
     * @return Doctrine_Collection
     */
lsmith's avatar
lsmith committed
944 945
    public function findAll()
    {
zYne's avatar
zYne committed
946
        $graph = new Doctrine_Query($this->conn);
zYne's avatar
zYne committed
947
        $users = $graph->query("FROM ".$this->options['name']);
doctrine's avatar
doctrine committed
948 949 950
        return $users;
    }
    /**
951 952
     * findByDql
     * finds records with given DQL where clause
doctrine's avatar
doctrine committed
953 954
     * returns a collection of records
     *
955
     * @param string $dql               DQL after WHERE clause
doctrine's avatar
doctrine committed
956 957 958
     * @param array $params             query parameters
     * @return Doctrine_Collection
     */
959
    public function findBySql($dql, array $params = array()) {
zYne's avatar
zYne committed
960
        $q = new Doctrine_Query($this->conn);
zYne's avatar
zYne committed
961
        $users = $q->query("FROM ".$this->options['name']." WHERE ".$dql, $params);
doctrine's avatar
doctrine committed
962 963
        return $users;
    }
964

965 966 967
    public function findByDql($dql, array $params = array()) {
        return $this->findBySql($dql, $params);
    }
doctrine's avatar
doctrine committed
968 969 970 971 972 973
    /**
     * clear
     * clears the first level cache (identityMap)
     *
     * @return void
     */
lsmith's avatar
lsmith committed
974 975
    public function clear()
    {
doctrine's avatar
doctrine committed
976 977 978 979 980 981 982 983 984
        $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
985 986
    public function getRecord()
    {
zYne's avatar
zYne committed
987 988
        $this->data = array_change_key_case($this->data, CASE_LOWER);

doctrine's avatar
doctrine committed
989 990
        $key = $this->getIdentifier();

lsmith's avatar
lsmith committed
991
        if ( ! is_array($key)) {
doctrine's avatar
doctrine committed
992
            $key = array($key);
lsmith's avatar
lsmith committed
993 994 995
        }
        foreach ($key as $k) {
            if ( ! isset($this->data[$k])) {
996
                throw new Doctrine_Exception("Primary key value for $k wasn't found");
lsmith's avatar
lsmith committed
997
            }
doctrine's avatar
doctrine committed
998 999
            $id[] = $this->data[$k];
        }
1000

doctrine's avatar
doctrine committed
1001 1002
        $id = implode(' ', $id);

lsmith's avatar
lsmith committed
1003
        if (isset($this->identityMap[$id])) {
doctrine's avatar
doctrine committed
1004
            $record = $this->identityMap[$id];
lsmith's avatar
lsmith committed
1005
        } else {
zYne's avatar
zYne committed
1006
            $record = new $this->options['name']($this);
doctrine's avatar
doctrine committed
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
            $this->identityMap[$id] = $record;
        }
        $this->data = array();

        return $record;
    }
    /**
     * @param $id                       database row id
     * @throws Doctrine_Find_Exception
     */
lsmith's avatar
lsmith committed
1017 1018
    final public function getProxy($id = null)
    {
lsmith's avatar
lsmith committed
1019
        if ($id !== null) {
doctrine's avatar
doctrine committed
1020 1021
            $query = "SELECT ".implode(", ",$this->primaryKeys)." FROM ".$this->getTableName()." WHERE ".implode(" = ? && ",$this->primaryKeys)." = ?";
            $query = $this->applyInheritance($query);
1022

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

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

lsmith's avatar
lsmith committed
1027
            if ($this->data === false)
1028
                return false;
doctrine's avatar
doctrine committed
1029 1030 1031
        }
        return $this->getRecord();
    }
1032 1033
    /**
     * count
1034
     *
1035 1036
     * @return integer
     */
lsmith's avatar
lsmith committed
1037 1038
    public function count()
    {
zYne's avatar
zYne committed
1039
        $a = $this->conn->getDBH()->query("SELECT COUNT(1) FROM ".$this->options['tableName'])->fetch(PDO::FETCH_NUM);
1040 1041
        return current($a);
    }
doctrine's avatar
doctrine committed
1042 1043 1044
    /**
     * @return Doctrine_Query                           a Doctrine_Query object
     */
lsmith's avatar
lsmith committed
1045 1046
    public function getQueryObject()
    {
zYne's avatar
zYne committed
1047
        $graph = new Doctrine_Query($this->getConnection());
doctrine's avatar
doctrine committed
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059
        $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
1060
        $query = $this->conn->modifyLimitQuery($query,$limit,$offset);
lsmith's avatar
lsmith committed
1061
        if ( ! empty($array)) {
zYne's avatar
zYne committed
1062
            $stmt = $this->conn->getDBH()->prepare($query);
doctrine's avatar
doctrine committed
1063 1064
            $stmt->execute($array);
        } else {
zYne's avatar
zYne committed
1065
            $stmt = $this->conn->getDBH()->query($query);
doctrine's avatar
doctrine committed
1066 1067 1068 1069
        }
        $data = $stmt->fetchAll(PDO::FETCH_ASSOC);
        $stmt->closeCursor();

lsmith's avatar
lsmith committed
1070
        foreach ($data as $row) {
doctrine's avatar
doctrine committed
1071 1072 1073 1074 1075 1076
            $this->data = $row;
            $record = $this->getRecord();
            $coll->add($record);
        }
        return $coll;
    }
doctrine's avatar
doctrine committed
1077 1078 1079 1080 1081 1082 1083
    /**
     * sets enumerated value array for given field
     *
     * @param string $field
     * @param array $values
     * @return void
     */
lsmith's avatar
lsmith committed
1084 1085
    final public function setEnumValues($field, array $values)
    {
zYne's avatar
zYne committed
1086
        $this->options['enumMap'][strtolower($field)] = $values;
doctrine's avatar
doctrine committed
1087
    }
doctrine's avatar
doctrine committed
1088 1089 1090 1091
    /**
     * @param string $field
     * @return array
     */
lsmith's avatar
lsmith committed
1092 1093
    final public function getEnumValues($field)
    {
lsmith's avatar
lsmith committed
1094
        if (isset($this->options['enumMap'][$field])) {
zYne's avatar
zYne committed
1095
            return $this->options['enumMap'][$field];
lsmith's avatar
lsmith committed
1096
        } else {
doctrine's avatar
doctrine committed
1097
            return array();
lsmith's avatar
lsmith committed
1098
        }
doctrine's avatar
doctrine committed
1099
    }
doctrine's avatar
doctrine committed
1100 1101
    /**
     * enumValue
1102 1103 1104 1105
     *
     * @param string $field
     * @param integer $index
     * @return mixed
doctrine's avatar
doctrine committed
1106
     */
lsmith's avatar
lsmith committed
1107 1108
    final public function enumValue($field, $index)
    {
1109
        if ($index instanceof Doctrine_Null)
1110
            return $index;
1111

zYne's avatar
zYne committed
1112
        return isset($this->options['enumMap'][$field][$index]) ? $this->options['enumMap'][$field][$index] : $index;
doctrine's avatar
doctrine committed
1113
    }
1114 1115 1116 1117 1118
    /**
     * invokeSet
     *
     * @param mixed $value
     */
lsmith's avatar
lsmith committed
1119 1120
    public function invokeSet(Doctrine_Record $record, $name, $value)
    {
lsmith's avatar
lsmith committed
1121
        if ( ! ($this->getAttribute(Doctrine::ATTR_ACCESSORS) & Doctrine::ACCESSOR_SET)) {
zYne's avatar
zYne committed
1122
            return $value;
lsmith's avatar
lsmith committed
1123
        }
zYne's avatar
zYne committed
1124 1125
        $prefix = $this->getAttribute(Doctrine::ATTR_ACCESSOR_PREFIX_SET);
        if (!$prefix)
1126
            $prefix = 'set';
1127

1128
        $method = $prefix . $name;
1129

lsmith's avatar
lsmith committed
1130
        if (method_exists($record, $method)) {
1131 1132 1133 1134 1135 1136 1137 1138 1139 1140
            return $record->$method($value);
        }

        return $value;
    }
    /**
     * invokeGet
     *
     * @param mixed $value
     */
lsmith's avatar
lsmith committed
1141 1142
    public function invokeGet(Doctrine_Record $record, $name, $value)
    {
lsmith's avatar
lsmith committed
1143
        if ( ! ($this->getAttribute(Doctrine::ATTR_ACCESSORS) & Doctrine::ACCESSOR_GET)) {
1144
            return $value;
lsmith's avatar
lsmith committed
1145
        }
zYne's avatar
zYne committed
1146 1147
        $prefix = $this->getAttribute(Doctrine::ATTR_ACCESSOR_PREFIX_GET);
        if (!$prefix)
1148
            $prefix = 'get';
zYne's avatar
zYne committed
1149

1150
        $method = $prefix . $name;
1151

lsmith's avatar
lsmith committed
1152
        if (method_exists($record, $method)) {
1153 1154 1155 1156 1157
            return $record->$method($value);
        }

        return $value;
    }
doctrine's avatar
doctrine committed
1158 1159
    /**
     * enumIndex
1160 1161 1162 1163
     *
     * @param string $field
     * @param mixed $value
     * @return mixed
doctrine's avatar
doctrine committed
1164
     */
lsmith's avatar
lsmith committed
1165 1166
    final public function enumIndex($field, $value)
    {
lsmith's avatar
lsmith committed
1167
        if ( ! isset($this->options['enumMap'][$field])) {
1168
            $values = array();
lsmith's avatar
lsmith committed
1169
        } else {
zYne's avatar
zYne committed
1170
            $values = $this->options['enumMap'][$field];
lsmith's avatar
lsmith committed
1171
        }
1172 1173

        return array_search($value, $values);
doctrine's avatar
doctrine committed
1174
    }
doctrine's avatar
doctrine committed
1175
    /**
1176 1177 1178 1179
     * getDefinitionOf
     *
     * @return string       ValueWrapper class name on success, false on failure
     */
lsmith's avatar
lsmith committed
1180 1181
    public function getValueWrapperOf($column)
    {
lsmith's avatar
lsmith committed
1182
        if (isset($this->columns[$column][2]['wrapper'])) {
1183
            return $this->columns[$column][2]['wrapper'];
lsmith's avatar
lsmith committed
1184
        }
1185 1186 1187 1188 1189 1190
        return false;
    }
    /**
     * getColumnCount
     *
     * @return integer      the number of columns in this table
doctrine's avatar
doctrine committed
1191
     */
lsmith's avatar
lsmith committed
1192 1193
    final public function getColumnCount()
    {
1194
        return $this->columnCount;
doctrine's avatar
doctrine committed
1195
    }
doctrine's avatar
doctrine committed
1196

doctrine's avatar
doctrine committed
1197 1198 1199 1200 1201
    /**
     * returns all columns and their definitions
     *
     * @return array
     */
lsmith's avatar
lsmith committed
1202 1203
    final public function getColumns()
    {
doctrine's avatar
doctrine committed
1204 1205 1206 1207 1208 1209 1210
        return $this->columns;
    }
    /**
     * returns an array containing all the column names
     *
     * @return array
     */
lsmith's avatar
lsmith committed
1211 1212
    public function getColumnNames()
    {
doctrine's avatar
doctrine committed
1213 1214
        return array_keys($this->columns);
    }
1215

doctrine's avatar
doctrine committed
1216 1217
    /**
     * getDefinitionOf
1218 1219
     *
     * @return mixed        array on success, false on failure
doctrine's avatar
doctrine committed
1220
     */
lsmith's avatar
lsmith committed
1221 1222
    public function getDefinitionOf($column)
    {
lsmith's avatar
lsmith committed
1223
        if (isset($this->columns[$column])) {
doctrine's avatar
doctrine committed
1224
            return $this->columns[$column];
lsmith's avatar
lsmith committed
1225
        }
1226
        return false;
doctrine's avatar
doctrine committed
1227
    }
doctrine's avatar
doctrine committed
1228 1229
    /**
     * getTypeOf
1230 1231
     *
     * @return mixed        string on success, false on failure
doctrine's avatar
doctrine committed
1232
     */
lsmith's avatar
lsmith committed
1233 1234
    public function getTypeOf($column)
    {
lsmith's avatar
lsmith committed
1235
        if (isset($this->columns[$column])) {
1236
            return $this->columns[$column][0];
lsmith's avatar
lsmith committed
1237
        }
1238
        return false;
doctrine's avatar
doctrine committed
1239
    }
doctrine's avatar
doctrine committed
1240 1241 1242 1243 1244 1245 1246 1247
    /**
     * 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
1248 1249
    public function setData(array $data)
    {
doctrine's avatar
doctrine committed
1250 1251 1252 1253 1254 1255 1256
        $this->data = $data;
    }
    /**
     * returns the maximum primary key value
     *
     * @return integer
     */
lsmith's avatar
lsmith committed
1257 1258
    final public function getMaxIdentifier()
    {
doctrine's avatar
doctrine committed
1259
        $sql  = "SELECT MAX(".$this->getIdentifier().") FROM ".$this->getTableName();
zYne's avatar
zYne committed
1260
        $stmt = $this->conn->getDBH()->query($sql);
doctrine's avatar
doctrine committed
1261 1262 1263 1264 1265 1266 1267 1268
        $data = $stmt->fetch(PDO::FETCH_NUM);
        return isset($data[0])?$data[0]:1;
    }
    /**
     * returns simple cached query
     *
     * @return string
     */
lsmith's avatar
lsmith committed
1269 1270
    final public function getQuery()
    {
doctrine's avatar
doctrine committed
1271 1272 1273
        return $this->query;
    }
    /**
1274
     * returns internal data, used by Doctrine_Record instances
doctrine's avatar
doctrine committed
1275 1276 1277 1278
     * when retrieving data from database
     *
     * @return array
     */
lsmith's avatar
lsmith committed
1279 1280
    final public function getData()
    {
doctrine's avatar
doctrine committed
1281 1282 1283 1284 1285 1286 1287
        return $this->data;
    }
    /**
     * returns a string representation of this object
     *
     * @return string
     */
lsmith's avatar
lsmith committed
1288 1289
    public function __toString()
    {
doctrine's avatar
doctrine committed
1290 1291 1292
        return Doctrine_Lib::getTableAsString($this);
    }
}