# Coverage for Doctrine_Table

Back to coverage report

1 | <?php
2 | /*
3 | * $Id: Table.php 3206 2007-11-22 22:02:35Z zYne $
4 | *
5 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
6 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
7 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
8 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
9 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
10 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
11 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
12 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
13 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
15 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16 | *
17 | * This software consists of voluntary contributions made by many individuals
18 | * and is licensed under the LGPL. For more information, see
19 | * <http://www.phpdoctrine.org>.
20 | */
21 |
22 | /**
23 | * Doctrine_Table represents a database table
24 | * each Doctrine_Table holds the information of foreignKeys and associations
25 | *
26 | *
27 | * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
28 | * @package Doctrine
29 | * @subpackage Table
30 | * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
31 | * @version $Revision: 3206 $
32 | * @link www.phpdoctrine.org
33 | * @since 1.0
34 | */
35 | class Doctrine_Table extends Doctrine_Configurable implements Countable
36 | {
37 | /**
38 | * @var array $data temporary data which is then loaded into Doctrine_Record::$_data
39 | */
40 | protected $_data = array();
41 |
42 | /**
43 | * @var mixed $identifier The field names of all fields that are part of the identifier/primary key
44 | */
45 | protected $_identifier = array();
46 |
47 | /**
48 | * @see Doctrine_Identifier constants
49 | * @var integer $identifierType the type of identifier this table uses
50 | */
51 | protected $_identifierType;
52 |
53 | /**
54 | * @var Doctrine_Connection $conn Doctrine_Connection object that created this table
55 | */
56 | protected $_conn;
57 |
58 | /**
59 | * @var array $identityMap first level cache
60 | */
61 | protected $_identityMap = array();
62 |
63 | /**
64 | * @var Doctrine_Table_Repository $repository record repository
65 | */
66 | protected $_repository;
67 |
68 | /**
69 | * @var array $columns an array of column definitions,
70 | * keys are column names and values are column definitions
71 | *
72 | * the definition array has atleast the following values:
73 | *
74 | * -- type the column type, eg. 'integer'
75 | * -- length the column length, eg. 11
76 | *
77 | * additional keys:
78 | * -- notnull whether or not the column is marked as notnull
79 | * -- values enum values
80 | * -- notblank notblank validator + notnull constraint
81 | * ... many more
82 | */
83 | protected $_columns = array();
84 |
85 | /**
86 | * @var array $_fieldNames an array of field names. used to look up field names
87 | * from column names.
88 | * keys are column names and values are field names
89 | */
90 | protected $_fieldNames = array();
91 |
92 | /**
93 | *
94 | * @var array $_columnNames an array of column names
95 | * keys are field names and values column names.
96 | * used to look up column names from field names.
97 | * this is the reverse lookup map of $_fieldNames.
98 | */
99 | protected $_columnNames = array();
100 |
101 | /**
102 | * @var integer $columnCount cached column count, Doctrine_Record uses this column count in when
103 | * determining its state
104 | */
105 | protected $columnCount;
106 |
107 | /**
108 | * @var boolean $hasDefaultValues whether or not this table has default values
109 | */
110 | protected $hasDefaultValues;
111 |
112 | /**
113 | * @var array $options an array containing all options
114 | *
115 | * -- name name of the component, for example component name of the GroupTable is 'Group'
116 | *
117 | * -- parents the parent classes of this component
118 | *
119 | * -- declaringClass name of the table definition declaring class (when using inheritance the class
120 | * that defines the table structure can be any class in the inheritance hierarchy,
121 | * hence we need reflection to check out which class actually calls setTableDefinition)
122 | *
123 | * -- tableName database table name, in most cases this is the same as component name but in some cases
124 | * where one-table-multi-class inheritance is used this will be the name of the inherited table
125 | *
126 | * -- sequenceName Some databases need sequences instead of auto incrementation primary keys,
127 | * you can set specific sequence for your table by calling setOption('sequenceName', $seqName)
128 | * where $seqName is the name of the desired sequence
129 | *
130 | * -- enumMap enum value arrays
131 | *
132 | * -- inheritanceMap inheritanceMap is used for inheritance mapping, keys representing columns and values
133 | * the column values that should correspond to child classes
134 | *
135 | * -- type table type (mysql example: INNODB)
136 | *
137 | * -- charset character set
138 | *
139 | * -- foreignKeys the foreign keys of this table
140 | *
141 | * -- checks the check constraints of this table, eg. 'price > dicounted_price'
142 | *
143 | * -- collation collation attribute
144 | *
145 | * -- indexes the index definitions of this table
146 | *
147 | * -- treeImpl the tree implementation of this table (if any)
148 | *
149 | * -- treeOptions the tree options
150 | *
151 | * -- queryParts the bound query parts
152 | *
153 | * -- versioning
154 | */
155 | protected $_options = array('name' => null,
156 | 'tableName' => null,
157 | 'sequenceName' => null,
158 | 'inheritanceMap' => array(),
159 | 'enumMap' => array(),
160 | 'type' => null,
161 | 'charset' => null,
162 | 'collation' => null,
163 | 'treeImpl' => null,
164 | 'treeOptions' => null,
165 | 'indexes' => array(),
166 | 'parents' => array(),
167 | 'queryParts' => array(),
168 | 'versioning' => null,
169 | );
170 |
171 | /**
172 | * @var Doctrine_Tree $tree tree object associated with this table
173 | */
174 | protected $_tree;
175 |
176 | /**
177 | * @var Doctrine_Relation_Parser $_parser relation parser object
178 | */
179 | protected $_parser;
180 |
181 | /**
182 | * @var array $_templates an array containing all templates attached to this table
183 | */
184 | protected $_templates = array();
185 |
186 | /**
187 | * @var array $_filters an array containing all record filters attached to this table
188 | */
189 | protected $_filters = array();
190 |
191 | /**
192 | * @var array $_invokedMethods method invoker cache
193 | */
194 | protected $_invokedMethods = array();
195 |
196 |
197 |
198 | /**
199 | * the constructor
200 | *
201 | * @throws Doctrine_Connection_Exception if there are no opened connections
202 | * @param string $name the name of the component
203 | * @param Doctrine_Connection $conn the connection associated with this table
204 | */
205 | public function __construct($name, Doctrine_Connection $conn, $initDefinition = false)
206 | {
207 | $this->_conn = $conn;
208 |
209 | $this->setParent($this->_conn);
210 |
211 | $this->_options['name'] = $name;
212 | $this->_parser = new Doctrine_Relation_Parser($this);
213 |
214 | if ($initDefinition) {
215 | $record = $this->initDefinition();
216 |
217 | $this->initIdentifier();
218 |
219 | $record->setUp();
220 |
221 | // if tree, set up tree
222 | if ($this->isTree()) {
223 | $this->getTree()->setUp();
224 | }
225 | }
226 | $this->_filters[] = new Doctrine_Record_Filter_Standard();
227 | $this->_repository = new Doctrine_Table_Repository($this);
228 | }
229 |
230 | /**
231 | * Initializes the in-memory table definition.
232 | *
233 | * @param string $name
234 | */
235 | public function initDefinition()
236 | {
237 | $name = $this->_options['name'];
238 | if ( ! class_exists($name) || empty($name)) {
239 | throw new Doctrine_Exception("Couldn't find class " . $name);
240 | }
241 | $record = new $name($this);
242 |
243 | $names = array();
244 |
245 | $class = $name;
246 |
247 | // get parent classes
248 |
249 | do {
250 | if ($class === 'Doctrine_Record') {
251 | break;
252 | }
253 |
254 | $name = $class;
255 | $names[] = $name;
256 | } while ($class = get_parent_class($class));
257 |
258 | if ($class === false) {
259 | throw new Doctrine_Table_Exception('Unknown component.');
260 | }
261 |
262 | // reverse names
263 | $names = array_reverse($names);
264 | // save parents
265 | array_pop($names);
266 | $this->_options['parents'] = $names;
267 |
268 | // create database table
269 | if (method_exists($record, 'setTableDefinition')) {
270 | $record->setTableDefinition();
271 | // get the declaring class of setTableDefinition method
272 | $method = new ReflectionMethod($this->_options['name'], 'setTableDefinition');
273 | $class = $method->getDeclaringClass();
274 |
275 | } else {
276 | $class = new ReflectionClass($class);
277 | }
278 |
279 | $this->_options['joinedParents'] = array();
280 |
281 | foreach (array_reverse($this->_options['parents']) as $parent) {
282 |
283 | if ($parent === $class->getName()) {
284 | continue;
285 | }
286 | $ref = new ReflectionClass($parent);
287 |
288 | if ($ref->isAbstract()) {
289 | continue;
290 | }
291 | $parentTable = $this->_conn->getTable($parent);
292 |
293 | $found = false;
294 | $parentColumns = $parentTable->getColumns();
295 |
296 | foreach ($parentColumns as $columnName => $definition) {
297 | if ( ! isset($definition['primary'])) {
298 | if (isset($this->_columns[$columnName])) {
299 | $found = true;
300 | break;
301 | } else {
302 | if ( ! isset($parentColumns[$columnName]['owner'])) {
303 | $parentColumns[$columnName]['owner'] = $parentTable->getComponentName();
304 | }
305 |
306 | $this->_options['joinedParents'][] = $parentColumns[$columnName]['owner'];
307 | }
308 | } else {
309 | unset($parentColumns[$columnName]);
310 | }
311 | }
312 |
313 | if ($found) {
314 | continue;
315 | }
316 |
317 | foreach ($parentColumns as $columnName => $definition) {
318 | $fullName = $columnName . ' as ' . $parentTable->getFieldName($columnName);
319 | $this->setColumn($fullName, $definition['type'], $definition['length'], $definition, true);
320 | }
321 |
322 | break;
323 | }
324 |
325 | $this->_options['joinedParents'] = array_values(array_unique($this->_options['joinedParents']));
326 |
327 | $this->_options['declaringClass'] = $class;
328 |
329 | // set the table definition for the given tree implementation
330 | if ($this->isTree()) {
331 | $this->getTree()->setTableDefinition();
332 | }
333 |
334 | $this->columnCount = count($this->_columns);
335 |
336 | if ( ! isset($this->_options['tableName'])) {
337 | $this->_options['tableName'] = Doctrine::tableize($class->getName());
338 | }
339 |
340 | return $record;
341 | }
342 |
343 | /**
344 | * Initializes the table identifier(s)/primary key(s)
345 | *
346 | */
347 | public function initIdentifier()
348 | {
349 | switch (count($this->_identifier)) {
350 | case 0:
351 | if ( ! empty($this->_options['joinedParents'])) {
352 | $root = current($this->_options['joinedParents']);
353 |
354 | $table = $this->_conn->getTable($root);
355 |
356 | $this->_identifier = $table->getIdentifier();
357 |
358 | $this->_identifierType = ($table->getIdentifierType() !== Doctrine::IDENTIFIER_AUTOINC)
359 | ? $table->getIdentifierType() : Doctrine::IDENTIFIER_NATURAL;
360 |
361 | // add all inherited primary keys
362 | foreach ((array) $this->_identifier as $id) {
363 | $definition = $table->getDefinitionOf($id);
364 |
365 | // inherited primary keys shouldn't contain autoinc
366 | // and sequence definitions
367 | unset($definition['autoincrement']);
368 | unset($definition['sequence']);
369 |
370 | // add the inherited primary key column
371 | $fullName = $id . ' as ' . $table->getFieldName($id);
372 | $this->setColumn($fullName, $definition['type'], $definition['length'],
373 | $definition, true);
374 | }
375 | } else {
376 | $definition = array('type' => 'integer',
377 | 'length' => 20,
378 | 'autoincrement' => true,
379 | 'primary' => true);
380 | $this->setColumn('id', $definition['type'], $definition['length'], $definition, true);
381 | $this->_identifier = 'id';
382 | $this->_identifierType = Doctrine::IDENTIFIER_AUTOINC;
383 | }
384 | $this->columnCount++;
385 | break;
386 | case 1:
387 | foreach ($this->_identifier as $pk) {
388 | $columnName = $this->getColumnName($pk);
389 | $e = $this->_columns[$columnName];
390 |
391 | $found = false;
392 |
393 | foreach ($e as $option => $value) {
394 | if ($found) {
395 | break;
396 | }
397 |
398 | $e2 = explode(':', $option);
399 |
400 | switch (strtolower($e2[0])) {
401 | case 'autoincrement':
402 | case 'autoinc':
403 | $this->_identifierType = Doctrine::IDENTIFIER_AUTOINC;
404 | $found = true;
405 | break;
406 | case 'seq':
407 | case 'sequence':
408 | $this->_identifierType = Doctrine::IDENTIFIER_SEQUENCE;
409 | $found = true;
410 |
411 | if ($value) {
412 | $this->_options['sequenceName'] = $value;
413 | } else {
414 | if (($sequence = $this->getAttribute(Doctrine::ATTR_DEFAULT_SEQUENCE)) !== null) {
415 | $this->_options['sequenceName'] = $sequence;
416 | } else {
417 | $this->_options['sequenceName'] = $this->_conn->getSequenceName($this->_options['tableName']);
418 | }
419 | }
420 | break;
421 | }
422 | }
423 | if ( ! isset($this->_identifierType)) {
424 | $this->_identifierType = Doctrine::IDENTIFIER_NATURAL;
425 | }
426 | }
427 |
428 | $this->_identifier = $pk;
429 |
430 | break;
431 | default:
432 | $this->_identifierType = Doctrine::IDENTIFIER_COMPOSITE;
433 | }
434 | }
435 |
436 | /**
437 | * Gets the owner of a column.
438 | * The owner of a column is the name of the component in a hierarchy that
439 | * defines the column.
440 | *
441 | * @param string $columnName The column name
442 | * @return string The name of the owning/defining component
443 | */
444 | public function getColumnOwner($columnName)
445 | {
446 | if (isset($this->_columns[$columnName]['owner'])) {
447 | return $this->_columns[$columnName]['owner'];
448 | } else {
449 | return $this->getComponentName();
450 | }
451 | }
452 |
453 | /**
454 | * Checks whether a column is inherited from a component further up in the hierarchy.
455 | *
456 | * @param $columnName The column name
457 | * @return boolean TRUE if column is inherited, FALSE otherwise.
458 | */
459 | public function isInheritedColumn($columnName)
460 | {
461 | return (isset($this->_columns[$columnName]['owner']));
462 | }
463 |
464 | /**
465 | * Checks whether a field is part of the table identifier/primary key field(s).
466 | *
467 | * @param string $fieldName The field name
468 | * @return boolean TRUE if the field is part of the table identifier/primary key field(s),
469 | * FALSE otherwise.
470 | */
471 | public function isIdentifier($fieldName)
472 | {
473 | return ($fieldName === $this->getIdentifier() ||
474 | in_array($fieldName, (array) $this->getIdentifier()));
475 | }
476 |
477 | public function getMethodOwner($method)
478 | {
479 | return (isset($this->_invokedMethods[$method])) ?
480 | $this->_invokedMethods[$method] : false;
481 | }
482 |
483 | public function setMethodOwner($method, $class)
484 | {
485 | $this->_invokedMethods[$method] = $class;
486 | }
487 |
488 | /**
489 | * getTemplates
490 | * returns all templates attached to this table
491 | *
492 | * @return array an array containing all templates
493 | */
494 | public function getTemplates()
495 | {
496 | return $this->_templates;
497 | }
498 |
499 | /**
500 | * export
501 | * exports this table to database based on column and option definitions
502 | *
503 | * @throws Doctrine_Connection_Exception if some error other than Doctrine::ERR_ALREADY_EXISTS
504 | * occurred during the create table operation
505 | * @return boolean whether or not the export operation was successful
506 | * false if table already existed in the database
507 | */
508 | public function export()
509 | {
510 | $this->_conn->export->exportTable($this);
511 | }
512 |
513 | /**
514 | * getExportableFormat
515 | * returns exportable presentation of this object
516 | *
517 | * @return array
518 | */
519 | public function getExportableFormat($parseForeignKeys = true)
520 | {
521 | $columns = array();
522 | $primary = array();
523 |
524 | foreach ($this->getColumns() as $name => $definition) {
525 |
526 | if (isset($definition['owner'])) {
527 | continue;
528 | }
529 |
530 | switch ($definition['type']) {
531 | case 'enum':
532 | if (isset($definition['default'])) {
533 | $definition['default'] = $this->enumIndex($name, $definition['default']);
534 | }
535 | break;
536 | case 'boolean':
537 | if (isset($definition['default'])) {
538 | $definition['default'] = $this->getConnection()->convertBooleans($definition['default']);
539 | }
540 | break;
541 | }
542 | $columns[$name] = $definition;
543 |
544 | if (isset($definition['primary']) && $definition['primary']) {
545 | $primary[] = $name;
546 | }
547 | }
548 | $options['foreignKeys'] = array();
549 |
550 |
551 | if ($parseForeignKeys && $this->getAttribute(Doctrine::ATTR_EXPORT)
552 | & Doctrine::EXPORT_CONSTRAINTS) {
553 |
554 | $constraints = array();
555 |
556 | $emptyIntegrity = array('onUpdate' => null,
557 | 'onDelete' => null);
558 |
559 | foreach ($this->getRelations() as $name => $relation) {
560 | $fk = $relation->toArray();
561 | $fk['foreignTable'] = $relation->getTable()->getTableName();
562 |
563 | if ($relation->getTable() === $this && in_array($relation->getLocal(), $primary)) {
564 | if ($relation->hasConstraint()) {
565 | throw new Doctrine_Table_Exception("Badly constructed integrity constraints.");
566 | }
567 | continue;
568 | }
569 |
570 | $integrity = array('onUpdate' => $fk['onUpdate'],
571 | 'onDelete' => $fk['onDelete']);
572 |
573 | if ($relation instanceof Doctrine_Relation_LocalKey) {
574 | $def = array('local' => $relation->getLocal(),
575 | 'foreign' => $relation->getForeign(),
576 | 'foreignTable' => $relation->getTable()->getTableName());
577 |
578 | if (($key = array_search($def, $options['foreignKeys'])) === false) {
579 | $options['foreignKeys'][] = $def;
580 | $constraints[] = $integrity;
581 | } else {
582 | if ($integrity !== $emptyIntegrity) {
583 | $constraints[$key] = $integrity;
584 | }
585 | }
586 | }
587 | }
588 |
589 | foreach ($constraints as $k => $def) {
590 | $options['foreignKeys'][$k] = array_merge($options['foreignKeys'][$k], $def);
591 | }
592 | }
593 |
594 | $options['primary'] = $primary;
595 |
596 | return array('tableName' => $this->getOption('tableName'),
597 | 'columns' => $columns,
598 | 'options' => array_merge($this->getOptions(), $options));
599 | }
600 |
601 | /**
602 | * exportConstraints
603 | * exports the constraints of this table into database based on option definitions
604 | *
605 | * @throws Doctrine_Connection_Exception if something went wrong on db level
606 | * @return void
607 | */
608 | public function exportConstraints()
609 | {
610 | try {
611 | $this->_conn->beginTransaction();
612 |
613 | foreach ($this->_options['index'] as $index => $definition) {
614 | $this->_conn->export->createIndex($this->_options['tableName'], $index, $definition);
615 | }
616 | $this->_conn->commit();
617 | } catch (Doctrine_Connection_Exception $e) {
618 | $this->_conn->rollback();
619 | throw $e;
620 | }
621 | }
622 |
623 | /**
624 | * getRelationParser
625 | * return the relation parser associated with this table
626 | *
627 | * @return Doctrine_Relation_Parser relation parser object
628 | */
629 | public function getRelationParser()
630 | {
631 | return $this->_parser;
632 | }
633 |
634 | /**
635 | * __get
636 | * an alias for getOption
637 | *
638 | * @param string $option
639 | */
640 | public function __get($option)
641 | {
642 | if (isset($this->_options[$option])) {
643 | return $this->_options[$option];
644 | }
645 | return null;
646 | }
647 |
648 | /**
649 | * __isset
650 | *
651 | * @param string $option
652 | */
653 | public function __isset($option)
654 | {
655 | return isset($this->_options[$option]);
656 | }
657 |
658 | /**
659 | * getOptions
660 | * returns all options of this table and the associated values
661 | *
662 | * @return array all options and their values
663 | */
664 | public function getOptions()
665 | {
666 | return $this->_options;
667 | }
668 |
669 | /**
670 | * addForeignKey
671 | *
672 | * adds a foreignKey to this table
673 | *
674 | * @return void
675 | */
676 | public function addForeignKey(array $definition)
677 | {
678 | $this->_options['foreignKeys'][] = $definition;
679 | }
680 |
681 | /**
682 | * addCheckConstraint
683 | *
684 | * adds a check constraint to this table
685 | *
686 | * @return void
687 | */
688 | public function addCheckConstraint($definition, $name)
689 | {
690 | if (is_string($name)) {
691 | $this->_options['checks'][$name] = $definition;
692 | } else {
693 | $this->_options['checks'][] = $definition;
694 | }
695 |
696 | return $this;
697 | }
698 |
699 | /**
700 | * addIndex
701 | *
702 | * adds an index to this table
703 | *
704 | * @return void
705 | */
706 | public function addIndex($index, array $definition)
707 | {
708 | $this->_options['indexes'][$index] = $definition;
709 | }
710 |
711 | /**
712 | * getIndex
713 | *
714 | * @return array|boolean array on success, FALSE on failure
715 | */
716 | public function getIndex($index)
717 | {
718 | if (isset($this->_options['indexes'][$index])) {
719 | return $this->_options['indexes'][$index];
720 | }
721 |
722 | return false;
723 | }
724 |
725 | /**
726 | * DESCRIBE WHAT THIS METHOD DOES, PLEASE!
727 | *
728 | * @todo Name proposal: addRelation
729 | */
730 | public function bind($args, $type)
731 | {
732 | $options = array();
733 | $options['type'] = $type;
734 |
735 | if ( ! isset($args[1])) {
736 | $args[1] = array();
737 | }
738 |
739 | // the following is needed for backwards compatibility
740 | if (is_string($args[1])) {
741 | if ( ! isset($args[2])) {
742 | $args[2] = array();
743 | } elseif (is_string($args[2])) {
744 | $args[2] = (array) $args[2];
745 | }
746 |
747 | $classes = array_merge($this->_options['parents'], array($this->getComponentName()));
748 |
749 |
750 | $e = explode('.', $args[1]);
751 | if (in_array($e[0], $classes)) {
752 | if ($options['type'] >= Doctrine_Relation::MANY) {
753 | $options['foreign'] = $e[1];
754 | } else {
755 | $options['local'] = $e[1];
756 | }
757 | } else {
758 | $e2 = explode(' as ', $args[0]);
759 | if ($e[0] !== $e2[0] && ( ! isset($e2[1]) || $e[0] !== $e2[1])) {
760 | $options['refClass'] = $e[0];
761 | }
762 |
763 | $options['foreign'] = $e[1];
764 | }
765 |
766 | $options = array_merge($args[2], $options);
767 |
768 | $this->_parser->bind($args[0], $options);
769 | } else {
770 | $options = array_merge($args[1], $options);
771 | $this->_parser->bind($args[0], $options);
772 | }
773 | }
774 |
775 | /**
776 | * hasRelation
777 | *
778 | * @param string $alias the relation to check if exists
779 | * @return boolean true if the relation exists otherwise false
780 | */
781 | public function hasRelation($alias)
782 | {
783 | return $this->_parser->hasRelation($alias);
784 | }
785 |
786 | /**
787 | * getRelation
788 | *
789 | * @param string $alias relation alias
790 | */
791 | public function getRelation($alias, $recursive = true)
792 | {
793 | return $this->_parser->getRelation($alias, $recursive);
794 | }
795 |
796 | /**
797 | * getRelations
798 | * returns an array containing all relation objects
799 | *
800 | * @return array an array of Doctrine_Relation objects
801 | */
802 | public function getRelations()
803 | {
804 | return $this->_parser->getRelations();
805 | }
806 |
807 | /**
808 | * createQuery
809 | * creates a new Doctrine_Query object and adds the component name
810 | * of this table as the query 'from' part
811 | *
812 | * @param string Optional alias name for component aliasing.
813 | *
814 | * @return Doctrine_Query
815 | */
816 | public function createQuery($alias = '')
817 | {
818 | if ( ! empty($alias)) {
819 | $alias = ' ' . trim($alias);
820 | }
821 | return Doctrine_Query::create($this->_conn)->from($this->getComponentName() . $alias);
822 | }
823 |
824 | /**
825 | * getRepository
826 | *
827 | * @return Doctrine_Table_Repository
828 | */
829 | public function getRepository()
830 | {
831 | return $this->_repository;
832 | }
833 |
834 | /**
835 | * setOption
836 | * sets an option and returns this object in order to
837 | * allow flexible method chaining
838 | *
839 | * @see Doctrine_Table::$_options for available options
840 | * @param string $name the name of the option to set
841 | * @param mixed $value the value of the option
842 | * @return Doctrine_Table this object
843 | */
844 | public function setOption($name, $value)
845 | {
846 | switch ($name) {
847 | case 'name':
848 | case 'tableName':
849 | break;
850 | case 'enumMap':
851 | case 'inheritanceMap':
852 | case 'index':
853 | case 'treeOptions':
854 | if ( ! is_array($value)) {
855 | throw new Doctrine_Table_Exception($name . ' should be an array.');
856 | }
857 | break;
858 | }
859 | $this->_options[$name] = $value;
860 | }
861 |
862 | /**
863 | * getOption
864 | * returns the value of given option
865 | *
866 | * @param string $name the name of the option
867 | * @return mixed the value of given option
868 | */
869 | public function getOption($name)
870 | {
871 | if (isset($this->_options[$name])) {
872 | return $this->_options[$name];
873 | }
874 | return null;
875 | }
876 |
877 | /**
878 | * getColumnName
879 | *
880 | * returns a column name for column alias
881 | * if the actual name for the alias cannot be found
882 | * this method returns the given alias
883 | *
884 | * @param string $alias column alias
885 | * @return string column name
886 | */
887 | public function getColumnName($fieldName)
888 | {
889 | if (isset($this->_columnNames[$fieldName])) {
890 | return $this->_columnNames[$fieldName];
891 | }
892 | return $fieldName;
893 | }
894 |
895 | /**
896 | *
897 | *
898 | */
899 | public function getColumnDefinition($columnName)
900 | {
901 | if ( ! isset($this->_columns[$columnName])) {
902 | return false;
903 | }
904 | return $this->_columns[$columnName];
905 | }
906 |
907 | /**
908 | * getColumnAlias
909 | *
910 | * returns a column alias for a column name
911 | * if no alias can be found the column name is returned.
912 | *
913 | * @param string $columnName column name
914 | * @return string column alias
915 | */
916 | public function getFieldName($columnName)
917 | {
918 | if (isset($this->_fieldNames[$columnName])) {
919 | return $this->_fieldNames[$columnName];
920 | }
921 | return $columnName;
922 | }
923 |
924 | /**
925 | * setColumn
926 | *
927 | * @param string $name
928 | * @param string $type
929 | * @param integer $length
930 | * @param mixed $options
931 | * @param boolean $prepend Whether to prepend or append the new column to the column list.
932 | * By default the column gets appended.
933 | * @throws Doctrine_Table_Exception if trying use wrongly typed parameter
934 | * @return void
935 | */
936 | public function setColumn($name, $type, $length = null, $options = array(), $prepend = false)
937 | {
938 | if (is_string($options)) {
939 | $options = explode('|', $options);
940 | }
941 |
942 | foreach ($options as $k => $option) {
943 | if (is_numeric($k)) {
944 | if ( ! empty($option)) {
945 | $options[$option] = true;
946 | }
947 | unset($options[$k]);
948 | }
949 | }
950 |
951 | // extract column name & field name
952 | $parts = explode(' as ', $name);
953 | if (count($parts) > 1) {
954 | $fieldName = $parts[1];
955 | } else {
956 | $fieldName = $parts[0];
957 | }
958 | $name = strtolower($parts[0]);
959 | if ($prepend) {
960 | $this->_columnNames = array_merge(array($fieldName => $name), $this->_columnNames);
961 | $this->_fieldNames = array_merge(array($name => $fieldName), $this->_fieldNames);
962 | } else {
963 | $this->_columnNames[$fieldName] = $name;
964 | $this->_fieldNames[$name] = $fieldName;
965 | }
966 |
967 | if ($length == null) {
968 | switch ($type) {
969 | case 'string':
970 | case 'clob':
971 | case 'float':
972 | case 'integer':
973 | case 'array':
974 | case 'object':
975 | case 'blob':
976 | case 'gzip':
977 | // use php int max
978 | $length = 2147483647;
979 | break;
980 | case 'boolean':
981 | $length = 1;
982 | case 'date':
983 | // YYYY-MM-DD ISO 8601
984 | $length = 10;
985 | case 'time':
986 | // HH:NN:SS+00:00 ISO 8601
987 | $length = 14;
988 | case 'timestamp':
989 | // YYYY-MM-DDTHH:MM:SS+00:00 ISO 8601
990 | $length = 25;
991 | break;
992 | }
993 | }
994 |
995 | $options['type'] = $type;
996 | $options['length'] = $length;
997 |
998 | if ($prepend) {
999 | $this->_columns = array_merge(array($name => $options), $this->_columns);
1000 | } else {
1001 | $this->_columns[$name] = $options;
1002 | }
1003 |
1004 | if (isset($options['primary'])) {
1005 | if (isset($this->_identifier)) {
1006 | $this->_identifier = (array) $this->_identifier;
1007 | }
1008 | if ( ! in_array($fieldName, $this->_identifier)) {
1009 | $this->_identifier[] = $fieldName;
1010 | }
1011 | }
1012 | if (isset($options['default'])) {
1013 | $this->hasDefaultValues = true;
1014 | }
1015 | }
1016 |
1017 | /**
1018 | * hasDefaultValues
1019 | * returns true if this table has default values, otherwise false
1020 | *
1021 | * @return boolean
1022 | */
1023 | public function hasDefaultValues()
1024 | {
1025 | return $this->hasDefaultValues;
1026 | }
1027 |
1028 | /**
1029 | * getDefaultValueOf
1030 | * returns the default value(if any) for given column
1031 | *
1032 | * @param string $fieldName
1033 | * @return mixed
1034 | */
1035 | public function getDefaultValueOf($fieldName)
1036 | {
1037 | $columnName = $this->getColumnName($fieldName);
1038 | if ( ! isset($this->_columns[$columnName])) {
1039 | throw new Doctrine_Table_Exception("Couldn't get default value. Column ".$columnName." doesn't exist.");
1040 | }
1041 | if (isset($this->_columns[$columnName]['default'])) {
1042 | return $this->_columns[$columnName]['default'];
1043 | } else {
1044 | return null;
1045 | }
1046 | }
1047 |
1048 | /**
1049 | * @return mixed
1050 | */
1051 | public function getIdentifier()
1052 | {
1053 | return $this->_identifier;
1054 | }
1055 |
1056 | /**
1057 | * @return integer
1058 | */
1059 | public function getIdentifierType()
1060 | {
1061 | return $this->_identifierType;
1062 | }
1063 |
1064 | /**
1065 | * hasColumn
1066 | * @return boolean
1067 | */
1068 | public function hasColumn($columnName)
1069 | {
1070 | return isset($this->_columns[$columnName]);
1071 | }
1072 |
1073 | /**
1074 | * sets the connection for this class
1075 | *
1076 | * @params Doctrine_Connection a connection object
1077 | * @return Doctrine_Table this object
1078 | */
1079 | public function setConnection(Doctrine_Connection $conn)
1080 | {
1081 | $this->_conn = $conn;
1082 |
1083 | $this->setParent($this->_conn);
1084 |
1085 | return $this;
1086 | }
1087 |
1088 | /**
1089 | * returns the connection associated with this table (if any)
1090 | *
1091 | * @return Doctrine_Connection|null the connection object
1092 | */
1093 | public function getConnection()
1094 | {
1095 | return $this->_conn;
1096 | }
1097 |
1098 | /**
1099 | * creates a new record
1100 | *
1101 | * @param $array an array where keys are field names and
1102 | * values representing field values
1103 | * @return Doctrine_Record the created record object
1104 | */
1105 | public function create(array $array = array())
1106 | {
1107 | $record = new $this->_options['name']($this, true);
1108 | $record->fromArray($array);
1109 |
1110 | return $record;
1111 | }
1112 |
1113 | /**
1114 | * finds a record by its identifier
1115 | *
1116 | * @param $id database row id
1117 | * @param int $hydrationMode Doctrine::HYDRATE_ARRAY or Doctrine::HYDRATE_RECORD
1118 | * @return mixed Array or Doctrine_Record or false if no result
1119 | */
1120 | public function find($id, $hydrationMode = null)
1121 | {
1122 | if (is_null($id)) {
1123 | return false;
1124 | }
1125 |
1126 | $id = is_array($id) ? array_values($id) : array($id);
1127 |
1128 | return $this->createQuery()
1129 | ->where(implode(' = ? AND ', $this->getIdentifierColumnNames()) . ' = ?')
1130 | ->fetchOne($id, $hydrationMode);
1131 | }
1132 |
1133 | /**
1134 | * findAll
1135 | * returns a collection of records
1136 | *
1137 | * @param int $hydrationMode Doctrine::FETCH_ARRAY or Doctrine::FETCH_RECORD
1138 | * @return Doctrine_Collection
1139 | */
1140 | public function findAll($hydrationMode = null)
1141 | {
1142 | return $this->createQuery()->execute(array(), $hydrationMode);
1143 | }
1144 |
1145 | /**
1146 | * findByDql
1147 | * finds records with given DQL where clause
1148 | * returns a collection of records
1149 | *
1150 | * @param string $dql DQL after WHERE clause
1151 | * @param array $params query parameters
1152 | * @param int $hydrationMode Doctrine::FETCH_ARRAY or Doctrine::FETCH_RECORD
1153 | * @return Doctrine_Collection
1154 | */
1155 | public function findBySql($dql, array $params = array(), $hydrationMode = null)
1156 | {
1157 | return $this->createQuery()->where($dql)->execute($params, $hydrationMode);
1158 | }
1159 |
1160 | public function findByDql($dql, array $params = array(), $hydrationMode = null)
1161 | {
1162 | return $this->findBySql($dql, $params, $hydrationMode);
1163 | }
1164 |
1165 | /**
1166 | * execute
1167 | * fetches data using the provided queryKey and
1168 | * the associated query in the query registry
1169 | *
1170 | * if no query for given queryKey is being found a
1171 | * Doctrine_Query_Registry exception is being thrown
1172 | *
1173 | * @param string $queryKey the query key
1174 | * @param array $params prepared statement params (if any)
1175 | * @return mixed the fetched data
1176 | */
1177 | public function execute($queryKey, $params = array(), $hydrationMode = Doctrine::HYDRATE_RECORD)
1178 | {
1179 | return Doctrine_Manager::getInstance()
1180 | ->getQueryRegistry()
1181 | ->get($queryKey, $this->getComponentName())
1182 | ->execute($params, $hydrationMode);
1183 | }
1184 |
1185 | /**
1186 | * executeOne
1187 | * fetches data using the provided queryKey and
1188 | * the associated query in the query registry
1189 | *
1190 | * if no query for given queryKey is being found a
1191 | * Doctrine_Query_Registry exception is being thrown
1192 | *
1193 | * @param string $queryKey the query key
1194 | * @param array $params prepared statement params (if any)
1195 | * @return mixed the fetched data
1196 | */
1197 | public function executeOne($queryKey, $params = array(), $hydrationMode = Doctrine::HYDRATE_RECORD)
1198 | {
1199 | return Doctrine_Manager::getInstance()
1200 | ->getQueryRegistry()
1201 | ->get($queryKey, $this->getComponentName())
1202 | ->fetchOne($params, $hydrationMode);
1203 | }
1204 |
1205 | /**
1206 | * clear
1207 | * clears the first level cache (identityMap)
1208 | *
1209 | * @return void
1210 | * @todo what about a more descriptive name? clearIdentityMap?
1211 | */
1212 | public function clear()
1213 | {
1214 | $this->_identityMap = array();
1215 | }
1216 |
1217 | /**
1218 | * addRecord
1219 | * adds a record to identity map
1220 | *
1221 | * @param Doctrine_Record $record record to be added
1222 | * @return boolean
1223 | * @todo Better name? registerRecord?
1224 | */
1225 | public function addRecord(Doctrine_Record $record)
1226 | {
1227 | $id = implode(' ', $record->identifier());
1228 |
1229 | if (isset($this->_identityMap[$id])) {
1230 | return false;
1231 | }
1232 |
1233 | $this->_identityMap[$id] = $record;
1234 |
1235 | return true;
1236 | }
1237 |
1238 | /**
1239 | * removeRecord
1240 | * removes a record from the identity map, returning true if the record
1241 | * was found and removed and false if the record wasn't found.
1242 | *
1243 | * @param Doctrine_Record $record record to be removed
1244 | * @return boolean
1245 | */
1246 | public function removeRecord(Doctrine_Record $record)
1247 | {
1248 | $id = implode(' ', $record->identifier());
1249 |
1250 | if (isset($this->_identityMap[$id])) {
1251 | unset($this->_identityMap[$id]);
1252 | return true;
1253 | }
1254 |
1255 | return false;
1256 | }
1257 |
1258 | /**
1259 | * getRecord
1260 | * first checks if record exists in identityMap, if not
1261 | * returns a new record
1262 | *
1263 | * @return Doctrine_Record
1264 | */
1265 | public function getRecord()
1266 | {
1267 | if ( ! empty($this->_data)) {
1268 |
1269 | $identifierFieldNames = $this->getIdentifier();
1270 |
1271 | if ( ! is_array($identifierFieldNames)) {
1272 | $identifierFieldNames = array($identifierFieldNames);
1273 | }
1274 |
1275 | $found = false;
1276 | foreach ($identifierFieldNames as $fieldName) {
1277 | if ( ! isset($this->_data[$fieldName])) {
1278 | // primary key column not found return new record
1279 | $found = true;
1280 | break;
1281 | }
1282 | $id[] = $this->_data[$fieldName];
1283 | }
1284 |
1285 | if ($found) {
1286 | $recordName = $this->getClassnameToReturn();
1287 | $record = new $recordName($this, true);
1288 | $this->_data = array();
1289 | return $record;
1290 | }
1291 |
1292 |
1293 | $id = implode(' ', $id);
1294 |
1295 | if (isset($this->_identityMap[$id])) {
1296 | $record = $this->_identityMap[$id];
1297 | $record->hydrate($this->_data);
1298 | } else {
1299 | $recordName = $this->getClassnameToReturn();
1300 | $record = new $recordName($this);
1301 | $this->_identityMap[$id] = $record;
1302 | }
1303 | $this->_data = array();
1304 | } else {
1305 | $recordName = $this->getClassnameToReturn();
1306 | $record = new $recordName($this, true);
1307 | }
1308 |
1309 | return $record;
1310 | }
1311 |
1312 | /**
1313 | * Get the classname to return. Most often this is just the options['name']
1314 | *
1315 | * Check the subclasses option and the inheritanceMap for each subclass to see
1316 | * if all the maps in a subclass is met. If this is the case return that
1317 | * subclass name. If no subclasses match or if there are no subclasses defined
1318 | * return the name of the class for this tables record.
1319 | *
1320 | * @todo this function could use reflection to check the first time it runs
1321 | * if the subclassing option is not set.
1322 | *
1323 | * @return string The name of the class to create
1324 | *
1325 | */
1326 | public function getClassnameToReturn()
1327 | {
1328 | if ( ! isset($this->_options['subclasses'])) {
1329 | return $this->_options['name'];
1330 | }
1331 | foreach ($this->_options['subclasses'] as $subclass) {
1332 | $table = $this->_conn->getTable($subclass);
1333 | $inheritanceMap = $table->getOption('inheritanceMap');
1334 | $nomatch = false;
1335 | foreach ($inheritanceMap as $key => $value) {
1336 | if ( ! isset($this->_data[$key]) || $this->_data[$key] != $value) {
1337 | $nomatch = true;
1338 | break;
1339 | }
1340 | }
1341 | if ( ! $nomatch) {
1342 | return $table->getComponentName();
1343 | }
1344 | }
1345 | return $this->_options['name'];
1346 | }
1347 |
1348 | /**
1349 | * @param $id database row id
1350 | * @throws Doctrine_Find_Exception
1351 | */
1352 | final public function getProxy($id = null)
1353 | {
1354 | if ($id !== null) {
1355 | $identifierColumnNames = $this->getIdentifierColumnNames();
1356 | $query = 'SELECT ' . implode(', ', (array) $identifierColumnNames)
1357 | . ' FROM ' . $this->getTableName()
1358 | . ' WHERE ' . implode(' = ? && ', (array) $identifierColumnNames) . ' = ?';
1359 | $query = $this->applyInheritance($query);
1360 |
1361 | $params = array_merge(array($id), array_values($this->_options['inheritanceMap']));
1362 |
1363 | $this->_data = $this->_conn->execute($query, $params)->fetch(PDO::FETCH_ASSOC);
1364 |
1365 | if ($this->_data === false)
1366 | return false;
1367 | }
1368 | return $this->getRecord();
1369 | }
1370 |
1371 | /**
1372 | * applyInheritance
1373 | * @param $where query where part to be modified
1374 | * @return string query where part with column aggregation inheritance added
1375 | */
1376 | final public function applyInheritance($where)
1377 | {
1378 | if ( ! empty($this->_options['inheritanceMap'])) {
1379 | $a = array();
1380 | foreach ($this->_options['inheritanceMap'] as $field => $value) {
1381 | $a[] = $this->getColumnName($field) . ' = ?';
1382 | }
1383 | $i = implode(' AND ', $a);
1384 | $where .= ' AND ' . $i;
1385 | }
1386 | return $where;
1387 | }
1388 |
1389 | /**
1390 | * count
1391 | *
1392 | * @return integer
1393 | */
1394 | public function count()
1395 | {
1396 | $a = $this->_conn->execute('SELECT COUNT(1) FROM ' . $this->_options['tableName'])->fetch(Doctrine::FETCH_NUM);
1397 | return current($a);
1398 | }
1399 |
1400 | /**
1401 | * @return Doctrine_Query a Doctrine_Query object
1402 | */
1403 | public function getQueryObject()
1404 | {
1405 | $graph = new Doctrine_Query($this->getConnection());
1406 | $graph->load($this->getComponentName());
1407 | return $graph;
1408 | }
1409 |
1410 | /**
1411 | * @param string $fieldName
1412 | * @return array
1413 | */
1414 | public function getEnumValues($fieldName)
1415 | {
1416 | $columnName = $this->getColumnName($fieldName);
1417 | if (isset($this->_columns[$columnName]['values'])) {
1418 | return $this->_columns[$columnName]['values'];
1419 | } else {
1420 | return array();
1421 | }
1422 | }
1423 |
1424 | /**
1425 | * enumValue
1426 | *
1427 | * @param string $field
1428 | * @param integer $index
1429 | * @return mixed
1430 | */
1431 | public function enumValue($fieldName, $index)
1432 | {
1433 | if ($index instanceof Doctrine_Null) {
1434 | return $index;
1435 | }
1436 |
1437 | $columnName = $this->getColumnName($fieldName);
1438 | if ( ! $this->_conn->getAttribute(Doctrine::ATTR_USE_NATIVE_ENUM)
1439 | && isset($this->_columns[$columnName]['values'][$index])
1440 | ) {
1441 | return $this->_columns[$columnName]['values'][$index];
1442 | }
1443 |
1444 | return $index;
1445 | }
1446 |
1447 | /**
1448 | * enumIndex
1449 | *
1450 | * @param string $field
1451 | * @param mixed $value
1452 | * @return mixed
1453 | */
1454 | public function enumIndex($fieldName, $value)
1455 | {
1456 | $values = $this->getEnumValues($fieldName);
1457 |
1458 | $index = array_search($value, $values);
1459 | if ($index === false || !$this->_conn->getAttribute(Doctrine::ATTR_USE_NATIVE_ENUM)) {
1460 | return $index;
1461 | }
1462 | return $value;
1463 | }
1464 |
1465 | /**
1466 | * getColumnCount
1467 | *
1468 | * @return integer the number of columns in this table
1469 | */
1470 | public function getColumnCount()
1471 | {
1472 | return $this->columnCount;
1473 | }
1474 |
1475 | /**
1476 | * returns all columns and their definitions
1477 | *
1478 | * @return array
1479 | */
1480 | public function getColumns()
1481 | {
1482 | return $this->_columns;
1483 | }
1484 |
1485 | /**
1486 | * removeColumn
1487 | * removes given column
1488 | *
1489 | * @return boolean
1490 | */
1491 | public function removeColumn($fieldName)
1492 | {
1493 | $columnName = array_search($fieldName, $this->_fieldNames);
1494 |
1495 | unset($this->_fieldNames[$columnName]);
1496 |
1497 | if (isset($this->_columns[$columnName])) {
1498 | unset($this->_columns[$columnName]);
1499 | return true;
1500 | }
1501 | $this->columnCount--;
1502 |
1503 | return false;
1504 | }
1505 |
1506 | /**
1507 | * returns an array containing all the column names.
1508 | *
1509 | * @return array
1510 | */
1511 | public function getColumnNames(array $fieldNames = null)
1512 | {
1513 | if ($fieldNames === null) {
1514 | return array_keys($this->_columns);
1515 | } else {
1516 | $columnNames = array();
1517 | foreach ($fieldNames as $fieldName) {
1518 | $columnNames[] = $this->getColumnName($fieldName);
1519 | }
1520 | return $columnNames;
1521 | }
1522 | }
1523 |
1524 | /**
1525 | * returns an array with all the identifier column names.
1526 | *
1527 | * @return array
1528 | */
1529 | public function getIdentifierColumnNames()
1530 | {
1531 | return $this->getColumnNames((array) $this->getIdentifier());
1532 | }
1533 |
1534 | /**
1535 | * returns an array containing all the field names.
1536 | *
1537 | * @return array
1538 | */
1539 | public function getFieldNames()
1540 | {
1541 | return array_values($this->_fieldNames);
1542 | }
1543 |
1544 | /**
1545 | * getDefinitionOf
1546 | *
1547 | * @return mixed array on success, false on failure
1548 | */
1549 | public function getDefinitionOf($fieldName)
1550 | {
1551 | $columnName = $this->getColumnName($fieldName);
1552 | return $this->getColumnDefinition($columnName);
1553 | }
1554 |
1555 | /**
1556 | * getTypeOf
1557 | *
1558 | * @return mixed string on success, false on failure
1559 | */
1560 | public function getTypeOf($fieldName)
1561 | {
1562 | $columnName = $this->getColumnName($fieldName);
1563 | if (isset($this->_columns[$columnName])) {
1564 | return $this->_columns[$columnName]['type'];
1565 | }
1566 | return false;
1567 | }
1568 |
1569 | /**
1570 | * setData
1571 | * doctrine uses this function internally
1572 | * users are strongly discouraged to use this function
1573 | *
1574 | * @param array $data internal data
1575 | * @return void
1576 | */
1577 | public function setData(array $data)
1578 | {
1579 | $this->_data = $data;
1580 | }
1581 |
1582 | /**
1583 | * returns internal data, used by Doctrine_Record instances
1584 | * when retrieving data from database
1585 | *
1586 | * @return array
1587 | */
1588 | public function getData()
1589 | {
1590 | return $this->_data;
1591 | }
1592 |
1593 | /**
1594 | * prepareValue
1595 | * this method performs special data preparation depending on
1596 | * the type of the given column
1597 | *
1598 | * 1. It unserializes array and object typed columns
1599 | * 2. Uncompresses gzip typed columns
1600 | * 3. Gets the appropriate enum values for enum typed columns
1601 | * 4. Initializes special null object pointer for null values (for fast column existence checking purposes)
1602 | *
1603 | * example:
1604 | * <code type='php'>
1605 | * $field = 'name';
1606 | * $value = null;
1607 | * $table->prepareValue($field, $value); // Doctrine_Null
1608 | * </code>
1609 | *
1610 | * @throws Doctrine_Table_Exception if unserialization of array/object typed column fails or
1611 | * @throws Doctrine_Table_Exception if uncompression of gzip typed column fails *
1612 | * @param string $field the name of the field
1613 | * @param string $value field value
1614 | * @return mixed prepared value
1615 | */
1616 | public function prepareValue($fieldName, $value)
1617 | {
1618 | if ($value === self::$_null) {
1619 | return self::$_null;
1620 | } else if ($value === null) {
1621 | return null;
1622 | } else {
1623 | $type = $this->getTypeOf($fieldName);
1624 |
1625 | switch ($type) {
1626 | case 'array':
1627 | case 'object':
1628 | if (is_string($value)) {
1629 | $value = unserialize($value);
1630 |
1631 | if ($value === false) {
1632 | throw new Doctrine_Table_Exception('Unserialization of ' . $fieldName . ' failed.');
1633 | }
1634 | return $value;
1635 | }
1636 | break;
1637 | case 'gzip':
1638 | $value = gzuncompress($value);
1639 |
1640 | if ($value === false) {
1641 | throw new Doctrine_Table_Exception('Uncompressing of ' . $fieldName . ' failed.');
1642 | }
1643 | return $value;
1644 | break;
1645 | case 'enum':
1646 | return $this->enumValue($fieldName, $value);
1647 | break;
1648 | case 'boolean':
1649 | return (boolean) $value;
1650 | break;
1651 | case 'integer':
1652 | // don't do any casting here PHP INT_MAX is smaller than what the databases support
1653 | break;
1654 | }
1655 | }
1656 | return $value;
1657 | }
1658 |
1659 | /**
1660 | * getTree
1661 | *
1662 | * getter for associated tree
1663 | *
1664 | * @return mixed if tree return instance of Doctrine_Tree, otherwise returns false
1665 | */
1666 | public function getTree()
1667 | {
1668 | if (isset($this->_options['treeImpl'])) {
1669 | if ( ! $this->_tree) {
1670 | $options = isset($this->_options['treeOptions']) ? $this->_options['treeOptions'] : array();
1671 | $this->_tree = Doctrine_Tree::factory($this,
1672 | $this->_options['treeImpl'],
1673 | $options
1674 | );
1675 | }
1676 | return $this->_tree;
1677 | }
1678 | return false;
1679 | }
1680 |
1681 | /**
1682 | * getComponentName
1683 | *
1684 | * @return void
1685 | */
1686 | public function getComponentName()
1687 | {
1688 | return $this->_options['name'];
1689 | }
1690 |
1691 | /**
1692 | * getTableName
1693 | *
1694 | * @return void
1695 | */
1696 | public function getTableName()
1697 | {
1698 | return $this->_options['tableName'];
1699 | }
1700 |
1701 | /**
1702 | * setTableName
1703 | *
1704 | * @param string $tableName
1705 | * @return void
1706 | */
1707 | public function setTableName($tableName)
1708 | {
1709 | $this->setOption('tableName', $this->_conn->formatter->getTableName($tableName));
1710 | }
1711 |
1712 | /**
1713 | * isTree
1714 | *
1715 | * determine if table acts as tree
1716 | *
1717 | * @return mixed if tree return true, otherwise returns false
1718 | */
1719 | public function isTree()
1720 | {
1721 | return ( ! is_null($this->_options['treeImpl'])) ? true : false;
1722 | }
1723 |
1724 | /**
1725 | * getTemplate
1726 | *
1727 | * @param string $template
1728 | * @return void
1729 | */
1730 | public function getTemplate($template)
1731 | {
1732 | if ( ! isset($this->_templates[$template])) {
1733 | throw new Doctrine_Table_Exception('Template ' . $template . ' not loaded');
1734 | }
1735 |
1736 | return $this->_templates[$template];
1737 | }
1738 |
1739 | public function hasTemplate($template)
1740 | {
1741 | return isset($this->_templates[$template]);
1742 | }
1743 |
1744 | public function addTemplate($template, Doctrine_Template $impl)
1745 | {
1746 | $this->_templates[$template] = $impl;
1747 |
1748 | return $this;
1749 | }
1750 |
1751 | /**
1752 | * bindQueryParts
1753 | * binds query parts to given component
1754 | *
1755 | * @param array $queryParts an array of pre-bound query parts
1756 | * @return Doctrine_Record this object
1757 | */
1758 | public function bindQueryParts(array $queryParts)
1759 | {
1760 | $this->_options['queryParts'] = $queryParts;
1761 |
1762 | return $this;
1763 | }
1764 |
1765 | /**
1766 | * bindQueryPart
1767 | * binds given value to given query part
1768 | *
1769 | * @param string $queryPart
1770 | * @param mixed $value
1771 | * @return Doctrine_Record this object
1772 | */
1773 | public function bindQueryPart($queryPart, $value)
1774 | {
1775 | $this->_options['queryParts'][$queryPart] = $value;
1776 |
1777 | return $this;
1778 | }
1779 |
1780 | /**
1781 | * getBoundQueryPart
1782 | *
1783 | * @param string $queryPart
1784 | * @return string $queryPart
1785 | */
1786 | public function getBoundQueryPart($queryPart)
1787 | {
1788 | if ( ! isset($this->_options['queryParts'][$queryPart])) {
1789 | return null;
1790 | }
1791 |
1792 | return $this->_options['queryParts'][$queryPart];
1793 | }
1794 |
1795 | /**
1796 | * unshiftFilter
1797 | *
1798 | * @param object Doctrine_Record_Filter $filter
1799 | * @return object $this
1800 | */
1801 | public function unshiftFilter(Doctrine_Record_Filter $filter)
1802 | {
1803 | $filter->setTable($this);
1804 |
1805 | $filter->init();
1806 |
1807 | array_unshift($this->_filters, $filter);
1808 |
1809 | return $this;
1810 | }
1811 |
1812 | /**
1813 | * getFilters
1814 | *
1815 | * @return array $filters
1816 | */
1817 | public function getFilters()
1818 | {
1819 | return $this->_filters;
1820 | }
1821 |
1822 | /**
1823 | * returns a string representation of this object
1824 | *
1825 | * @return string
1826 | */
1827 | public function __toString()
1828 | {
1829 | return Doctrine_Lib::getTableAsString($this);
1830 | }
1831 |
1832 | /**
1833 | * findBy
1834 | *
1835 | * @param string $column
1836 | * @param string $value
1837 | * @param string $hydrationMode
1838 | * @return void
1839 | */
1840 | protected function findBy($fieldName, $value, $hydrationMode = null)
1841 | {
1842 | return $this->createQuery()->where($fieldName . ' = ?')->execute(array($value), $hydrationMode);
1843 | }
1844 |
1845 | /**
1846 | * findOneBy
1847 | *
1848 | * @param string $column
1849 | * @param string $value
1850 | * @param string $hydrationMode
1851 | * @return void
1852 | */
1853 | protected function findOneBy($fieldName, $value, $hydrationMode = null)
1854 | {
1855 | $results = $this->createQuery()->where($fieldName . ' = ?')->limit(1)->execute(array($value), $hydrationMode);
1856 |
1857 | return $hydrationMode === Doctrine::FETCH_ARRAY ? $results[0] : $results->getFirst();
1858 | }
1859 |
1860 | /**
1861 | * __call
1862 | *
1863 | * Adds support for magic finders.
1864 | * findByColumnName, findByRelationAlias
1865 | * findById, findByContactId, etc.
1866 | *
1867 | * @return void
1868 | */
1869 | public function __call($method, $arguments)
1870 | {
1871 | if (substr($method, 0, 6) == 'findBy') {
1872 | $by = substr($method, 6, strlen($method));
1873 | $method = 'findBy';
1874 | } else if (substr($method, 0, 9) == 'findOneBy') {
1875 | $by = substr($method, 9, strlen($method));
1876 | $method = 'findOneBy';
1877 | }
1878 |
1879 | if (isset($by)) {
1880 | if ( ! isset($arguments[0])) {
1881 | throw new Doctrine_Table_Exception('You must specify the value to findBy');
1882 | }
1883 |
1884 | $fieldName = Doctrine::tableize($by);
1885 | $hydrationMode = isset($arguments[1]) ? $arguments[1]:null;
1886 |
1887 | if ($this->hasColumn($fieldName)) {
1888 | return $this->$method($fieldName, $arguments[0], $hydrationMode);
1889 | } else if ($this->hasRelation($by)) {
1890 | $relation = $this->getRelation($by);
1891 |
1892 | if ($relation['type'] === Doctrine_Relation::MANY) {
1893 | throw new Doctrine_Table_Exception('Cannot findBy many relationship.');
1894 | }
1895 |
1896 | return $this->$method($relation['local'], $arguments[0], $hydrationMode);
1897 | } else {
1898 | throw new Doctrine_Table_Exception('Cannot find by: ' . $by . '. Invalid column or relationship alias.');
1899 | }
1900 | }
1901 | }
1902 | }