Changeset 4699
- Timestamp:
- 07/20/08 21:13:24 (6 months ago)
- Location:
- trunk
- Files:
-
- 17 added
- 1 removed
- 26 modified
-
lib/Doctrine/Association (added)
-
lib/Doctrine/Association.php (added)
-
lib/Doctrine/Association/ManyToMany.php (added)
-
lib/Doctrine/Association/OneToMany.php (added)
-
lib/Doctrine/Association/OneToOne.php (added)
-
lib/Doctrine/ClassMetadata.php (modified) (46 diffs)
-
lib/Doctrine/ClassMetadata/Factory.php (modified) (13 diffs)
-
lib/Doctrine/Collection.php (modified) (40 diffs)
-
lib/Doctrine/Connection.php (modified) (12 diffs)
-
lib/Doctrine/Connection/UnitOfWork.php (modified) (15 diffs)
-
lib/Doctrine/Entity.php (modified) (18 diffs)
-
lib/Doctrine/EntityManager.php (modified) (9 diffs)
-
lib/Doctrine/EventListener.php (deleted)
-
lib/Doctrine/EventSubscriber.php (added)
-
lib/Doctrine/Exception.php (modified) (1 diff)
-
lib/Doctrine/Hydrator/RecordDriver.php (modified) (1 diff)
-
lib/Doctrine/HydratorNew.php (modified) (3 diffs)
-
lib/Doctrine/Internal (added)
-
lib/Doctrine/Internal/CommitOrderCalculator.php (added)
-
lib/Doctrine/Internal/CommitOrderNode.php (added)
-
lib/Doctrine/MappingException.php (modified) (1 diff)
-
lib/Doctrine/Overloadable.php (modified) (1 diff)
-
lib/Doctrine/Tree.php (modified) (1 diff)
-
lib/Doctrine/Validator.php (modified) (1 diff)
-
tests/lib/mocks/Doctrine_ConnectionMock.php (added)
-
tests/lib/mocks/Doctrine_EntityManagerMock.php (added)
-
tests/lib/mocks/Doctrine_EntityPersisterMock.php (added)
-
tests/lib/mocks/Doctrine_SequenceMock.php (added)
-
tests/models/cms/CmsArticle.php (modified) (1 diff)
-
tests/models/cms/CmsComment.php (modified) (1 diff)
-
tests/models/cms/CmsPhonenumber.php (modified) (1 diff)
-
tests/models/cms/CmsUser.php (modified) (1 diff)
-
tests/models/forum/ForumAdministrator.php (modified) (1 diff)
-
tests/models/forum/ForumBoard.php (modified) (2 diffs)
-
tests/models/forum/ForumCategory.php (modified) (1 diff)
-
tests/models/forum/ForumEntry.php (added)
-
tests/models/forum/ForumUser.php (modified) (2 diffs)
-
tests/Orm/Associations (added)
-
tests/Orm/Associations/CascadeTest.php (added)
-
tests/Orm/Associations/OneToOneMappingTest.php (added)
-
tests/Orm/Component/CollectionTest.php (modified) (3 diffs)
-
tests/Orm/Entity/AccessorTest.php (modified) (2 diffs)
-
tests/Orm/Entity/ConstructorTest.php (modified) (1 diff)
-
tests/Orm/UnitOfWorkTest.php (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/lib/Doctrine/ClassMetadata.php
r4655 r4699 22 22 #namespace Doctrine::ORM::Mapping; 23 23 24 #use Doctrine::ORM::EntityManager; 25 24 26 /** 25 27 * A <tt>ClassMetadata</tt> instance holds all the information (metadata) of an entity and … … 29 31 * @author Roman Borschel <roman@code-factory.org> 30 32 * @since 2.0 33 * @todo Rename to ClassDescriptor? 31 34 */ 32 35 class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable 33 36 { 34 /** 35 * The name of the entity class that is mapped to the database with this metadata. 37 /* The inheritance mapping types */ 38 const INHERITANCE_TYPE_NONE = 'none'; 39 const INHERITANCE_TYPE_JOINED = 'joined'; 40 const INHERITANCE_TYPE_SINGLE_TABLE = 'singleTable'; 41 const INHERITANCE_TYPE_TABLE_PER_CLASS = 'tablePerClass'; 42 43 /** 44 * Inheritance types enumeration. 45 * 46 * @var array 47 */ 48 protected static $_inheritanceTypes = array( 49 self::INHERITANCE_TYPE_NONE, 50 self::INHERITANCE_TYPE_JOINED, 51 self::INHERITANCE_TYPE_SINGLE_TABLE, 52 self::INHERITANCE_TYPE_TABLE_PER_CLASS 53 ); 54 55 /* The Id generator types. TODO: belongs more in a DBAL class */ 56 const GENERATOR_TYPE_AUTO = 'auto'; 57 const GENERATOR_TYPE_SEQUENCE = 'sequence'; 58 const GENERATOR_TYPE_TABLE = 'table'; 59 const GENERATOR_TYPE_IDENTITY = 'identity'; 60 const GENERATOR_TYPE_NONE = 'none'; 61 62 /** 63 * Id Generator types enumeration. 64 * 65 * @var array 66 */ 67 protected static $_generatorTypes = array( 68 self::GENERATOR_TYPE_AUTO, 69 self::GENERATOR_TYPE_SEQUENCE, 70 self::GENERATOR_TYPE_TABLE, 71 self::GENERATOR_TYPE_IDENTITY, 72 self::GENERATOR_TYPE_NONE 73 ); 74 75 /** 76 * The name of the entity class. 36 77 * 37 78 * @var string … … 42 83 * The name of the entity class that is at the root of the entity inheritance 43 84 * hierarchy. If the entity is not part of an inheritance hierarchy this is the same 44 * as the$_entityName.85 * as $_entityName. 45 86 * 46 87 * @var string … … 57 98 58 99 /** 59 * 60 * @var Doctrine_Connection 100 * The EntityManager. 101 * 102 * @var Doctrine::ORM::EntityManager 61 103 */ 62 104 protected $_em; … … 64 106 /** 65 107 * The names of the parent classes (ancestors). 108 * 109 * @var array 66 110 */ 67 111 protected $_parentClasses = array(); 68 112 69 113 /** 70 * The names of all subclasses 114 * The names of all subclasses. 115 * 116 * @var array 71 117 */ 72 118 protected $_subClasses = array(); … … 79 125 */ 80 126 protected $_identifier = array(); 81 82 /** 83 * The identifier type of the class. 84 * 85 * @see Doctrine::IDENTIFIER_* constants 127 128 /** 129 * The inheritance mapping type used by the class. 130 * 86 131 * @var integer 87 132 */ 88 protected $_identifierType; 89 90 /** 91 * The inheritance mapping type used by the class. 92 * 93 * 94 * @var integer 95 */ 96 protected $_inheritanceType = Doctrine::INHERITANCE_TYPE_NONE; 133 protected $_inheritanceType = self::INHERITANCE_TYPE_NONE; 134 135 /** 136 * The Id generator type used by the class. 137 * 138 * @var string 139 */ 140 protected $_generatorType = self::GENERATOR_TYPE_NONE; 97 141 98 142 /** … … 103 147 * @todo Unify under 'Behaviors'. 104 148 */ 105 protected $_behaviors = array(); 106 107 /** 108 * An array containing all behavior generators attached to the class. 109 * 110 * @see Doctrine_Record_Generator 111 * @var array $_generators 112 * @todo Unify under 'Behaviors'. 113 */ 114 protected $_generators = array(); 115 149 //protected $_behaviors = array(); 150 116 151 /** 117 152 * The field mappings of the class. 118 153 * Keys are field names and values are mapping definitions. 119 154 * 120 * The mapping definition array has at least the following values: 121 * 122 * -- type the column type, eg. 'integer' 123 * -- length the column length, eg. 11 124 * 125 * additional keys: 126 * -- notnull whether or not the column is marked as notnull 127 * -- values enum values 128 * ... many more 155 * The mapping definition array has the following values: 156 * 157 * - <b>fieldName</b> (string) 158 * The name of the field in the Entity. 159 * 160 * - <b>type</b> (string) 161 * The database type of the column. Can be one of Doctrine's portable types. 162 * 163 * - <b>columnName</b> (string, optional) 164 * The column name. Optional. Defaults to the field name. 165 * 166 * - <b>length</b> (integer, optional) 167 * The database length of the column. Optional. Defaults to Doctrine's 168 * default values for the portable types. 169 * 170 * - <b>id</b> (boolean, optional) 171 * Marks the field as the primary key of the Entity. Multiple fields of an 172 * entity can have the id attribute, forming a composite key. 173 * 174 * - <b>generatorType</b> (string, optional, requires: id) 175 * The generation type used for the field. Optional. Can only be applied on 176 * fields that are marked with the 'id' attribute. The possible values are: 177 * auto, identity, sequence, table. 178 * 179 * - <b>generator</b> (array, optional, requires: generationType=table|sequence) 180 * The generator options for a table or sequence generator. Can only be applied 181 * on fields that have a generationType of 'table' or 'sequence'. 182 * 183 * - <b>nullable</b> (boolean, optional) 184 * Whether the column is nullable. Defaults to TRUE. 185 * 186 * - <b>columnDefinition</b> (string, optional) 187 * The SQL fragment that is used when generating the DDL for the column. 188 * 189 * - <b>precision</b> (integer, optional) 190 * The precision of a decimal column. Only valid if the column type is decimal. 191 * 192 * - <b>scale</b> (integer, optional) 193 * The scale of a decimal column. Only valid if the column type is decimal. 129 194 * 130 195 * @var array … … 138 203 * @TODO Implementation (Value Object support) 139 204 */ 140 protected $_mappedEmbeddedValues = array();205 //protected $_embeddedValueMappings = array(); 141 206 142 207 /** … … 182 247 183 248 /** 184 * Caches enum value mappings. Keys are field names and values arrays with the185 * mapping.186 */187 protected $_enumValues = array();188 189 /**190 * Tree object associated with the class.191 *192 * @var Doctrine_Tree193 * @todo Belongs to the NestedSet Behavior plugin.194 */195 protected $_tree;196 197 /**198 * Cached column count, Doctrine_Entity uses this column count when199 * determining its state.200 *201 * @var integer202 */203 //protected $_columnCount;204 205 /**206 * Whether or not this class has default values.207 *208 * @var boolean209 */210 protected $_hasDefaultValues;211 212 /**213 249 * Relation parser object. Manages the relations for the class. 214 250 * 215 251 * @var Doctrine_Relation_Parser $_parser 252 * @todo Remove. 216 253 */ 217 254 protected $_parser; 218 219 /**220 * Enum value arrays.221 */222 protected $_enumMap = array();223 224 /**225 * @var array $options an array containing all options226 *227 * -- treeImpl the tree implementation of this table (if any)228 *229 * -- treeOptions the tree options230 *231 * -- queryParts the bound query parts232 */233 protected $_options = array(234 'treeImpl' => null,235 'treeOptions' => null,236 'queryParts' => array()237 );238 255 239 256 /** … … 277 294 'checks' => array() 278 295 ); 279 280 /**281 * @var array $_invokedMethods method invoker cache282 */283 protected $_invokedMethods = array();284 296 285 297 /** … … 305 317 protected $_lifecycleListeners = array(); 306 318 319 /** 320 * The association mappings. 321 * 322 * @var array 323 */ 324 protected $_associationMappings = array(); 325 326 /** 327 * Flag indicating whether the identifier/primary key of the class is composite. 328 * 329 * @var boolean 330 */ 331 protected $_isIdentifierComposite = false; 307 332 308 333 /** … … 316 341 $this->_rootEntityName = $entityName; 317 342 $this->_em = $em; 343 318 344 $this->_parser = new Doctrine_Relation_Parser($this); 319 345 } 320 346 321 347 /** 322 * 348 * @deprecated 323 349 */ 324 350 public function getConnection() … … 371 397 public function isIdentifier($fieldName) 372 398 { 373 if ( $this->_identifierType != Doctrine::IDENTIFIER_COMPOSITE) {399 if ( ! $this->_isIdentifierComposite) { 374 400 return $fieldName === $this->_identifier[0]; 375 401 } … … 378 404 379 405 /** 380 * Check if the field is unique406 * Check if the class has a composite identifier. 381 407 * 382 408 * @param string $fieldName The field name 383 * @return boolean TRUE if the field is unique, FALSE otherwise.409 * @return boolean TRUE if the identifier is composite, FALSE otherwise. 384 410 */ 385 411 public function isIdentifierComposite() 386 412 { 387 return $this->_i dentifierType == Doctrine::IDENTIFIER_COMPOSITE;413 return $this->_isIdentifierComposite; 388 414 } 389 415 … … 491 517 } 492 518 493 public function getBehaviorForMethod($method)519 /*public function getBehaviorForMethod($method) 494 520 { 495 521 return (isset($this->_invokedMethods[$method])) ? … … 499 525 { 500 526 $this->_invokedMethods[$method] = $class; 501 } 502 503 /** 504 * getOption 527 }*/ 528 529 /** 505 530 * returns the value of given option 506 531 * … … 563 588 public function getFieldMapping($fieldName) 564 589 { 565 return isset($this->_fieldMappings[$fieldName]) ? 566 $this->_fieldMappings[$fieldName] : false; 590 if ( ! isset($this->_fieldMappings[$fieldName])) { 591 throw Doctrine_MappingException::mappingNotFound($fieldName); 592 } 593 594 return $this->_fieldMappings[$fieldName]; 567 595 } 568 596 … … 576 604 public function getAssociationMapping($fieldName) 577 605 { 578 //... 606 if ( ! isset($this->_associationMappings[$fieldName])) { 607 throw Doctrine_MappingException::mappingNotFound($fieldName); 608 } 609 610 return $this->_associationMappings[$fieldName]; 611 } 612 613 /** 614 * Gets all association mappings of the class. 615 * 616 * @return array 617 */ 618 public function getAssociationMappings() 619 { 620 return $this->_associationMappings; 579 621 } 580 622 … … 627 669 * 628 670 * @return string The field name. 629 * @throws Doctrine::ORM::Exceptions::ClassMetadataException if the field name could671 * @throws Doctrine::ORM::Exceptions::ClassMetadataException If the field name could 630 672 * not be found. 631 673 */ … … 650 692 throw new Doctrine_ClassMetadata_Exception("No field name found for column name '$lcColumnName' during lookup."); 651 693 } 652 653 /** 654 * Maps a field of the class to a database column. 655 * 656 * @param string $name The name of the column to map. Syntax: columnName [as propertyName]. 657 * The property name is optional. If not used the column will be 658 * mapped to a property with the same name. 659 * @param string $type The type of the column. 660 * @param integer $length The length of the column. 661 * @param mixed $options 662 * @param boolean $prepend Whether to prepend or append the new column to the column list. 663 * By default the column gets appended. 664 * 665 * @throws Doctrine_ClassMetadata_Exception If trying use wrongly typed parameter. 666 * @todo Rename to mapField()/addFieldMapping(). 667 */ 668 public function mapColumn($name, $type, $length = null, $options = array()) 669 { 670 // converts 0 => 'primary' to 'primary' => true etc. 671 foreach ($options as $k => $option) { 672 if (is_numeric($k)) { 673 if ( ! empty($option) && $option !== false) { 674 $options[$option] = true; 694 695 /** 696 * Adds a field mapping. 697 * 698 * @param array $mapping 699 */ 700 public function mapField(array $mapping) 701 { 702 $mapping = $this->_validateAndCompleteFieldMapping($mapping); 703 if (isset($this->_fieldMappings[$mapping['fieldName']])) { 704 throw Doctrine_MappingException::duplicateFieldMapping(); 705 } 706 $this->_fieldMappings[$mapping['fieldName']] = $mapping; 707 } 708 709 /** 710 * Overrides an existant field mapping. 711 * Used i.e. by Entity classes deriving from another Entity class that acts 712 * as a mapped superclass to refine the basic mapping. 713 * 714 * @param array $newMapping 715 * @todo Implementation. 716 */ 717 public function overrideFieldMapping(array $newMapping) 718 { 719 //... 720 } 721 722 /** 723 * Validates & completes the field mapping. Default values are applied here. 724 * 725 * @param array $mapping 726 * @return array 727 */ 728 private function _validateAndCompleteFieldMapping(array $mapping) 729 { 730 // Check mandatory fields 731 if ( ! isset($mapping['fieldName'])) { 732 throw Doctrine_MappingException::missingFieldName(); 733 } 734 if ( ! isset($mapping['type'])) { 735 throw Doctrine_MappingException::missingType(); 736 } 737 738 // Complete fieldName and columnName mapping 739 if ( ! isset($mapping['columnName'])) { 740 $mapping['columnName'] = $mapping['fieldName']; 741 } 742 $lcColumnName = strtolower($mapping['columnName']); 743 744 $this->_columnNames[$mapping['fieldName']] = $mapping['columnName']; 745 $this->_fieldNames[$mapping['columnName']] = $mapping['fieldName']; 746 $this->_lcColumnToFieldNames[$lcColumnName] = $mapping['fieldName']; 747 748 // Complete length mapping 749 if ( ! isset($mapping['length'])) { 750 $mapping['length'] = $this->_getDefaultLength($mapping['type']); 751 } 752 753 // Complete id mapping 754 if (isset($mapping['id']) && $mapping['id'] === true) { 755 if ( ! in_array($mapping['fieldName'], $this->_identifier)) { 756 $this->_identifier[] = $mapping['fieldName']; 757 } 758 if (isset($mapping['generatorType'])) { 759 if ( ! in_array($mapping['generatorType'], self::$_generatorTypes)) { 760 throw Doctrine_MappingException::invalidGeneratorType($mapping['generatorType']); 761 } else if (count($this->_identifier) > 1) { 762 throw Doctrine_MappingException::generatorNotAllowedWithCompositeId(); 675 763 } 676 unset($options[$k]);764 $this->_generatorType = $mapping['generatorType']; 677 765 } 678 } 679 680 // extract column name & field name & lowercased column name 681 $parts = explode(' as ', $name); 682 if (count($parts) > 1) { 683 $fieldName = $parts[1]; 684 } else { 685 $fieldName = $parts[0]; 686 } 687 $columnName = $parts[0]; 688 $lcColumnName = strtolower($parts[0]); 689 690 if (isset($this->_fieldMappings[$fieldName])) { 691 return; 692 } 693 694 // Fill column name <-> field name lookup maps 695 $this->_columnNames[$fieldName] = $columnName; 696 $this->_fieldNames[$columnName] = $fieldName; 697 $this->_lcColumnToFieldNames[$lcColumnName] = $fieldName; 698 $this->_lcColumnToFieldNames[$lcColumnName] = $fieldName; 766 // TODO: validate/complete 'generator' mapping 767 768 // Check for composite key 769 if ( ! $this->_isIdentifierComposite && count($this->_identifier) > 1) { 770 $this->_isIdentifierComposite = true; 771 } 772 773 } 699 774 700 701 // Inspect & fill $options 702 703 if ($length == null) { 704 $length = $this->_getDefaultLength($type); 705 } 706 707 $options['type'] = $type; 708 $options['length'] = $length; 709 710 if ( ! $this->_hasDefaultValues && isset($options['default'])) { 711 $this->_hasDefaultValues = true; 712 } 713 if ( ! empty($options['primary'])) { 714 if ( ! in_array($fieldName, $this->_identifier)) { 715 $this->_identifier[] = $fieldName; 716 } 717 /*if (isset($options['autoincrement']) && $options['autoincrement'] === true) { 718 719 }*/ 720 } 721 /* 722 if ( ! isset($options['immutable'])) { 723 $options['immutable'] = false; 724 }*/ 725 726 $this->_fieldMappings[$fieldName] = $options; 727 728 $this->_columnCount++; 729 } 730 731 /** 732 * Gets the default length for a field type. 733 * 734 * @param unknown_type $type 735 * @return unknown 775 return $mapping; 776 } 777 778 /** 779 * Gets the default length for a column type. 780 * 781 * @param string $type 782 * @return mixed 736 783 */ 737 784 private function _getDefaultLength($type) … … 778 825 * @return array The names of all validators that are applied on the specified field. 779 826 */ 780 public function getFieldValidators($fieldName)827 /*public function getFieldValidators($fieldName) 781 828 { 782 829 return isset($this->_fieldMappings[$fieldName]['validators']) ? 783 830 $this->_fieldMappings[$fieldName]['validators'] : array(); 784 }785 786 /**787 * Checks whether the mapped class has a default value on any field.788 *789 * @return boolean TRUE if the entity has a default value on any field, otherwise false.790 */791 /*public function hasDefaultValues()792 {793 return $this->_hasDefaultValues;794 }*/795 796 /**797 * getDefaultValueOf798 * returns the default value(if any) for given field799 *800 * @param string $fieldName801 * @return mixed802 */803 /*public function getDefaultValueOf($fieldName)804 {805 if ( ! isset($this->_fieldMappings[$fieldName])) {806 throw new Doctrine_Table_Exception("Couldn't get default value. Column ".$fieldName." doesn't exist.");807 }808 if (isset($this->_fieldMappings[$fieldName]['default'])) {809 return $this->_fieldMappings[$fieldName]['default'];810 } else {811 return null;812 }813 831 }*/ 814 832 … … 833 851 return $this->_identifier; 834 852 } 853 854 /** 855 * Gets the name of the single id field. Note that this only works on 856 * entity classes that have a single-field pk. 857 * 858 * @return string 859 */ 860 public function getSingleIdentifierFieldName() 861 { 862 if ($this->_isIdentifierComposite) { 863 throw new Doctrine_Exception("Calling getSingleIdentifierFieldName " 864 . "on a class that uses a composite identifier is not allowed."); 865 <