diff -r 000000000000 -r 7f95f8617b0b vendor/doctrine/lib/Doctrine/ORM/Mapping/ClassMetadata.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/doctrine/lib/Doctrine/ORM/Mapping/ClassMetadata.php Sat Sep 24 15:40:41 2011 +0200 @@ -0,0 +1,346 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +use ReflectionClass, ReflectionProperty; + +/** + * A ClassMetadata instance holds all the object-relational mapping metadata + * of an entity and it's associations. + * + * Once populated, ClassMetadata instances are usually cached in a serialized form. + * + * IMPORTANT NOTE: + * + * The fields of this class are only public for 2 reasons: + * 1) To allow fast READ access. + * 2) To drastically reduce the size of a serialized instance (private/protected members + * get the whole class name, namespace inclusive, prepended to every property in + * the serialized representation). + * + * @author Roman Borschel + * @author Jonathan H. Wage + * @since 2.0 + */ +class ClassMetadata extends ClassMetadataInfo +{ + /** + * The ReflectionProperty instances of the mapped class. + * + * @var array + */ + public $reflFields = array(); + + /** + * The prototype from which new instances of the mapped class are created. + * + * @var object + */ + private $_prototype; + + /** + * Initializes a new ClassMetadata instance that will hold the object-relational mapping + * metadata of the class with the given name. + * + * @param string $entityName The name of the entity class the new instance is used for. + */ + public function __construct($entityName) + { + $this->reflClass = new ReflectionClass($entityName); + $this->namespace = $this->reflClass->getNamespaceName(); + $this->table['name'] = $this->reflClass->getShortName(); + parent::__construct($this->reflClass->getName()); // do not use $entityName, possible case-problems + } + + /** + * Gets the ReflectionPropertys of the mapped class. + * + * @return array An array of ReflectionProperty instances. + */ + public function getReflectionProperties() + { + return $this->reflFields; + } + + /** + * Gets a ReflectionProperty for a specific field of the mapped class. + * + * @param string $name + * @return ReflectionProperty + */ + public function getReflectionProperty($name) + { + return $this->reflFields[$name]; + } + + /** + * Gets the ReflectionProperty for the single identifier field. + * + * @return ReflectionProperty + * @throws BadMethodCallException If the class has a composite identifier. + */ + public function getSingleIdReflectionProperty() + { + if ($this->isIdentifierComposite) { + throw new \BadMethodCallException("Class " . $this->name . " has a composite identifier."); + } + return $this->reflFields[$this->identifier[0]]; + } + + /** + * Validates & completes the given field mapping. + * + * @param array $mapping The field mapping to validated & complete. + * @return array The validated and completed field mapping. + * + * @throws MappingException + */ + protected function _validateAndCompleteFieldMapping(array &$mapping) + { + parent::_validateAndCompleteFieldMapping($mapping); + + // Store ReflectionProperty of mapped field + $refProp = $this->reflClass->getProperty($mapping['fieldName']); + $refProp->setAccessible(true); + $this->reflFields[$mapping['fieldName']] = $refProp; + } + + /** + * Extracts the identifier values of an entity of this class. + * + * For composite identifiers, the identifier values are returned as an array + * with the same order as the field order in {@link identifier}. + * + * @param object $entity + * @return array + */ + public function getIdentifierValues($entity) + { + if ($this->isIdentifierComposite) { + $id = array(); + foreach ($this->identifier as $idField) { + $value = $this->reflFields[$idField]->getValue($entity); + if ($value !== null) { + $id[$idField] = $value; + } + } + return $id; + } else { + $value = $this->reflFields[$this->identifier[0]]->getValue($entity); + if ($value !== null) { + return array($this->identifier[0] => $value); + } + return array(); + } + } + + /** + * Populates the entity identifier of an entity. + * + * @param object $entity + * @param mixed $id + * @todo Rename to assignIdentifier() + */ + public function setIdentifierValues($entity, array $id) + { + foreach ($id as $idField => $idValue) { + $this->reflFields[$idField]->setValue($entity, $idValue); + } + } + + /** + * Sets the specified field to the specified value on the given entity. + * + * @param object $entity + * @param string $field + * @param mixed $value + */ + public function setFieldValue($entity, $field, $value) + { + $this->reflFields[$field]->setValue($entity, $value); + } + + /** + * Gets the specified field's value off the given entity. + * + * @param object $entity + * @param string $field + */ + public function getFieldValue($entity, $field) + { + return $this->reflFields[$field]->getValue($entity); + } + + /** + * Stores the association mapping. + * + * @param AssociationMapping $assocMapping + */ + protected function _storeAssociationMapping(array $assocMapping) + { + parent::_storeAssociationMapping($assocMapping); + + // Store ReflectionProperty of mapped field + $sourceFieldName = $assocMapping['fieldName']; + + $refProp = $this->reflClass->getProperty($sourceFieldName); + $refProp->setAccessible(true); + $this->reflFields[$sourceFieldName] = $refProp; + } + + /** + * Creates a string representation of this instance. + * + * @return string The string representation of this instance. + * @todo Construct meaningful string representation. + */ + public function __toString() + { + return __CLASS__ . '@' . spl_object_hash($this); + } + + /** + * Determines which fields get serialized. + * + * It is only serialized what is necessary for best unserialization performance. + * That means any metadata properties that are not set or empty or simply have + * their default value are NOT serialized. + * + * Parts that are also NOT serialized because they can not be properly unserialized: + * - reflClass (ReflectionClass) + * - reflFields (ReflectionProperty array) + * + * @return array The names of all the fields that should be serialized. + */ + public function __sleep() + { + // This metadata is always serialized/cached. + $serialized = array( + 'associationMappings', + 'columnNames', //TODO: Not really needed. Can use fieldMappings[$fieldName]['columnName'] + 'fieldMappings', + 'fieldNames', + 'identifier', + 'isIdentifierComposite', // TODO: REMOVE + 'name', + 'namespace', // TODO: REMOVE + 'table', + 'rootEntityName', + 'idGenerator', //TODO: Does not really need to be serialized. Could be moved to runtime. + ); + + // The rest of the metadata is only serialized if necessary. + if ($this->changeTrackingPolicy != self::CHANGETRACKING_DEFERRED_IMPLICIT) { + $serialized[] = 'changeTrackingPolicy'; + } + + if ($this->customRepositoryClassName) { + $serialized[] = 'customRepositoryClassName'; + } + + if ($this->inheritanceType != self::INHERITANCE_TYPE_NONE) { + $serialized[] = 'inheritanceType'; + $serialized[] = 'discriminatorColumn'; + $serialized[] = 'discriminatorValue'; + $serialized[] = 'discriminatorMap'; + $serialized[] = 'parentClasses'; + $serialized[] = 'subClasses'; + } + + if ($this->generatorType != self::GENERATOR_TYPE_NONE) { + $serialized[] = 'generatorType'; + if ($this->generatorType == self::GENERATOR_TYPE_SEQUENCE) { + $serialized[] = 'sequenceGeneratorDefinition'; + } + } + + if ($this->isMappedSuperclass) { + $serialized[] = 'isMappedSuperclass'; + } + + if ($this->containsForeignIdentifier) { + $serialized[] = 'containsForeignIdentifier'; + } + + if ($this->isVersioned) { + $serialized[] = 'isVersioned'; + $serialized[] = 'versionField'; + } + + if ($this->lifecycleCallbacks) { + $serialized[] = 'lifecycleCallbacks'; + } + + if ($this->namedQueries) { + $serialized[] = 'namedQueries'; + } + + if ($this->isReadOnly) { + $serialized[] = 'isReadOnly'; + } + + return $serialized; + } + + /** + * Restores some state that can not be serialized/unserialized. + * + * @return void + */ + public function __wakeup() + { + // Restore ReflectionClass and properties + $this->reflClass = new ReflectionClass($this->name); + + foreach ($this->fieldMappings as $field => $mapping) { + if (isset($mapping['declared'])) { + $reflField = new ReflectionProperty($mapping['declared'], $field); + } else { + $reflField = $this->reflClass->getProperty($field); + } + $reflField->setAccessible(true); + $this->reflFields[$field] = $reflField; + } + + foreach ($this->associationMappings as $field => $mapping) { + if (isset($mapping['declared'])) { + $reflField = new ReflectionProperty($mapping['declared'], $field); + } else { + $reflField = $this->reflClass->getProperty($field); + } + + $reflField->setAccessible(true); + $this->reflFields[$field] = $reflField; + } + } + + /** + * Creates a new instance of the mapped class, without invoking the constructor. + * + * @return object + */ + public function newInstance() + { + if ($this->_prototype === null) { + $this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name)); + } + return clone $this->_prototype; + } +}