Changeset 4699 for trunk/lib/Doctrine

Show
Ignore:
Timestamp:
07/20/08 21:13:24 (6 months ago)
Author:
romanb
Message:

Checkin of occasional work from the past weeks.

Location:
trunk/lib/Doctrine
Files:
9 added
1 removed
14 modified

Legend:

Unmodified
Added
Removed
  • trunk/lib/Doctrine/ClassMetadata.php

    r4655 r4699  
    2222#namespace Doctrine::ORM::Mapping; 
    2323 
     24#use Doctrine::ORM::EntityManager; 
     25 
    2426/** 
    2527 * A <tt>ClassMetadata</tt> instance holds all the information (metadata) of an entity and 
     
    2931 * @author Roman Borschel <roman@code-factory.org> 
    3032 * @since 2.0 
     33 * @todo Rename to ClassDescriptor? 
    3134 */ 
    3235class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable 
    3336{ 
    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. 
    3677     * 
    3778     * @var string 
     
    4283     * The name of the entity class that is at the root of the entity inheritance 
    4384     * hierarchy. If the entity is not part of an inheritance hierarchy this is the same 
    44      * as the $_entityName. 
     85     * as $_entityName. 
    4586     * 
    4687     * @var string 
     
    5798 
    5899    /** 
    59      * 
    60      * @var Doctrine_Connection 
     100     * The EntityManager. 
     101     *  
     102     * @var Doctrine::ORM::EntityManager 
    61103     */ 
    62104    protected $_em; 
     
    64106    /** 
    65107     * The names of the parent classes (ancestors). 
     108     *  
     109     * @var array 
    66110     */ 
    67111    protected $_parentClasses = array(); 
    68112 
    69113    /** 
    70      * The names of all subclasses 
     114     * The names of all subclasses. 
     115     *  
     116     * @var array 
    71117     */ 
    72118    protected $_subClasses = array(); 
     
    79125     */ 
    80126    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     * 
    86131     * @var integer 
    87132     */ 
    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; 
    97141 
    98142    /** 
     
    103147     * @todo Unify under 'Behaviors'. 
    104148     */ 
    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     
    116151    /** 
    117152     * The field mappings of the class. 
    118153     * Keys are field names and values are mapping definitions. 
    119154     * 
    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. 
    129194     * 
    130195     * @var array 
     
    138203     * @TODO Implementation (Value Object support) 
    139204     */ 
    140     protected $_mappedEmbeddedValues = array(); 
     205    //protected $_embeddedValueMappings = array(); 
    141206 
    142207    /** 
     
    182247 
    183248    /** 
    184      * Caches enum value mappings. Keys are field names and values arrays with the 
    185      * mapping. 
    186      */ 
    187     protected $_enumValues = array(); 
    188  
    189     /** 
    190      * Tree object associated with the class. 
    191      * 
    192      * @var Doctrine_Tree 
    193      * @todo Belongs to the NestedSet Behavior plugin. 
    194      */ 
    195     protected $_tree; 
    196  
    197     /** 
    198      * Cached column count, Doctrine_Entity uses this column count when 
    199      * determining its state. 
    200      * 
    201      * @var integer 
    202      */ 
    203     //protected $_columnCount; 
    204  
    205     /** 
    206      * Whether or not this class has default values. 
    207      * 
    208      * @var boolean 
    209      */ 
    210     protected $_hasDefaultValues; 
    211  
    212     /** 
    213249     * Relation parser object. Manages the relations for the class. 
    214250     * 
    215251     * @var Doctrine_Relation_Parser $_parser 
     252     * @todo Remove. 
    216253     */ 
    217254    protected $_parser; 
    218  
    219     /** 
    220      * Enum value arrays. 
    221      */ 
    222     protected $_enumMap = array(); 
    223  
    224     /** 
    225      * @var array $options                  an array containing all options 
    226      * 
    227      *      -- treeImpl                     the tree implementation of this table (if any) 
    228      * 
    229      *      -- treeOptions                  the tree options 
    230      * 
    231      *      -- queryParts                   the bound query parts 
    232      */ 
    233     protected $_options = array( 
    234             'treeImpl'    => null, 
    235             'treeOptions' => null, 
    236             'queryParts'  => array() 
    237     ); 
    238255 
    239256    /** 
     
    277294            'checks'         => array() 
    278295    ); 
    279  
    280     /** 
    281      * @var array $_invokedMethods              method invoker cache 
    282      */ 
    283     protected $_invokedMethods = array(); 
    284296     
    285297    /** 
     
    305317    protected $_lifecycleListeners = array(); 
    306318     
     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; 
    307332 
    308333    /** 
     
    316341        $this->_rootEntityName = $entityName; 
    317342        $this->_em = $em; 
     343         
    318344        $this->_parser = new Doctrine_Relation_Parser($this); 
    319345    } 
    320346 
    321347    /** 
    322      * 
     348     * @deprecated 
    323349     */ 
    324350    public function getConnection() 
     
    371397    public function isIdentifier($fieldName) 
    372398    { 
    373         if ($this->_identifierType != Doctrine::IDENTIFIER_COMPOSITE) { 
     399        if ( ! $this->_isIdentifierComposite) { 
    374400            return $fieldName === $this->_identifier[0]; 
    375401        } 
     
    378404 
    379405    /** 
    380      * Check if the field is unique 
     406     * Check if the class has a composite identifier. 
    381407     * 
    382408     * @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. 
    384410     */ 
    385411    public function isIdentifierComposite() 
    386412    { 
    387         return $this->_identifierType == Doctrine::IDENTIFIER_COMPOSITE; 
     413        return $this->_isIdentifierComposite; 
    388414    } 
    389415 
     
    491517    } 
    492518 
    493     public function getBehaviorForMethod($method) 
     519    /*public function getBehaviorForMethod($method) 
    494520    { 
    495521        return (isset($this->_invokedMethods[$method])) ? 
     
    499525    { 
    500526        $this->_invokedMethods[$method] = $class; 
    501     } 
    502  
    503     /** 
    504      * getOption 
     527    }*/ 
     528 
     529    /** 
    505530     * returns the value of given option 
    506531     * 
     
    563588    public function getFieldMapping($fieldName) 
    564589    { 
    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]; 
    567595    } 
    568596     
     
    576604    public function getAssociationMapping($fieldName) 
    577605    { 
    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; 
    579621    } 
    580622 
     
    627669     *  
    628670     * @return string  The field name. 
    629      * @throws Doctrine::ORM::Exceptions::ClassMetadataException if the field name could 
     671     * @throws Doctrine::ORM::Exceptions::ClassMetadataException If the field name could 
    630672     *         not be found. 
    631673     */ 
     
    650692        throw new Doctrine_ClassMetadata_Exception("No field name found for column name '$lcColumnName' during lookup."); 
    651693    } 
    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(); 
    675763                } 
    676                 unset($options[$k]); 
     764                $this->_generatorType = $mapping['generatorType']; 
    677765            } 
    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        } 
    699774         
    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 
    736783     */ 
    737784    private function _getDefaultLength($type) 
     
    778825     * @return array  The names of all validators that are applied on the specified field. 
    779826     */ 
    780     public function getFieldValidators($fieldName) 
     827    /*public function getFieldValidators($fieldName) 
    781828    { 
    782829        return isset($this->_fieldMappings[$fieldName]['validators']) ? 
    783830                $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      * getDefaultValueOf 
    798      * returns the default value(if any) for given field 
    799      * 
    800      * @param string $fieldName 
    801      * @return mixed 
    802      */ 
    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         } 
    813831    }*/ 
    814832 
     
    833851        return $this->_identifier; 
    834852    } 
     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        } 
     866        return $this->_identifier[0]; 
     867    } 
    835868 
    836869    public function setIdentifier(array $identifier) 
     
    840873 
    841874    /** 
    842      * Gets the type of the identifier (primary key) used by the mapped class. The type 
    843      * can be either 
    844      * <tt>Doctrine::IDENTIFIER_NATURAL</tt>, 
    845      * <tt>Doctrine::IDENTIFIER_AUTOINCREMENT</tt>, 
    846      * <tt>Doctrine::IDENTIFIER_SEQUENCE</tt> or 
    847      * <tt>Doctrine::IDENTIFIER_COMPOSITE</tt>. 
    848      * 
    849      * @return integer 
    850      */ 
    851     public function getIdentifierType() 
    852     { 
    853         return $this->_identifierType; 
    854     } 
    855  
    856     /** 
    857      * Sets the identifier type used by the mapped class. 
    858      */ 
    859     public function setIdentifierType($type) 
    860     { 
    861         $this->_identifierType = $type; 
    862     } 
    863  
    864     public function hasMappedColumn($columnName) 
    865     { 
    866         return isset($this->_fieldNames[$columnName]); 
    867     } 
    868  
    869     /** 
    870      * hasField 
     875     * Checks whether the class has a (mapped) field with a certain name. 
     876     *  
    871877     * @return boolean 
    872878     */