* @since 2.0
*/
class ClassMetadataInfo implements ClassMetadata
{
/* The inheritance mapping types */
/**
* NONE means the class does not participate in an inheritance hierarchy
* and therefore does not need an inheritance mapping type.
*/
const INHERITANCE_TYPE_NONE = 1;
/**
* JOINED means the class will be persisted according to the rules of
* Class Table Inheritance.
*/
const INHERITANCE_TYPE_JOINED = 2;
/**
* SINGLE_TABLE means the class will be persisted according to the rules of
* Single Table Inheritance.
*/
const INHERITANCE_TYPE_SINGLE_TABLE = 3;
/**
* TABLE_PER_CLASS means the class will be persisted according to the rules
* of Concrete Table Inheritance.
*/
const INHERITANCE_TYPE_TABLE_PER_CLASS = 4;
/* The Id generator types. */
/**
* AUTO means the generator type will depend on what the used platform prefers.
* Offers full portability.
*/
const GENERATOR_TYPE_AUTO = 1;
/**
* SEQUENCE means a separate sequence object will be used. Platforms that do
* not have native sequence support may emulate it. Full portability is currently
* not guaranteed.
*/
const GENERATOR_TYPE_SEQUENCE = 2;
/**
* TABLE means a separate table is used for id generation.
* Offers full portability.
*/
const GENERATOR_TYPE_TABLE = 3;
/**
* IDENTITY means an identity column is used for id generation. The database
* will fill in the id column on insertion. Platforms that do not support
* native identity columns may emulate them. Full portability is currently
* not guaranteed.
*/
const GENERATOR_TYPE_IDENTITY = 4;
/**
* NONE means the class does not have a generated id. That means the class
* must have a natural, manually assigned id.
*/
const GENERATOR_TYPE_NONE = 5;
/**
* UUID means that a UUID/GUID expression is used for id generation. Full
* portability is currently not guaranteed.
*/
const GENERATOR_TYPE_UUID = 6;
/**
* CUSTOM means that customer will use own ID generator that supposedly work
*/
const GENERATOR_TYPE_CUSTOM = 7;
/**
* DEFERRED_IMPLICIT means that changes of entities are calculated at commit-time
* by doing a property-by-property comparison with the original data. This will
* be done for all entities that are in MANAGED state at commit-time.
*
* This is the default change tracking policy.
*/
const CHANGETRACKING_DEFERRED_IMPLICIT = 1;
/**
* DEFERRED_EXPLICIT means that changes of entities are calculated at commit-time
* by doing a property-by-property comparison with the original data. This will
* be done only for entities that were explicitly saved (through persist() or a cascade).
*/
const CHANGETRACKING_DEFERRED_EXPLICIT = 2;
/**
* NOTIFY means that Doctrine relies on the entities sending out notifications
* when their properties change. Such entity classes must implement
* the NotifyPropertyChanged interface.
*/
const CHANGETRACKING_NOTIFY = 3;
/**
* Specifies that an association is to be fetched when it is first accessed.
*/
const FETCH_LAZY = 2;
/**
* Specifies that an association is to be fetched when the owner of the
* association is fetched.
*/
const FETCH_EAGER = 3;
/**
* Specifies that an association is to be fetched lazy (on first access) and that
* commands such as Collection#count, Collection#slice are issued directly against
* the database if the collection is not yet initialized.
*/
const FETCH_EXTRA_LAZY = 4;
/**
* Identifies a one-to-one association.
*/
const ONE_TO_ONE = 1;
/**
* Identifies a many-to-one association.
*/
const MANY_TO_ONE = 2;
/**
* Identifies a one-to-many association.
*/
const ONE_TO_MANY = 4;
/**
* Identifies a many-to-many association.
*/
const MANY_TO_MANY = 8;
/**
* Combined bitmask for to-one (single-valued) associations.
*/
const TO_ONE = 3;
/**
* Combined bitmask for to-many (collection-valued) associations.
*/
const TO_MANY = 12;
/**
* ReadOnly cache can do reads, inserts and deletes, cannot perform updates or employ any locks,
*/
const CACHE_USAGE_READ_ONLY = 1;
/**
* Nonstrict Read Write Cache doesn’t employ any locks but can do inserts, update and deletes.
*/
const CACHE_USAGE_NONSTRICT_READ_WRITE = 2;
/**
* Read Write Attempts to lock the entity before update/delete.
*/
const CACHE_USAGE_READ_WRITE = 3;
/**
* READ-ONLY: The name of the entity class.
*
* @var string
*/
public $name;
/**
* READ-ONLY: The namespace the entity class is contained in.
*
* @var string
*
* @todo Not really needed. Usage could be localized.
*/
public $namespace;
/**
* READ-ONLY: The name of the entity class that is at the root of the mapped entity inheritance
* hierarchy. If the entity is not part of a mapped inheritance hierarchy this is the same
* as {@link $entityName}.
*
* @var string
*/
public $rootEntityName;
/**
* READ-ONLY: The definition of custom generator. Only used for CUSTOM
* generator type
*
* The definition has the following structure:
*
* array(
* 'class' => 'ClassName',
* )
*
*
* @var array
*
* @todo Merge with tableGeneratorDefinition into generic generatorDefinition
*/
public $customGeneratorDefinition;
/**
* The name of the custom repository class used for the entity class.
* (Optional).
*
* @var string
*/
public $customRepositoryClassName;
/**
* READ-ONLY: Whether this class describes the mapping of a mapped superclass.
*
* @var boolean
*/
public $isMappedSuperclass = false;
/**
* READ-ONLY: Whether this class describes the mapping of an embeddable class.
*
* @var boolean
*/
public $isEmbeddedClass = false;
/**
* READ-ONLY: The names of the parent classes (ancestors).
*
* @var array
*/
public $parentClasses = array();
/**
* READ-ONLY: The names of all subclasses (descendants).
*
* @var array
*/
public $subClasses = array();
/**
* READ-ONLY: The names of all embedded classes based on properties.
*
* @var array
*/
public $embeddedClasses = array();
/**
* READ-ONLY: The named queries allowed to be called directly from Repository.
*
* @var array
*/
public $namedQueries = array();
/**
* READ-ONLY: The named native queries allowed to be called directly from Repository.
*
* A native SQL named query definition has the following structure:
*
* array(
* 'name' => ,
* 'query' => ,
* 'resultClass' => ,
* 'resultSetMapping' =>
* )
*
*
* @var array
*/
public $namedNativeQueries = array();
/**
* READ-ONLY: The mappings of the results of native SQL queries.
*
* A native result mapping definition has the following structure:
*
* array(
* 'name' => ,
* 'entities' => array(),
* 'columns' => array()
* )
*
*
* @var array
*/
public $sqlResultSetMappings = array();
/**
* READ-ONLY: The field names of all fields that are part of the identifier/primary key
* of the mapped entity class.
*
* @var array
*/
public $identifier = array();
/**
* READ-ONLY: The inheritance mapping type used by the class.
*
* @var integer
*/
public $inheritanceType = self::INHERITANCE_TYPE_NONE;
/**
* READ-ONLY: The Id generator type used by the class.
*
* @var int
*/
public $generatorType = self::GENERATOR_TYPE_NONE;
/**
* READ-ONLY: The field mappings of the class.
* Keys are field names and values are mapping definitions.
*
* The mapping definition array has the following values:
*
* - fieldName (string)
* The name of the field in the Entity.
*
* - type (string)
* The type name of the mapped field. Can be one of Doctrine's mapping types
* or a custom mapping type.
*
* - columnName (string, optional)
* The column name. Optional. Defaults to the field name.
*
* - length (integer, optional)
* The database length of the column. Optional. Default value taken from
* the type.
*
* - id (boolean, optional)
* Marks the field as the primary key of the entity. Multiple fields of an
* entity can have the id attribute, forming a composite key.
*
* - nullable (boolean, optional)
* Whether the column is nullable. Defaults to FALSE.
*
* - columnDefinition (string, optional, schema-only)
* The SQL fragment that is used when generating the DDL for the column.
*
* - precision (integer, optional, schema-only)
* The precision of a decimal column. Only valid if the column type is decimal.
*
* - scale (integer, optional, schema-only)
* The scale of a decimal column. Only valid if the column type is decimal.
*
* - 'unique' (string, optional, schema-only)
* Whether a unique constraint should be generated for the column.
*
* @var array
*/
public $fieldMappings = array();
/**
* READ-ONLY: An array of field names. Used to look up field names from column names.
* Keys are column names and values are field names.
* This is the reverse lookup map of $_columnNames.
*
* @var array
*/
public $fieldNames = array();
/**
* READ-ONLY: A map of field names to column names. Keys are field names and values column names.
* Used to look up column names from field names.
* This is the reverse lookup map of $_fieldNames.
*
* @var array
*
* @todo We could get rid of this array by just using $fieldMappings[$fieldName]['columnName'].
*/
public $columnNames = array();
/**
* READ-ONLY: The discriminator value of this class.
*
* This does only apply to the JOINED and SINGLE_TABLE inheritance mapping strategies
* where a discriminator column is used.
*
* @var mixed
*
* @see discriminatorColumn
*/
public $discriminatorValue;
/**
* READ-ONLY: The discriminator map of all mapped classes in the hierarchy.
*
* This does only apply to the JOINED and SINGLE_TABLE inheritance mapping strategies
* where a discriminator column is used.
*
* @var mixed
*
* @see discriminatorColumn
*/
public $discriminatorMap = array();
/**
* READ-ONLY: The definition of the discriminator column used in JOINED and SINGLE_TABLE
* inheritance mappings.
*
* @var array
*/
public $discriminatorColumn;
/**
* READ-ONLY: The primary table definition. The definition is an array with the
* following entries:
*
* name =>
* schema =>
* indexes => array
* uniqueConstraints => array
*
* @var array
*/
public $table;
/**
* READ-ONLY: The registered lifecycle callbacks for entities of this class.
*
* @var array
*/
public $lifecycleCallbacks = array();
/**
* READ-ONLY: The registered entity listeners.
*
* @var array
*/
public $entityListeners = array();
/**
* READ-ONLY: The association mappings of this class.
*
* The mapping definition array supports the following keys:
*
* - fieldName (string)
* The name of the field in the entity the association is mapped to.
*
* - targetEntity (string)
* The class name of the target entity. If it is fully-qualified it is used as is.
* If it is a simple, unqualified class name the namespace is assumed to be the same
* as the namespace of the source entity.
*
* - mappedBy (string, required for bidirectional associations)
* The name of the field that completes the bidirectional association on the owning side.
* This key must be specified on the inverse side of a bidirectional association.
*
* - inversedBy (string, required for bidirectional associations)
* The name of the field that completes the bidirectional association on the inverse side.
* This key must be specified on the owning side of a bidirectional association.
*
* - cascade (array, optional)
* The names of persistence operations to cascade on the association. The set of possible
* values are: "persist", "remove", "detach", "merge", "refresh", "all" (implies all others).
*
* - orderBy (array, one-to-many/many-to-many only)
* A map of field names (of the target entity) to sorting directions (ASC/DESC).
* Example: array('priority' => 'desc')
*
* - fetch (integer, optional)
* The fetching strategy to use for the association, usually defaults to FETCH_LAZY.
* Possible values are: ClassMetadata::FETCH_EAGER, ClassMetadata::FETCH_LAZY.
*
* - joinTable (array, optional, many-to-many only)
* Specification of the join table and its join columns (foreign keys).
* Only valid for many-to-many mappings. Note that one-to-many associations can be mapped
* through a join table by simply mapping the association as many-to-many with a unique
* constraint on the join table.
*
* - indexBy (string, optional, to-many only)
* Specification of a field on target-entity that is used to index the collection by.
* This field HAS to be either the primary key or a unique column. Otherwise the collection
* does not contain all the entities that are actually related.
*
* A join table definition has the following structure:
*
* array(
* 'name' => ,
* 'joinColumns' => array(),
* 'inverseJoinColumns' => array()
* )
*
*
* @var array
*/
public $associationMappings = array();
/**
* READ-ONLY: Flag indicating whether the identifier/primary key of the class is composite.
*
* @var boolean
*/
public $isIdentifierComposite = false;
/**
* READ-ONLY: Flag indicating whether the identifier/primary key contains at least one foreign key association.
*
* This flag is necessary because some code blocks require special treatment of this cases.
*
* @var boolean
*/
public $containsForeignIdentifier = false;
/**
* READ-ONLY: The ID generator used for generating IDs for this class.
*
* @var \Doctrine\ORM\Id\AbstractIdGenerator
*
* @todo Remove!
*/
public $idGenerator;
/**
* READ-ONLY: The definition of the sequence generator of this class. Only used for the
* SEQUENCE generation strategy.
*
* The definition has the following structure:
*
* array(
* 'sequenceName' => 'name',
* 'allocationSize' => 20,
* 'initialValue' => 1
* )
*
*
* @var array
*
* @todo Merge with tableGeneratorDefinition into generic generatorDefinition
*/
public $sequenceGeneratorDefinition;
/**
* READ-ONLY: The definition of the table generator of this class. Only used for the
* TABLE generation strategy.
*
* @var array
*
* @todo Merge with tableGeneratorDefinition into generic generatorDefinition
*/
public $tableGeneratorDefinition;
/**
* READ-ONLY: The policy used for change-tracking on entities of this class.
*
* @var integer
*/
public $changeTrackingPolicy = self::CHANGETRACKING_DEFERRED_IMPLICIT;
/**
* READ-ONLY: A flag for whether or not instances of this class are to be versioned
* with optimistic locking.
*
* @var boolean
*/
public $isVersioned;
/**
* READ-ONLY: The name of the field which is used for versioning in optimistic locking (if any).
*
* @var mixed
*/
public $versionField;
/**
* @var array
*/
public $cache = null;
/**
* The ReflectionClass instance of the mapped class.
*
* @var ReflectionClass
*/
public $reflClass;
/**
* Is this entity marked as "read-only"?
*
* That means it is never considered for change-tracking in the UnitOfWork. It is a very helpful performance
* optimization for entities that are immutable, either in your domain or through the relation database
* (coming from a view, or a history table for example).
*
* @var bool
*/
public $isReadOnly = false;
/**
* NamingStrategy determining the default column and table names.
*
* @var \Doctrine\ORM\Mapping\NamingStrategy
*/
protected $namingStrategy;
/**
* The ReflectionProperty instances of the mapped class.
*
* @var \ReflectionProperty[]
*/
public $reflFields = array();
/**
* @var \Doctrine\Instantiator\InstantiatorInterface|null
*/
private $instantiator;
/**
* 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.
* @param NamingStrategy|null $namingStrategy
*/
public function __construct($entityName, NamingStrategy $namingStrategy = null)
{
$this->name = $entityName;
$this->rootEntityName = $entityName;
$this->namingStrategy = $namingStrategy ?: new DefaultNamingStrategy();
$this->instantiator = new Instantiator();
}
/**
* Gets the ReflectionProperties 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]];
}
/**
* 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;
}
$id = $this->identifier[0];
$value = $this->reflFields[$id]->getValue($entity);
if (null === $value) {
return array();
}
return array($id => $value);
}
/**
* Populates the entity identifier of an entity.
*
* @param object $entity
* @param mixed $id
*
* @return void
*
* @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
*
* @return void
*/
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
*
* @return mixed
*/
public function getFieldValue($entity, $field)
{
return $this->reflFields[$field]->getValue($entity);
}
/**
* 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',
'embeddedClasses',
'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->isEmbeddedClass) {
$serialized[] = 'isEmbeddedClass';
}
if ($this->containsForeignIdentifier) {
$serialized[] = 'containsForeignIdentifier';
}
if ($this->isVersioned) {
$serialized[] = 'isVersioned';
$serialized[] = 'versionField';
}
if ($this->lifecycleCallbacks) {
$serialized[] = 'lifecycleCallbacks';
}
if ($this->entityListeners) {
$serialized[] = 'entityListeners';
}
if ($this->namedQueries) {
$serialized[] = 'namedQueries';
}
if ($this->namedNativeQueries) {
$serialized[] = 'namedNativeQueries';
}
if ($this->sqlResultSetMappings) {
$serialized[] = 'sqlResultSetMappings';
}
if ($this->isReadOnly) {
$serialized[] = 'isReadOnly';
}
if ($this->customGeneratorDefinition) {
$serialized[] = "customGeneratorDefinition";
}
if ($this->cache) {
$serialized[] = 'cache';
}
return $serialized;
}
/**
* Creates a new instance of the mapped class, without invoking the constructor.
*
* @return object
*/
public function newInstance()
{
return $this->instantiator->instantiate($this->name);
}
/**
* Restores some state that can not be serialized/unserialized.
*
* @param \Doctrine\Common\Persistence\Mapping\ReflectionService $reflService
*
* @return void
*/
public function wakeupReflection($reflService)
{
// Restore ReflectionClass and properties
$this->reflClass = $reflService->getClass($this->name);
$this->instantiator = $this->instantiator ?: new Instantiator();
$parentReflFields = array();
foreach ($this->embeddedClasses as $property => $embeddedClass) {
if (isset($embeddedClass['declaredField'])) {
$parentReflFields[$property] = new ReflectionEmbeddedProperty(
$parentReflFields[$embeddedClass['declaredField']],
$reflService->getAccessibleProperty(
$this->embeddedClasses[$embeddedClass['declaredField']]['class'],
$embeddedClass['originalField']
),
$this->embeddedClasses[$embeddedClass['declaredField']]['class']
);
continue;
}
$fieldRefl = $reflService->getAccessibleProperty(
isset($embeddedClass['declared']) ? $embeddedClass['declared'] : $this->name,
$property
);
$parentReflFields[$property] = $fieldRefl;
$this->reflFields[$property] = $fieldRefl;
}
foreach ($this->fieldMappings as $field => $mapping) {
if (isset($mapping['declaredField']) && isset($parentReflFields[$mapping['declaredField']])) {
$this->reflFields[$field] = new ReflectionEmbeddedProperty(
$parentReflFields[$mapping['declaredField']],
$reflService->getAccessibleProperty($mapping['originalClass'], $mapping['originalField']),
$mapping['originalClass']
);
continue;
}
$this->reflFields[$field] = isset($mapping['declared'])
? $reflService->getAccessibleProperty($mapping['declared'], $field)
: $reflService->getAccessibleProperty($this->name, $field);
}
foreach ($this->associationMappings as $field => $mapping) {
$this->reflFields[$field] = isset($mapping['declared'])
? $reflService->getAccessibleProperty($mapping['declared'], $field)
: $reflService->getAccessibleProperty($this->name, $field);
}
}
/**
* Initializes a new ClassMetadata instance that will hold the object-relational mapping
* metadata of the class with the given name.
*
* @param \Doctrine\Common\Persistence\Mapping\ReflectionService $reflService The reflection service.
*
* @return void
*/
public function initializeReflection($reflService)
{
$this->reflClass = $reflService->getClass($this->name);
$this->namespace = $reflService->getClassNamespace($this->name);
if ($this->reflClass) {
$this->name = $this->rootEntityName = $this->reflClass->getName();
}
$this->table['name'] = $this->namingStrategy->classToTableName($this->name);
}
/**
* Validates Identifier.
*
* @return void
*
* @throws MappingException
*/
public function validateIdentifier()
{
if ($this->isMappedSuperclass || $this->isEmbeddedClass) {
return;
}
// Verify & complete identifier mapping
if ( ! $this->identifier) {
throw MappingException::identifierRequired($this->name);
}
if ($this->usesIdGenerator() && $this->isIdentifierComposite) {
throw MappingException::compositeKeyAssignedIdGeneratorRequired($this->name);
}
}
/**
* Validates association targets actually exist.
*
* @return void
*
* @throws MappingException
*/
public function validateAssociations()
{
foreach ($this->associationMappings as $mapping) {
if ( ! ClassLoader::classExists($mapping['targetEntity']) ) {
throw MappingException::invalidTargetEntityClass($mapping['targetEntity'], $this->name, $mapping['fieldName']);
}
}
}
/**
* Validates lifecycle callbacks.
*
* @param \Doctrine\Common\Persistence\Mapping\ReflectionService $reflService
*
* @return void
*
* @throws MappingException
*/
public function validateLifecycleCallbacks($reflService)
{
foreach ($this->lifecycleCallbacks as $callbacks) {
foreach ($callbacks as $callbackFuncName) {
if ( ! $reflService->hasPublicMethod($this->name, $callbackFuncName)) {
throw MappingException::lifecycleCallbackMethodNotFound($this->name, $callbackFuncName);
}
}
}
}
/**
* {@inheritDoc}
*/
public function getReflectionClass()
{
return $this->reflClass;
}
/**
* @param array $cache
*
* @return void
*/
public function enableCache(array $cache)
{
if ( ! isset($cache['usage'])) {
$cache['usage'] = self::CACHE_USAGE_READ_ONLY;
}
if ( ! isset($cache['region'])) {
$cache['region'] = strtolower(str_replace('\\', '_', $this->rootEntityName));
}
$this->cache = $cache;
}
/**
* @param string $fieldName
* @param array $cache
*
* @return void
*/
public function enableAssociationCache($fieldName, array $cache)
{
if ( ! isset($cache['usage'])) {
$cache['usage'] = isset($this->cache['usage'])
? $this->cache['usage']
: self::CACHE_USAGE_READ_ONLY;
}
if ( ! isset($cache['region'])) {
$cache['region'] = strtolower(str_replace('\\', '_', $this->rootEntityName)) . '__' . $fieldName;
}
$this->associationMappings[$fieldName]['cache'] = $cache;
}
/**
* Sets the change tracking policy used by this class.
*
* @param integer $policy
*
* @return void
*/
public function setChangeTrackingPolicy($policy)
{
$this->changeTrackingPolicy = $policy;
}
/**
* Whether the change tracking policy of this class is "deferred explicit".
*
* @return boolean
*/
public function isChangeTrackingDeferredExplicit()
{
return $this->changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_EXPLICIT;
}
/**
* Whether the change tracking policy of this class is "deferred implicit".
*
* @return boolean
*/
public function isChangeTrackingDeferredImplicit()
{
return $this->changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_IMPLICIT;
}
/**
* Whether the change tracking policy of this class is "notify".
*
* @return boolean
*/
public function isChangeTrackingNotify()
{
return $this->changeTrackingPolicy == self::CHANGETRACKING_NOTIFY;
}
/**
* Checks whether a field is part of the identifier/primary key field(s).
*
* @param string $fieldName The field name.
*
* @return boolean TRUE if the field is part of the table identifier/primary key field(s),
* FALSE otherwise.
*/
public function isIdentifier($fieldName)
{
if ( ! $this->identifier) {
return false;
}
if ( ! $this->isIdentifierComposite) {
return $fieldName === $this->identifier[0];
}
return in_array($fieldName, $this->identifier);
}
/**
* Checks if the field is unique.
*
* @param string $fieldName The field name.
*
* @return boolean TRUE if the field is unique, FALSE otherwise.
*/
public function isUniqueField($fieldName)
{
$mapping = $this->getFieldMapping($fieldName);
if ($mapping !== false) {
return isset($mapping['unique']) && $mapping['unique'] == true;
}
return false;
}
/**
* Checks if the field is not null.
*
* @param string $fieldName The field name.
*
* @return boolean TRUE if the field is not null, FALSE otherwise.
*/
public function isNullable($fieldName)
{
$mapping = $this->getFieldMapping($fieldName);
if ($mapping !== false) {
return isset($mapping['nullable']) && $mapping['nullable'] == true;
}
return false;
}
/**
* Gets a column name for a field name.
* If the column name for the field cannot be found, the given field name
* is returned.
*
* @param string $fieldName The field name.
*
* @return string The column name.
*/
public function getColumnName($fieldName)
{
return isset($this->columnNames[$fieldName]) ?
$this->columnNames[$fieldName] : $fieldName;
}
/**
* Gets the mapping of a (regular) field that holds some data but not a
* reference to another object.
*
* @param string $fieldName The field name.
*
* @return array The field mapping.
*
* @throws MappingException
*/
public function getFieldMapping($fieldName)
{
if ( ! isset($this->fieldMappings[$fieldName])) {
throw MappingException::mappingNotFound($this->name, $fieldName);
}
return $this->fieldMappings[$fieldName];
}
/**
* Gets the mapping of an association.
*
* @see ClassMetadataInfo::$associationMappings
*
* @param string $fieldName The field name that represents the association in
* the object model.
*
* @return array The mapping.
*
* @throws MappingException
*/
public function getAssociationMapping($fieldName)
{
if ( ! isset($this->associationMappings[$fieldName])) {
throw MappingException::mappingNotFound($this->name, $fieldName);
}
return $this->associationMappings[$fieldName];
}
/**
* Gets all association mappings of the class.
*
* @return array
*/
public function getAssociationMappings()
{
return $this->associationMappings;
}
/**
* Gets the field name for a column name.
* If no field name can be found the column name is returned.
*
* @param string $columnName The column name.
*
* @return string The column alias.
*/
public function getFieldName($columnName)
{
return isset($this->fieldNames[$columnName]) ?
$this->fieldNames[$columnName] : $columnName;
}
/**
* Gets the named query.
*
* @see ClassMetadataInfo::$namedQueries
*
* @param string $queryName The query name.
*
* @return string
*
* @throws MappingException
*/
public function getNamedQuery($queryName)
{
if ( ! isset($this->namedQueries[$queryName])) {
throw MappingException::queryNotFound($this->name, $queryName);
}
return $this->namedQueries[$queryName]['dql'];
}
/**
* Gets all named queries of the class.
*
* @return array
*/
public function getNamedQueries()
{
return $this->namedQueries;
}
/**
* Gets the named native query.
*
* @see ClassMetadataInfo::$namedNativeQueries
*
* @param string $queryName The query name.
*
* @return array
*
* @throws MappingException
*/
public function getNamedNativeQuery($queryName)
{
if ( ! isset($this->namedNativeQueries[$queryName])) {
throw MappingException::queryNotFound($this->name, $queryName);
}
return $this->namedNativeQueries[$queryName];
}
/**
* Gets all named native queries of the class.
*
* @return array
*/
public function getNamedNativeQueries()
{
return $this->namedNativeQueries;
}
/**
* Gets the result set mapping.
*
* @see ClassMetadataInfo::$sqlResultSetMappings
*
* @param string $name The result set mapping name.
*
* @return array
*
* @throws MappingException
*/
public function getSqlResultSetMapping($name)
{
if ( ! isset($this->sqlResultSetMappings[$name])) {
throw MappingException::resultMappingNotFound($this->name, $name);
}
return $this->sqlResultSetMappings[$name];
}
/**
* Gets all sql result set mappings of the class.
*
* @return array
*/
public function getSqlResultSetMappings()
{
return $this->sqlResultSetMappings;
}
/**
* Validates & completes the given field mapping.
*
* @param array $mapping The field mapping to validate & complete.
*
* @return array The validated and completed field mapping.
*
* @throws MappingException
*/
protected function _validateAndCompleteFieldMapping(array &$mapping)
{
// Check mandatory fields
if ( ! isset($mapping['fieldName']) || strlen($mapping['fieldName']) == 0) {
throw MappingException::missingFieldName($this->name);
}
if ( ! isset($mapping['type'])) {
// Default to string
$mapping['type'] = 'string';
}
// Complete fieldName and columnName mapping
if ( ! isset($mapping['columnName'])) {
$mapping['columnName'] = $this->namingStrategy->propertyToColumnName($mapping['fieldName'], $this->name);
}
if ($mapping['columnName'][0] === '`') {
$mapping['columnName'] = trim($mapping['columnName'], '`');
$mapping['quoted'] = true;
}
$this->columnNames[$mapping['fieldName']] = $mapping['columnName'];
if (isset($this->fieldNames[$mapping['columnName']]) || ($this->discriminatorColumn != null && $this->discriminatorColumn['name'] == $mapping['columnName'])) {
throw MappingException::duplicateColumnName($this->name, $mapping['columnName']);
}
$this->fieldNames[$mapping['columnName']] = $mapping['fieldName'];
// Complete id mapping
if (isset($mapping['id']) && $mapping['id'] === true) {
if ($this->versionField == $mapping['fieldName']) {
throw MappingException::cannotVersionIdField($this->name, $mapping['fieldName']);
}
if ( ! in_array($mapping['fieldName'], $this->identifier)) {
$this->identifier[] = $mapping['fieldName'];
}
// Check for composite key
if ( ! $this->isIdentifierComposite && count($this->identifier) > 1) {
$this->isIdentifierComposite = true;
}
}
if (Type::hasType($mapping['type']) && Type::getType($mapping['type'])->canRequireSQLConversion()) {
if (isset($mapping['id']) && $mapping['id'] === true) {
throw MappingException::sqlConversionNotAllowedForIdentifiers($this->name, $mapping['fieldName'], $mapping['type']);
}
$mapping['requireSQLConversion'] = true;
}
}
/**
* Validates & completes the basic mapping information that is common to all
* association mappings (one-to-one, many-ot-one, one-to-many, many-to-many).
*
* @param array $mapping The mapping.
*
* @return array The updated mapping.
*
* @throws MappingException If something is wrong with the mapping.
*/
protected function _validateAndCompleteAssociationMapping(array $mapping)
{
if ( ! isset($mapping['mappedBy'])) {
$mapping['mappedBy'] = null;
}
if ( ! isset($mapping['inversedBy'])) {
$mapping['inversedBy'] = null;
}
$mapping['isOwningSide'] = true; // assume owning side until we hit mappedBy
// unset optional indexBy attribute if its empty
if ( ! isset($mapping['indexBy']) || !$mapping['indexBy']) {
unset($mapping['indexBy']);
}
// If targetEntity is unqualified, assume it is in the same namespace as
// the sourceEntity.
$mapping['sourceEntity'] = $this->name;
if (isset($mapping['targetEntity'])) {
$mapping['targetEntity'] = $this->fullyQualifiedClassName($mapping['targetEntity']);
$mapping['targetEntity'] = ltrim($mapping['targetEntity'], '\\');
}
if ( ($mapping['type'] & self::MANY_TO_ONE) > 0 &&
isset($mapping['orphanRemoval']) &&
$mapping['orphanRemoval'] == true) {
throw MappingException::illegalOrphanRemoval($this->name, $mapping['fieldName']);
}
// Complete id mapping
if (isset($mapping['id']) && $mapping['id'] === true) {
if (isset($mapping['orphanRemoval']) && $mapping['orphanRemoval'] == true) {
throw MappingException::illegalOrphanRemovalOnIdentifierAssociation($this->name, $mapping['fieldName']);
}
if ( ! in_array($mapping['fieldName'], $this->identifier)) {
if (isset($mapping['joinColumns']) && count($mapping['joinColumns']) >= 2) {
throw MappingException::cannotMapCompositePrimaryKeyEntitiesAsForeignId(
$mapping['targetEntity'], $this->name, $mapping['fieldName']
);
}
$this->identifier[] = $mapping['fieldName'];
$this->containsForeignIdentifier = true;
}
// Check for composite key
if ( ! $this->isIdentifierComposite && count($this->identifier) > 1) {
$this->isIdentifierComposite = true;
}
}
// Mandatory attributes for both sides
// Mandatory: fieldName, targetEntity
if ( ! isset($mapping['fieldName']) || strlen($mapping['fieldName']) == 0) {
throw MappingException::missingFieldName($this->name);
}
if ( ! isset($mapping['targetEntity'])) {
throw MappingException::missingTargetEntity($mapping['fieldName']);
}
// Mandatory and optional attributes for either side
if ( ! $mapping['mappedBy']) {
if (isset($mapping['joinTable']) && $mapping['joinTable']) {
if (isset($mapping['joinTable']['name']) && $mapping['joinTable']['name'][0] === '`') {
$mapping['joinTable']['name'] = trim($mapping['joinTable']['name'], '`');
$mapping['joinTable']['quoted'] = true;
}
}
} else {
$mapping['isOwningSide'] = false;
}
if (isset($mapping['id']) && $mapping['id'] === true && $mapping['type'] & self::TO_MANY) {
throw MappingException::illegalToManyIdentifierAssociation($this->name, $mapping['fieldName']);
}
// Fetch mode. Default fetch mode to LAZY, if not set.
if ( ! isset($mapping['fetch'])) {
$mapping['fetch'] = self::FETCH_LAZY;
}
// Cascades
$cascades = isset($mapping['cascade']) ? array_map('strtolower', $mapping['cascade']) : array();
if (in_array('all', $cascades)) {
$cascades = array('remove', 'persist', 'refresh', 'merge', 'detach');
}
if (count($cascades) !== count(array_intersect($cascades, array('remove', 'persist', 'refresh', 'merge', 'detach')))) {
throw MappingException::invalidCascadeOption(
array_diff($cascades, array_intersect($cascades, array('remove', 'persist', 'refresh', 'merge', 'detach'))),
$this->name,
$mapping['fieldName']
);
}
$mapping['cascade'] = $cascades;
$mapping['isCascadeRemove'] = in_array('remove', $cascades);
$mapping['isCascadePersist'] = in_array('persist', $cascades);
$mapping['isCascadeRefresh'] = in_array('refresh', $cascades);
$mapping['isCascadeMerge'] = in_array('merge', $cascades);
$mapping['isCascadeDetach'] = in_array('detach', $cascades);
return $mapping;
}
/**
* Validates & completes a one-to-one association mapping.
*
* @param array $mapping The mapping to validate & complete.
*
* @return array The validated & completed mapping.
*
* @throws RuntimeException
* @throws MappingException
*/
protected function _validateAndCompleteOneToOneMapping(array $mapping)
{
$mapping = $this->_validateAndCompleteAssociationMapping($mapping);
if (isset($mapping['joinColumns']) && $mapping['joinColumns']) {
$mapping['isOwningSide'] = true;
}
if ($mapping['isOwningSide']) {
if ( ! isset($mapping['joinColumns']) || ! $mapping['joinColumns']) {
// Apply default join column
$mapping['joinColumns'] = array(array(
'name' => $this->namingStrategy->joinColumnName($mapping['fieldName'], $this->name),
'referencedColumnName' => $this->namingStrategy->referenceColumnName()
));
}
$uniqueConstraintColumns = array();
foreach ($mapping['joinColumns'] as &$joinColumn) {
if ($mapping['type'] === self::ONE_TO_ONE && ! $this->isInheritanceTypeSingleTable()) {
if (count($mapping['joinColumns']) == 1) {
if ( ! isset($mapping['id']) || ! $mapping['id']) {
$joinColumn['unique'] = true;
}
} else {
$uniqueConstraintColumns[] = $joinColumn['name'];
}
}
if (empty($joinColumn['name'])) {
$joinColumn['name'] = $this->namingStrategy->joinColumnName($mapping['fieldName'], $this->name);
}
if (empty($joinColumn['referencedColumnName'])) {
$joinColumn['referencedColumnName'] = $this->namingStrategy->referenceColumnName();
}
if ($joinColumn['name'][0] === '`') {
$joinColumn['name'] = trim($joinColumn['name'], '`');
$joinColumn['quoted'] = true;
}
if ($joinColumn['referencedColumnName'][0] === '`') {
$joinColumn['referencedColumnName'] = trim($joinColumn['referencedColumnName'], '`');
$joinColumn['quoted'] = true;
}
$mapping['sourceToTargetKeyColumns'][$joinColumn['name']] = $joinColumn['referencedColumnName'];
$mapping['joinColumnFieldNames'][$joinColumn['name']] = isset($joinColumn['fieldName'])
? $joinColumn['fieldName'] : $joinColumn['name'];
}
if ($uniqueConstraintColumns) {
if ( ! $this->table) {
throw new RuntimeException("ClassMetadataInfo::setTable() has to be called before defining a one to one relationship.");
}
$this->table['uniqueConstraints'][$mapping['fieldName']."_uniq"] = array(
'columns' => $uniqueConstraintColumns
);
}
$mapping['targetToSourceKeyColumns'] = array_flip($mapping['sourceToTargetKeyColumns']);
}
$mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ? (bool) $mapping['orphanRemoval'] : false;
$mapping['isCascadeRemove'] = $mapping['orphanRemoval'] ? true : $mapping['isCascadeRemove'];
if ($mapping['orphanRemoval']) {
unset($mapping['unique']);
}
if (isset($mapping['id']) && $mapping['id'] === true && !$mapping['isOwningSide']) {
throw MappingException::illegalInverseIdentifierAssociation($this->name, $mapping['fieldName']);
}
return $mapping;
}
/**
* Validates & completes a one-to-many association mapping.
*
* @param array $mapping The mapping to validate and complete.
*
* @return array The validated and completed mapping.
*
* @throws MappingException
* @throws InvalidArgumentException
*/
protected function _validateAndCompleteOneToManyMapping(array $mapping)
{
$mapping = $this->_validateAndCompleteAssociationMapping($mapping);
// OneToMany-side MUST be inverse (must have mappedBy)
if ( ! isset($mapping['mappedBy'])) {
throw MappingException::oneToManyRequiresMappedBy($mapping['fieldName']);
}
$mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ? (bool) $mapping['orphanRemoval'] : false;
$mapping['isCascadeRemove'] = $mapping['orphanRemoval'] ? true : $mapping['isCascadeRemove'];
if (isset($mapping['orderBy'])) {
if ( ! is_array($mapping['orderBy'])) {
throw new InvalidArgumentException("'orderBy' is expected to be an array, not ".gettype($mapping['orderBy']));
}
}
return $mapping;
}
/**
* Validates & completes a many-to-many association mapping.
*
* @param array $mapping The mapping to validate & complete.
*
* @return array The validated & completed mapping.
*
* @throws \InvalidArgumentException
*/
protected function _validateAndCompleteManyToManyMapping(array $mapping)
{
$mapping = $this->_validateAndCompleteAssociationMapping($mapping);
if ($mapping['isOwningSide']) {
// owning side MUST have a join table
if ( ! isset($mapping['joinTable']['name'])) {
$mapping['joinTable']['name'] = $this->namingStrategy->joinTableName($mapping['sourceEntity'], $mapping['targetEntity'], $mapping['fieldName']);
}
$selfReferencingEntityWithoutJoinColumns = $mapping['sourceEntity'] == $mapping['targetEntity']
&& (! (isset($mapping['joinTable']['joinColumns']) || isset($mapping['joinTable']['inverseJoinColumns'])));
if ( ! isset($mapping['joinTable']['joinColumns'])) {
$mapping['joinTable']['joinColumns'] = array(array(
'name' => $this->namingStrategy->joinKeyColumnName($mapping['sourceEntity'], $selfReferencingEntityWithoutJoinColumns ? 'source' : null),
'referencedColumnName' => $this->namingStrategy->referenceColumnName(),
'onDelete' => 'CASCADE'));
}
if ( ! isset($mapping['joinTable']['inverseJoinColumns'])) {
$mapping['joinTable']['inverseJoinColumns'] = array(array(
'name' => $this->namingStrategy->joinKeyColumnName($mapping['targetEntity'], $selfReferencingEntityWithoutJoinColumns ? 'target' : null),
'referencedColumnName' => $this->namingStrategy->referenceColumnName(),
'onDelete' => 'CASCADE'));
}
$mapping['joinTableColumns'] = array();
foreach ($mapping['joinTable']['joinColumns'] as &$joinColumn) {
if (empty($joinColumn['name'])) {
$joinColumn['name'] = $this->namingStrategy->joinKeyColumnName($mapping['sourceEntity'], $joinColumn['referencedColumnName']);
}
if (empty($joinColumn['referencedColumnName'])) {
$joinColumn['referencedColumnName'] = $this->namingStrategy->referenceColumnName();
}
if ($joinColumn['name'][0] === '`') {
$joinColumn['name'] = trim($joinColumn['name'], '`');
$joinColumn['quoted'] = true;
}
if ($joinColumn['referencedColumnName'][0] === '`') {
$joinColumn['referencedColumnName'] = trim($joinColumn['referencedColumnName'], '`');
$joinColumn['quoted'] = true;
}
if (isset($joinColumn['onDelete']) && strtolower($joinColumn['onDelete']) == 'cascade') {
$mapping['isOnDeleteCascade'] = true;
}
$mapping['relationToSourceKeyColumns'][$joinColumn['name']] = $joinColumn['referencedColumnName'];
$mapping['joinTableColumns'][] = $joinColumn['name'];
}
foreach ($mapping['joinTable']['inverseJoinColumns'] as &$inverseJoinColumn) {
if (empty($inverseJoinColumn['name'])) {
$inverseJoinColumn['name'] = $this->namingStrategy->joinKeyColumnName($mapping['targetEntity'], $inverseJoinColumn['referencedColumnName']);
}
if (empty($inverseJoinColumn['referencedColumnName'])) {
$inverseJoinColumn['referencedColumnName'] = $this->namingStrategy->referenceColumnName();
}
if ($inverseJoinColumn['name'][0] === '`') {
$inverseJoinColumn['name'] = trim($inverseJoinColumn['name'], '`');
$inverseJoinColumn['quoted'] = true;
}
if ($inverseJoinColumn['referencedColumnName'][0] === '`') {
$inverseJoinColumn['referencedColumnName'] = trim($inverseJoinColumn['referencedColumnName'], '`');
$inverseJoinColumn['quoted'] = true;
}
if (isset($inverseJoinColumn['onDelete']) && strtolower($inverseJoinColumn['onDelete']) == 'cascade') {
$mapping['isOnDeleteCascade'] = true;
}
$mapping['relationToTargetKeyColumns'][$inverseJoinColumn['name']] = $inverseJoinColumn['referencedColumnName'];
$mapping['joinTableColumns'][] = $inverseJoinColumn['name'];
}
}
$mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ? (bool) $mapping['orphanRemoval'] : false;
if (isset($mapping['orderBy'])) {
if ( ! is_array($mapping['orderBy'])) {
throw new InvalidArgumentException("'orderBy' is expected to be an array, not ".gettype($mapping['orderBy']));
}
}
return $mapping;
}
/**
* {@inheritDoc}
*/
public function getIdentifierFieldNames()
{
return $this->identifier;
}
/**
* Gets the name of the single id field. Note that this only works on
* entity classes that have a single-field pk.
*
* @return string
*
* @throws MappingException If the class has a composite primary key.
*/
public function getSingleIdentifierFieldName()
{
if ($this->isIdentifierComposite) {
throw MappingException::singleIdNotAllowedOnCompositePrimaryKey($this->name);
}
return $this->identifier[0];
}
/**
* Gets the column name of the single id column. Note that this only works on
* entity classes that have a single-field pk.
*
* @return string
*
* @throws MappingException If the class has a composite primary key.
*/
public function getSingleIdentifierColumnName()
{
return $this->getColumnName($this->getSingleIdentifierFieldName());
}
/**
* INTERNAL:
* Sets the mapped identifier/primary key fields of this class.
* Mainly used by the ClassMetadataFactory to assign inherited identifiers.
*
* @param array $identifier
*
* @return void
*/
public function setIdentifier(array $identifier)
{
$this->identifier = $identifier;
$this->isIdentifierComposite = (count($this->identifier) > 1);
}
/**
* {@inheritDoc}
*/
public function getIdentifier()
{
return $this->identifier;
}
/**
* {@inheritDoc}
*/
public function hasField($fieldName)
{
return isset($this->fieldMappings[$fieldName]);
}
/**
* Gets an array containing all the column names.
*
* @param array|null $fieldNames
*
* @return array
*/
public function getColumnNames(array $fieldNames = null)
{
if ($fieldNames === null) {
return array_keys($this->fieldNames);
} else {
$columnNames = array();
foreach ($fieldNames as $fieldName) {
$columnNames[] = $this->getColumnName($fieldName);
}
return $columnNames;
}
}
/**
* Returns an array with all the identifier column names.
*
* @return array
*/
public function getIdentifierColumnNames()
{
$columnNames = array();
foreach ($this->identifier as $idProperty) {
if (isset($this->fieldMappings[$idProperty])) {
$columnNames[] = $this->fieldMappings[$idProperty]['columnName'];
continue;
}
// Association defined as Id field
$joinColumns = $this->associationMappings[$idProperty]['joinColumns'];
$assocColumnNames = array_map(function ($joinColumn) { return $joinColumn['name']; }, $joinColumns);
$columnNames = array_merge($columnNames, $assocColumnNames);
}
return $columnNames;
}
/**
* Sets the type of Id generator to use for the mapped class.
*
* @param int $generatorType
*
* @return void
*/
public function setIdGeneratorType($generatorType)
{
$this->generatorType = $generatorType;
}
/**
* Checks whether the mapped class uses an Id generator.
*
* @return boolean TRUE if the mapped class uses an Id generator, FALSE otherwise.
*/
public function usesIdGenerator()
{
return $this->generatorType != self::GENERATOR_TYPE_NONE;
}
/**
* @return boolean
*/
public function isInheritanceTypeNone()
{
return $this->inheritanceType == self::INHERITANCE_TYPE_NONE;
}
/**
* Checks whether the mapped class uses the JOINED inheritance mapping strategy.
*
* @return boolean TRUE if the class participates in a JOINED inheritance mapping,
* FALSE otherwise.
*/
public function isInheritanceTypeJoined()
{
return $this->inheritanceType == self::INHERITANCE_TYPE_JOINED;
}
/**
* Checks whether the mapped class uses the SINGLE_TABLE inheritance mapping strategy.
*
* @return boolean TRUE if the class participates in a SINGLE_TABLE inheritance mapping,
* FALSE otherwise.
*/
public function isInheritanceTypeSingleTable()
{
return $this->inheritanceType == self::INHERITANCE_TYPE_SINGLE_TABLE;
}
/**
* Checks whether the mapped class uses the TABLE_PER_CLASS inheritance mapping strategy.
*
* @return boolean TRUE if the class participates in a TABLE_PER_CLASS inheritance mapping,
* FALSE otherwise.
*/
public function isInheritanceTypeTablePerClass()
{
return $this->inheritanceType == self::INHERITANCE_TYPE_TABLE_PER_CLASS;
}
/**
* Checks whether the class uses an identity column for the Id generation.
*
* @return boolean TRUE if the class uses the IDENTITY generator, FALSE otherwise.
*/
public function isIdGeneratorIdentity()
{
return $this->generatorType == self::GENERATOR_TYPE_IDENTITY;
}
/**
* Checks whether the class uses a sequence for id generation.
*
* @return boolean TRUE if the class uses the SEQUENCE generator, FALSE otherwise.
*/
public function isIdGeneratorSequence()
{
return $this->generatorType == self::GENERATOR_TYPE_SEQUENCE;
}
/**
* Checks whether the class uses a table for id generation.
*
* @return boolean TRUE if the class uses the TABLE generator, FALSE otherwise.
*/
public function isIdGeneratorTable()
{
return $this->generatorType == self::GENERATOR_TYPE_TABLE;
}
/**
* Checks whether the class has a natural identifier/pk (which means it does
* not use any Id generator.
*
* @return boolean
*/
public function isIdentifierNatural()
{
return $this->generatorType == self::GENERATOR_TYPE_NONE;
}
/**
* Checks whether the class use a UUID for id generation.
*
* @return boolean
*/
public function isIdentifierUuid()
{
return $this->generatorType == self::GENERATOR_TYPE_UUID;
}
/**
* Gets the type of a field.
*
* @param string $fieldName
*
* @return \Doctrine\DBAL\Types\Type|string|null
*/
public function getTypeOfField($fieldName)
{
return isset($this->fieldMappings[$fieldName]) ?
$this->fieldMappings[$fieldName]['type'] : null;
}
/**
* Gets the type of a column.
*
* @param string $columnName
*
* @return \Doctrine\DBAL\Types\Type|string|null
*
* @deprecated this method is bogous and unreliable, since it cannot resolve the type of a column that is
* derived by a referenced field on a different entity.
*/
public function getTypeOfColumn($columnName)
{
return $this->getTypeOfField($this->getFieldName($columnName));
}
/**
* Gets the name of the primary table.
*
* @return string
*/
public function getTableName()
{
return $this->table['name'];
}
/**
* Gets primary table's schema name.
*
* @return string|null
*/
public function getSchemaName()
{
return isset($this->table['schema']) ? $this->table['schema'] : null;
}
/**
* Gets the table name to use for temporary identifier tables of this class.
*
* @return string
*/
public function getTemporaryIdTableName()
{
// replace dots with underscores because PostgreSQL creates temporary tables in a special schema
return str_replace('.', '_', $this->getTableName() . '_id_tmp');
}
/**
* Sets the mapped subclasses of this class.
*
* @param array $subclasses The names of all mapped subclasses.
*
* @return void
*/
public function setSubclasses(array $subclasses)
{
foreach ($subclasses as $subclass) {
$this->subClasses[] = $this->fullyQualifiedClassName($subclass);
}
}
/**
* Sets the parent class names.
* Assumes that the class names in the passed array are in the order:
* directParent -> directParentParent -> directParentParentParent ... -> root.
*
* @param array $classNames
*
* @return void
*/
public function setParentClasses(array $classNames)
{
$this->parentClasses = $classNames;
if (count($classNames) > 0) {
$this->rootEntityName = array_pop($classNames);
}
}
/**
* Sets the inheritance type used by the class and its subclasses.
*
* @param integer $type
*
* @return void
*
* @throws MappingException
*/
public function setInheritanceType($type)
{
if ( ! $this->_isInheritanceType($type)) {
throw MappingException::invalidInheritanceType($this->name, $type);
}
$this->inheritanceType = $type;
}
/**
* Sets the association to override association mapping of property for an entity relationship.
*
* @param string $fieldName
* @param array $overrideMapping
*
* @return void
*
* @throws MappingException
*/
public function setAssociationOverride($fieldName, array $overrideMapping)
{
if ( ! isset($this->associationMappings[$fieldName])) {
throw MappingException::invalidOverrideFieldName($this->name, $fieldName);
}
$mapping = $this->associationMappings[$fieldName];
if (isset($overrideMapping['joinColumns'])) {
$mapping['joinColumns'] = $overrideMapping['joinColumns'];
}
if (isset($overrideMapping['joinTable'])) {
$mapping['joinTable'] = $overrideMapping['joinTable'];
}
$mapping['joinColumnFieldNames'] = null;
$mapping['joinTableColumns'] = null;
$mapping['sourceToTargetKeyColumns'] = null;
$mapping['relationToSourceKeyColumns'] = null;
$mapping['relationToTargetKeyColumns'] = null;
switch ($mapping['type']) {
case self::ONE_TO_ONE:
$mapping = $this->_validateAndCompleteOneToOneMapping($mapping);
break;
case self::ONE_TO_MANY:
$mapping = $this->_validateAndCompleteOneToManyMapping($mapping);
break;
case self::MANY_TO_ONE:
$mapping = $this->_validateAndCompleteOneToOneMapping($mapping);
break;
case self::MANY_TO_MANY:
$mapping = $this->_validateAndCompleteManyToManyMapping($mapping);
break;
}
$this->associationMappings[$fieldName] = $mapping;
}
/**
* Sets the override for a mapped field.
*
* @param string $fieldName
* @param array $overrideMapping
*
* @return void
*
* @throws MappingException
*/
public function setAttributeOverride($fieldName, array $overrideMapping)
{
if ( ! isset($this->fieldMappings[$fieldName])) {
throw MappingException::invalidOverrideFieldName($this->name, $fieldName);
}
$mapping = $this->fieldMappings[$fieldName];
if (isset($mapping['id'])) {
$overrideMapping['id'] = $mapping['id'];
}
if ( ! isset($overrideMapping['type']) || $overrideMapping['type'] === null) {
$overrideMapping['type'] = $mapping['type'];
}
if ( ! isset($overrideMapping['fieldName']) || $overrideMapping['fieldName'] === null) {
$overrideMapping['fieldName'] = $mapping['fieldName'];
}
if ($overrideMapping['type'] !== $mapping['type']) {
throw MappingException::invalidOverrideFieldType($this->name, $fieldName);
}
unset($this->fieldMappings[$fieldName]);
unset($this->fieldNames[$mapping['columnName']]);
unset($this->columnNames[$mapping['fieldName']]);
$this->_validateAndCompleteFieldMapping($overrideMapping);
$this->fieldMappings[$fieldName] = $overrideMapping;
}
/**
* Checks whether a mapped field is inherited from an entity superclass.
*
* @param string $fieldName
*
* @return bool TRUE if the field is inherited, FALSE otherwise.
*/
public function isInheritedField($fieldName)
{
return isset($this->fieldMappings[$fieldName]['inherited']);
}
/**
* Checks if this entity is the root in any entity-inheritance-hierarchy.
*
* @return bool
*/
public function isRootEntity()
{
return $this->name == $this->rootEntityName;
}
/**
* Checks whether a mapped association field is inherited from a superclass.
*
* @param string $fieldName
*
* @return boolean TRUE if the field is inherited, FALSE otherwise.
*/
public function isInheritedAssociation($fieldName)
{
return isset($this->associationMappings[$fieldName]['inherited']);
}
public function isInheritedEmbeddedClass($fieldName)
{
return isset($this->embeddedClasses[$fieldName]['inherited']);
}
/**
* Sets the name of the primary table the class is mapped to.
*
* @param string $tableName The table name.
*
* @return void
*
* @deprecated Use {@link setPrimaryTable}.
*/
public function setTableName($tableName)
{
$this->table['name'] = $tableName;
}
/**
* Sets the primary table definition. The provided array supports the
* following structure:
*
* name => (optional, defaults to class name)
* indexes => array of indexes (optional)
* uniqueConstraints => array of constraints (optional)
*
* If a key is omitted, the current value is kept.
*
* @param array $table The table description.
*
* @return void
*/
public function setPrimaryTable(array $table)
{
if (isset($table['name'])) {
// Split schema and table name from a table name like "myschema.mytable"
if (strpos($table['name'], '.') !== false) {
list($this->table['schema'], $table['name']) = explode('.', $table['name'], 2);
}
if ($table['name'][0] === '`') {
$table['name'] = trim($table['name'], '`');
$this->table['quoted'] = true;
}
$this->table['name'] = $table['name'];
}
if (isset($table['schema'])) {
$this->table['schema'] = $table['schema'];
}
if (isset($table['indexes'])) {
$this->table['indexes'] = $table['indexes'];
}
if (isset($table['uniqueConstraints'])) {
$this->table['uniqueConstraints'] = $table['uniqueConstraints'];
}
if (isset($table['options'])) {
$this->table['options'] = $table['options'];
}
}
/**
* Checks whether the given type identifies an inheritance type.
*
* @param integer $type
*
* @return boolean TRUE if the given type identifies an inheritance type, FALSe otherwise.
*/
private function _isInheritanceType($type)
{
return $type == self::INHERITANCE_TYPE_NONE ||
$type == self::INHERITANCE_TYPE_SINGLE_TABLE ||
$type == self::INHERITANCE_TYPE_JOINED ||
$type == self::INHERITANCE_TYPE_TABLE_PER_CLASS;
}
/**
* Adds a mapped field to the class.
*
* @param array $mapping The field mapping.
*
* @return void
*
* @throws MappingException
*/
public function mapField(array $mapping)
{
$this->_validateAndCompleteFieldMapping($mapping);
$this->assertFieldNotMapped($mapping['fieldName']);
$this->fieldMappings[$mapping['fieldName']] = $mapping;
}
/**
* INTERNAL:
* Adds an association mapping without completing/validating it.
* This is mainly used to add inherited association mappings to derived classes.
*
* @param array $mapping
*
* @return void
*
* @throws MappingException
*/
public function addInheritedAssociationMapping(array $mapping/*, $owningClassName = null*/)
{
if (isset($this->associationMappings[$mapping['fieldName']])) {
throw MappingException::duplicateAssociationMapping($this->name, $mapping['fieldName']);
}
$this->associationMappings[$mapping['fieldName']] = $mapping;
}
/**
* INTERNAL:
* Adds a field mapping without completing/validating it.
* This is mainly used to add inherited field mappings to derived classes.
*
* @param array $fieldMapping
*
* @return void
*/
public function addInheritedFieldMapping(array $fieldMapping)
{
$this->fieldMappings[$fieldMapping['fieldName']] = $fieldMapping;
$this->columnNames[$fieldMapping['fieldName']] = $fieldMapping['columnName'];
$this->fieldNames[$fieldMapping['columnName']] = $fieldMapping['fieldName'];
}
/**
* INTERNAL:
* Adds a named query to this class.
*
* @param array $queryMapping
*
* @return void
*
* @throws MappingException
*/
public function addNamedQuery(array $queryMapping)
{
if (!isset($queryMapping['name'])) {
throw MappingException::nameIsMandatoryForQueryMapping($this->name);
}
if (isset($this->namedQueries[$queryMapping['name']])) {
throw MappingException::duplicateQueryMapping($this->name, $queryMapping['name']);
}
if (!isset($queryMapping['query'])) {
throw MappingException::emptyQueryMapping($this->name, $queryMapping['name']);
}
$name = $queryMapping['name'];
$query = $queryMapping['query'];
$dql = str_replace('__CLASS__', $this->name, $query);
$this->namedQueries[$name] = array(
'name' => $name,
'query' => $query,
'dql' => $dql
);
}
/**
* INTERNAL:
* Adds a named native query to this class.
*
* @param array $queryMapping
*
* @return void
*
* @throws MappingException
*/
public function addNamedNativeQuery(array $queryMapping)
{
if (!isset($queryMapping['name'])) {
throw MappingException::nameIsMandatoryForQueryMapping($this->name);
}
if (isset($this->namedNativeQueries[$queryMapping['name']])) {
throw MappingException::duplicateQueryMapping($this->name, $queryMapping['name']);
}
if (!isset($queryMapping['query'])) {
throw MappingException::emptyQueryMapping($this->name, $queryMapping['name']);
}
if (!isset($queryMapping['resultClass']) && !isset($queryMapping['resultSetMapping'])) {
throw MappingException::missingQueryMapping($this->name, $queryMapping['name']);
}
$queryMapping['isSelfClass'] = false;
if (isset($queryMapping['resultClass'])) {
if ($queryMapping['resultClass'] === '__CLASS__') {
$queryMapping['isSelfClass'] = true;
$queryMapping['resultClass'] = $this->name;
}
$queryMapping['resultClass'] = $this->fullyQualifiedClassName($queryMapping['resultClass']);
$queryMapping['resultClass'] = ltrim($queryMapping['resultClass'], '\\');
}
$this->namedNativeQueries[$queryMapping['name']] = $queryMapping;
}
/**
* INTERNAL:
* Adds a sql result set mapping to this class.
*
* @param array $resultMapping
*
* @return void
*
* @throws MappingException
*/
public function addSqlResultSetMapping(array $resultMapping)
{
if (!isset($resultMapping['name'])) {
throw MappingException::nameIsMandatoryForSqlResultSetMapping($this->name);
}
if (isset($this->sqlResultSetMappings[$resultMapping['name']])) {
throw MappingException::duplicateResultSetMapping($this->name, $resultMapping['name']);
}
if (isset($resultMapping['entities'])) {
foreach ($resultMapping['entities'] as $key => $entityResult) {
if (!isset($entityResult['entityClass'])) {
throw MappingException::missingResultSetMappingEntity($this->name, $resultMapping['name']);
}
$entityResult['isSelfClass'] = false;
if ($entityResult['entityClass'] === '__CLASS__') {
$entityResult['isSelfClass'] = true;
$entityResult['entityClass'] = $this->name;
}
$entityResult['entityClass'] = $this->fullyQualifiedClassName($entityResult['entityClass']);
$resultMapping['entities'][$key]['entityClass'] = ltrim($entityResult['entityClass'], '\\');
$resultMapping['entities'][$key]['isSelfClass'] = $entityResult['isSelfClass'];
if (isset($entityResult['fields'])) {
foreach ($entityResult['fields'] as $k => $field) {
if (!isset($field['name'])) {
throw MappingException::missingResultSetMappingFieldName($this->name, $resultMapping['name']);
}
if (!isset($field['column'])) {
$fieldName = $field['name'];
if (strpos($fieldName, '.')) {
list(, $fieldName) = explode('.', $fieldName);
}
$resultMapping['entities'][$key]['fields'][$k]['column'] = $fieldName;
}
}
}
}
}
$this->sqlResultSetMappings[$resultMapping['name']] = $resultMapping;
}
/**
* Adds a one-to-one mapping.
*
* @param array $mapping The mapping.
*
* @return void
*/
public function mapOneToOne(array $mapping)
{
$mapping['type'] = self::ONE_TO_ONE;
$mapping = $this->_validateAndCompleteOneToOneMapping($mapping);
$this->_storeAssociationMapping($mapping);
}
/**
* Adds a one-to-many mapping.
*
* @param array $mapping The mapping.
*
* @return void
*/
public function mapOneToMany(array $mapping)
{
$mapping['type'] = self::ONE_TO_MANY;
$mapping = $this->_validateAndCompleteOneToManyMapping($mapping);
$this->_storeAssociationMapping($mapping);
}
/**
* Adds a many-to-one mapping.
*
* @param array $mapping The mapping.
*
* @return void
*/
public function mapManyToOne(array $mapping)
{
$mapping['type'] = self::MANY_TO_ONE;
// A many-to-one mapping is essentially a one-one backreference
$mapping = $this->_validateAndCompleteOneToOneMapping($mapping);
$this->_storeAssociationMapping($mapping);
}
/**
* Adds a many-to-many mapping.
*
* @param array $mapping The mapping.
*
* @return void
*/
public function mapManyToMany(array $mapping)
{
$mapping['type'] = self::MANY_TO_MANY;
$mapping = $this->_validateAndCompleteManyToManyMapping($mapping);
$this->_storeAssociationMapping($mapping);
}
/**
* Stores the association mapping.
*
* @param array $assocMapping
*
* @return void
*
* @throws MappingException
*/
protected function _storeAssociationMapping(array $assocMapping)
{
$sourceFieldName = $assocMapping['fieldName'];
$this->assertFieldNotMapped($sourceFieldName);
$this->associationMappings[$sourceFieldName] = $assocMapping;
}
/**
* Registers a custom repository class for the entity class.
*
* @param string $repositoryClassName The class name of the custom mapper.
*
* @return void
*/
public function setCustomRepositoryClass($repositoryClassName)
{
$this->customRepositoryClassName = $this->fullyQualifiedClassName($repositoryClassName);
}
/**
* Dispatches the lifecycle event of the given entity to the registered
* lifecycle callbacks and lifecycle listeners.
*
* @deprecated Deprecated since version 2.4 in favor of \Doctrine\ORM\Event\ListenersInvoker
*
* @param string $lifecycleEvent The lifecycle event.
* @param object $entity The Entity on which the event occurred.
*
* @return void
*/
public function invokeLifecycleCallbacks($lifecycleEvent, $entity)
{
foreach ($this->lifecycleCallbacks[$lifecycleEvent] as $callback) {
$entity->$callback();
}
}
/**
* Whether the class has any attached lifecycle listeners or callbacks for a lifecycle event.
*
* @param string $lifecycleEvent
*
* @return boolean
*/
public function hasLifecycleCallbacks($lifecycleEvent)
{
return isset($this->lifecycleCallbacks[$lifecycleEvent]);
}
/**
* Gets the registered lifecycle callbacks for an event.
*
* @param string $event
*
* @return array
*/
public function getLifecycleCallbacks($event)
{
return isset($this->lifecycleCallbacks[$event]) ? $this->lifecycleCallbacks[$event] : array();
}
/**
* Adds a lifecycle callback for entities of this class.
*
* @param string $callback
* @param string $event
*
* @return void
*/
public function addLifecycleCallback($callback, $event)
{
if (isset($this->lifecycleCallbacks[$event]) && in_array($callback, $this->lifecycleCallbacks[$event])) {
return;
}
$this->lifecycleCallbacks[$event][] = $callback;
}
/**
* Sets the lifecycle callbacks for entities of this class.
* Any previously registered callbacks are overwritten.
*
* @param array $callbacks
*
* @return void
*/
public function setLifecycleCallbacks(array $callbacks)
{
$this->lifecycleCallbacks = $callbacks;
}
/**
* Adds a entity listener for entities of this class.
*
* @param string $eventName The entity lifecycle event.
* @param string $class The listener class.
* @param string $method The listener callback method.
*
* @throws \Doctrine\ORM\Mapping\MappingException
*/
public function addEntityListener($eventName, $class, $method)
{
$class = $this->fullyQualifiedClassName($class);
$listener = array(
'class' => $class,
'method' => $method
);
if ( ! class_exists($class)) {
throw MappingException::entityListenerClassNotFound($class, $this->name);
}
if ( ! method_exists($class, $method)) {
throw MappingException::entityListenerMethodNotFound($class, $method, $this->name);
}
if (isset($this->entityListeners[$eventName]) && in_array($listener, $this->entityListeners[$eventName])) {
throw MappingException::duplicateEntityListener($class, $method, $this->name);
}
$this->entityListeners[$eventName][] = $listener;
}
/**
* Sets the discriminator column definition.
*
* @param array $columnDef
*
* @return void
*
* @throws MappingException
*
* @see getDiscriminatorColumn()
*/
public function setDiscriminatorColumn($columnDef)
{
if ($columnDef !== null) {
if ( ! isset($columnDef['name'])) {
throw MappingException::nameIsMandatoryForDiscriminatorColumns($this->name);
}
if (isset($this->fieldNames[$columnDef['name']])) {
throw MappingException::duplicateColumnName($this->name, $columnDef['name']);
}
if ( ! isset($columnDef['fieldName'])) {
$columnDef['fieldName'] = $columnDef['name'];
}
if ( ! isset($columnDef['type'])) {
$columnDef['type'] = "string";
}
if (in_array($columnDef['type'], array("boolean", "array", "object", "datetime", "time", "date"))) {
throw MappingException::invalidDiscriminatorColumnType($this->name, $columnDef['type']);
}
$this->discriminatorColumn = $columnDef;
}
}
/**
* Sets the discriminator values used by this class.
* Used for JOINED and SINGLE_TABLE inheritance mapping strategies.
*
* @param array $map
*
* @return void
*/
public function setDiscriminatorMap(array $map)
{
foreach ($map as $value => $className) {
$this->addDiscriminatorMapClass($value, $className);
}
}
/**
* Adds one entry of the discriminator map with a new class and corresponding name.
*
* @param string $name
* @param string $className
*
* @return void
*
* @throws MappingException
*/
public function addDiscriminatorMapClass($name, $className)
{
$className = $this->fullyQualifiedClassName($className);
$className = ltrim($className, '\\');
$this->discriminatorMap[$name] = $className;
if ($this->name === $className) {
$this->discriminatorValue = $name;
return;
}
if ( ! (class_exists($className) || interface_exists($className))) {
throw MappingException::invalidClassInDiscriminatorMap($className, $this->name);
}
if (is_subclass_of($className, $this->name) && ! in_array($className, $this->subClasses)) {
$this->subClasses[] = $className;
}
}
/**
* Checks whether the class has a named query with the given query name.
*
* @param string $queryName
*
* @return boolean
*/
public function hasNamedQuery($queryName)
{
return isset($this->namedQueries[$queryName]);
}
/**
* Checks whether the class has a named native query with the given query name.
*
* @param string $queryName
*
* @return boolean
*/
public function hasNamedNativeQuery($queryName)
{
return isset($this->namedNativeQueries[$queryName]);
}
/**
* Checks whether the class has a named native query with the given query name.
*
* @param string $name
*
* @return boolean
*/
public function hasSqlResultSetMapping($name)
{
return isset($this->sqlResultSetMappings[$name]);
}
/**
* {@inheritDoc}
*/
public function hasAssociation($fieldName)
{
return isset($this->associationMappings[$fieldName]);
}
/**
* {@inheritDoc}
*/
public function isSingleValuedAssociation($fieldName)
{
return isset($this->associationMappings[$fieldName]) &&
($this->associationMappings[$fieldName]['type'] & self::TO_ONE);
}
/**
* {@inheritDoc}
*/
public function isCollectionValuedAssociation($fieldName)
{
return isset($this->associationMappings[$fieldName]) &&
! ($this->associationMappings[$fieldName]['type'] & self::TO_ONE);
}
/**
* Is this an association that only has a single join column?
*
* @param string $fieldName
*
* @return bool
*/
public function isAssociationWithSingleJoinColumn($fieldName)
{
return (
isset($this->associationMappings[$fieldName]) &&
isset($this->associationMappings[$fieldName]['joinColumns'][0]) &&
!isset($this->associationMappings[$fieldName]['joinColumns'][1])
);
}
/**
* Returns the single association join column (if any).
*
* @param string $fieldName
*
* @return string
*
* @throws MappingException
*/
public function getSingleAssociationJoinColumnName($fieldName)
{
if ( ! $this->isAssociationWithSingleJoinColumn($fieldName)) {
throw MappingException::noSingleAssociationJoinColumnFound($this->name, $fieldName);
}
return $this->associationMappings[$fieldName]['joinColumns'][0]['name'];
}
/**
* Returns the single association referenced join column name (if any).
*
* @param string $fieldName
*
* @return string
*
* @throws MappingException
*/
public function getSingleAssociationReferencedJoinColumnName($fieldName)
{
if ( ! $this->isAssociationWithSingleJoinColumn($fieldName)) {
throw MappingException::noSingleAssociationJoinColumnFound($this->name, $fieldName);
}
return $this->associationMappings[$fieldName]['joinColumns'][0]['referencedColumnName'];
}
/**
* Used to retrieve a fieldname for either field or association from a given column.
*
* This method is used in foreign-key as primary-key contexts.
*
* @param string $columnName
*
* @return string
*
* @throws MappingException
*/
public function getFieldForColumn($columnName)
{
if (isset($this->fieldNames[$columnName])) {
return $this->fieldNames[$columnName];
} else {
foreach ($this->associationMappings as $assocName => $mapping) {
if ($this->isAssociationWithSingleJoinColumn($assocName) &&
$this->associationMappings[$assocName]['joinColumns'][0]['name'] == $columnName) {
return $assocName;
}
}
throw MappingException::noFieldNameFoundForColumn($this->name, $columnName);
}
}
/**
* Sets the ID generator used to generate IDs for instances of this class.
*
* @param \Doctrine\ORM\Id\AbstractIdGenerator $generator
*
* @return void
*/
public function setIdGenerator($generator)
{
$this->idGenerator = $generator;
}
/**
* Sets definition.
*
* @param array $definition
*
* @return void
*/
public function setCustomGeneratorDefinition(array $definition)
{
$this->customGeneratorDefinition = $definition;
}
/**
* Sets the definition of the sequence ID generator for this class.
*
* The definition must have the following structure:
*
* array(
* 'sequenceName' => 'name',
* 'allocationSize' => 20,
* 'initialValue' => 1
* 'quoted' => 1
* )
*
*
* @param array $definition
*
* @return void
*/
public function setSequenceGeneratorDefinition(array $definition)
{
if ( ! isset($definition['sequenceName']) || trim($definition['sequenceName']) === '') {
throw MappingException::missingSequenceName($this->name);
}
if ($definition['sequenceName'][0] == '`') {
$definition['sequenceName'] = trim($definition['sequenceName'], '`');
$definition['quoted'] = true;
}
if ( ! isset($definition['allocationSize']) || trim($definition['allocationSize']) === '') {
$definition['allocationSize'] = '1';
}
if ( ! isset($definition['initialValue']) || trim($definition['initialValue']) === '') {
$definition['initialValue'] = '1';
}
$this->sequenceGeneratorDefinition = $definition;
}
/**
* Sets the version field mapping used for versioning. Sets the default
* value to use depending on the column type.
*
* @param array $mapping The version field mapping array.
*
* @return void
*
* @throws MappingException
*/
public function setVersionMapping(array &$mapping)
{
$this->isVersioned = true;
$this->versionField = $mapping['fieldName'];
if ( ! isset($mapping['default'])) {
if (in_array($mapping['type'], array('integer', 'bigint', 'smallint'))) {
$mapping['default'] = 1;
} else if ($mapping['type'] == 'datetime') {
$mapping['default'] = 'CURRENT_TIMESTAMP';
} else {
throw MappingException::unsupportedOptimisticLockingType($this->name, $mapping['fieldName'], $mapping['type']);
}
}
}
/**
* Sets whether this class is to be versioned for optimistic locking.
*
* @param boolean $bool
*
* @return void
*/
public function setVersioned($bool)
{
$this->isVersioned = $bool;
}
/**
* Sets the name of the field that is to be used for versioning if this class is
* versioned for optimistic locking.
*
* @param string $versionField
*
* @return void
*/
public function setVersionField($versionField)
{
$this->versionField = $versionField;
}
/**
* Marks this class as read only, no change tracking is applied to it.
*
* @return void
*/
public function markReadOnly()
{
$this->isReadOnly = true;
}
/**
* {@inheritDoc}
*/
public function getFieldNames()
{
return array_keys($this->fieldMappings);
}
/**
* {@inheritDoc}
*/
public function getAssociationNames()
{
return array_keys($this->associationMappings);
}
/**
* {@inheritDoc}
*
* @throws InvalidArgumentException
*/
public function getAssociationTargetClass($assocName)
{
if ( ! isset($this->associationMappings[$assocName])) {
throw new InvalidArgumentException("Association name expected, '" . $assocName ."' is not an association.");
}
return $this->associationMappings[$assocName]['targetEntity'];
}
/**
* {@inheritDoc}
*/
public function getName()
{
return $this->name;
}
/**
* Gets the (possibly quoted) identifier column names for safe use in an SQL statement.
*
* @deprecated Deprecated since version 2.3 in favor of \Doctrine\ORM\Mapping\QuoteStrategy
*
* @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
*
* @return array
*/
public function getQuotedIdentifierColumnNames($platform)
{
$quotedColumnNames = array();
foreach ($this->identifier as $idProperty) {
if (isset($this->fieldMappings[$idProperty])) {
$quotedColumnNames[] = isset($this->fieldMappings[$idProperty]['quoted'])
? $platform->quoteIdentifier($this->fieldMappings[$idProperty]['columnName'])
: $this->fieldMappings[$idProperty]['columnName'];
continue;
}
// Association defined as Id field
$joinColumns = $this->associationMappings[$idProperty]['joinColumns'];
$assocQuotedColumnNames = array_map(
function ($joinColumn) use ($platform) {
return isset($joinColumn['quoted'])
? $platform->quoteIdentifier($joinColumn['name'])
: $joinColumn['name'];
},
$joinColumns
);
$quotedColumnNames = array_merge($quotedColumnNames, $assocQuotedColumnNames);
}
return $quotedColumnNames;
}
/**
* Gets the (possibly quoted) column name of a mapped field for safe use in an SQL statement.
*
* @deprecated Deprecated since version 2.3 in favor of \Doctrine\ORM\Mapping\QuoteStrategy
*
* @param string $field
* @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
*
* @return string
*/
public function getQuotedColumnName($field, $platform)
{
return isset($this->fieldMappings[$field]['quoted'])
? $platform->quoteIdentifier($this->fieldMappings[$field]['columnName'])
: $this->fieldMappings[$field]['columnName'];
}
/**
* Gets the (possibly quoted) primary table name of this class for safe use in an SQL statement.
*
* @deprecated Deprecated since version 2.3 in favor of \Doctrine\ORM\Mapping\QuoteStrategy
*
* @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
*
* @return string
*/
public function getQuotedTableName($platform)
{
return isset($this->table['quoted']) ? $platform->quoteIdentifier($this->table['name']) : $this->table['name'];
}
/**
* Gets the (possibly quoted) name of the join table.
*
* @deprecated Deprecated since version 2.3 in favor of \Doctrine\ORM\Mapping\QuoteStrategy
*
* @param array $assoc
* @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
*
* @return string
*/
public function getQuotedJoinTableName(array $assoc, $platform)
{
return isset($assoc['joinTable']['quoted']) ? $platform->quoteIdentifier($assoc['joinTable']['name']) : $assoc['joinTable']['name'];
}
/**
* {@inheritDoc}
*/
public function isAssociationInverseSide($fieldName)
{
return isset($this->associationMappings[$fieldName]) && ! $this->associationMappings[$fieldName]['isOwningSide'];
}
/**
* {@inheritDoc}
*/
public function getAssociationMappedByTargetField($fieldName)
{
return $this->associationMappings[$fieldName]['mappedBy'];
}
/**
* @param string $targetClass
*
* @return array
*/
public function getAssociationsByTargetClass($targetClass)
{
$relations = array();
foreach ($this->associationMappings as $mapping) {
if ($mapping['targetEntity'] == $targetClass) {
$relations[$mapping['fieldName']] = $mapping;
}
}
return $relations;
}
/**
* @param string|null $className
* @return string|null null if the input value is null
*/
public function fullyQualifiedClassName($className)
{
if (empty($className)) {
return $className;
}
if ($className !== null && strpos($className, '\\') === false && strlen($this->namespace) > 0) {
return $this->namespace . '\\' . $className;
}
return $className;
}
/**
* @param string $name
*
* @return mixed
*/
public function getMetadataValue($name) {
if (isset($this->$name)) {
return $this->$name;
}
return null;
}
/**
* Map Embedded Class
*
* @param array $mapping
* @throws MappingException
* @return void
*/
public function mapEmbedded(array $mapping)
{
$this->assertFieldNotMapped($mapping['fieldName']);
$this->embeddedClasses[$mapping['fieldName']] = array(
'class' => $this->fullyQualifiedClassName($mapping['class']),
'columnPrefix' => $mapping['columnPrefix'],
'declaredField' => isset($mapping['declaredField']) ? $mapping['declaredField'] : null,
'originalField' => isset($mapping['originalField']) ? $mapping['originalField'] : null,
);
}
/**
* Inline the embeddable class
*
* @param string $property
* @param ClassMetadataInfo $embeddable
*/
public function inlineEmbeddable($property, ClassMetadataInfo $embeddable)
{
foreach ($embeddable->fieldMappings as $fieldMapping) {
$fieldMapping['originalClass'] = isset($fieldMapping['originalClass'])
? $fieldMapping['originalClass']
: $embeddable->name;
$fieldMapping['declaredField'] = isset($fieldMapping['declaredField'])
? $property . '.' . $fieldMapping['declaredField']
: $property;
$fieldMapping['originalField'] = isset($fieldMapping['originalField'])
? $fieldMapping['originalField']
: $fieldMapping['fieldName'];
$fieldMapping['fieldName'] = $property . "." . $fieldMapping['fieldName'];
if (! empty($this->embeddedClasses[$property]['columnPrefix'])) {
$fieldMapping['columnName'] = $this->embeddedClasses[$property]['columnPrefix'] . $fieldMapping['columnName'];
} elseif ($this->embeddedClasses[$property]['columnPrefix'] !== false) {
$fieldMapping['columnName'] = $this->namingStrategy
->embeddedFieldToColumnName(
$property,
$fieldMapping['columnName'],
$this->reflClass->name,
$embeddable->reflClass->name
);
}
$this->mapField($fieldMapping);
}
}
/**
* @param string $fieldName
* @throws MappingException
*/
private function assertFieldNotMapped($fieldName)
{
if (isset($this->fieldMappings[$fieldName]) ||
isset($this->associationMappings[$fieldName]) ||
isset($this->embeddedClasses[$fieldName])) {
throw MappingException::duplicateFieldMapping($this->name, $fieldName);
}
}
/**
* Gets the sequence name based on class metadata.
*
* @param AbstractPlatform $platform
* @return string
*
* @todo Sequence names should be computed in DBAL depending on the platform
*/
public function getSequenceName(AbstractPlatform $platform)
{
$sequencePrefix = $this->getSequencePrefix($platform);
$columnName = $this->getSingleIdentifierColumnName();
$sequenceName = $sequencePrefix . '_' . $columnName . '_seq';
return $sequenceName;
}
/**
* Gets the sequence name prefix based on class metadata.
*
* @param AbstractPlatform $platform
* @return string
*
* @todo Sequence names should be computed in DBAL depending on the platform
*/
public function getSequencePrefix(AbstractPlatform $platform)
{
$tableName = $this->getTableName();
$sequencePrefix = $tableName;
// Prepend the schema name to the table name if there is one
if ($schemaName = $this->getSchemaName()) {
$sequencePrefix = $schemaName . '.' . $tableName;
if ( ! $platform->supportsSchemas() && $platform->canEmulateSchemas()) {
$sequencePrefix = $schemaName . '__' . $tableName;
}
}
return $sequencePrefix;
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/Column.php 0000664 0000000 0000000 00000003536 13215356457 0022031 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target({"PROPERTY","ANNOTATION"})
*/
final class Column implements Annotation
{
/**
* @var string
*/
public $name;
/**
* @var mixed
*/
public $type = 'string';
/**
* @var integer
*/
public $length;
/**
* The precision for a decimal (exact numeric) column (Applies only for decimal column).
*
* @var integer
*/
public $precision = 0;
/**
* The scale for a decimal (exact numeric) column (Applies only for decimal column).
*
* @var integer
*/
public $scale = 0;
/**
* @var boolean
*/
public $unique = false;
/**
* @var boolean
*/
public $nullable = false;
/**
* @var array
*/
public $options = array();
/**
* @var string
*/
public $columnDefinition;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/ColumnResult.php 0000664 0000000 0000000 00000002731 13215356457 0023224 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* References name of a column in the SELECT clause of a SQL query.
* Scalar result types can be included in the query result by specifying this annotation in the metadata.
*
* @author Fabio B. Silva
* @since 2.3
*
* @Annotation
* @Target("ANNOTATION")
*/
final class ColumnResult implements Annotation
{
/**
* The name of a column in the SELECT clause of a SQL query.
*
* @var string
*/
public $name;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/CustomIdGenerator.php 0000664 0000000 0000000 00000002232 13215356457 0024162 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class CustomIdGenerator implements Annotation
{
/**
* @var string
*/
public $class;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/DefaultEntityListenerResolver.php 0000664 0000000 0000000 00000004322 13215356457 0026577 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* The default DefaultEntityListener
*
* @since 2.4
* @author Fabio B. Silva
*/
class DefaultEntityListenerResolver implements EntityListenerResolver
{
/**
* @var array Map to store entity listener instances.
*/
private $instances = array();
/**
* {@inheritdoc}
*/
public function clear($className = null)
{
if ($className === null) {
$this->instances = array();
return;
}
if (isset($this->instances[$className = trim($className, '\\')])) {
unset($this->instances[$className]);
}
}
/**
* {@inheritdoc}
*/
public function register($object)
{
if ( ! is_object($object)) {
throw new \InvalidArgumentException(sprintf('An object was expected, but got "%s".', gettype($object)));
}
$this->instances[get_class($object)] = $object;
}
/**
* {@inheritdoc}
*/
public function resolve($className)
{
if (isset($this->instances[$className = trim($className, '\\')])) {
return $this->instances[$className];
}
return $this->instances[$className] = new $className();
}
} doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/DefaultNamingStrategy.php 0000664 0000000 0000000 00000005242 13215356457 0025031 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* The default NamingStrategy
*
*
* @link www.doctrine-project.org
* @since 2.3
* @author Fabio B. Silva
*/
class DefaultNamingStrategy implements NamingStrategy
{
/**
* {@inheritdoc}
*/
public function classToTableName($className)
{
if (strpos($className, '\\') !== false) {
return substr($className, strrpos($className, '\\') + 1);
}
return $className;
}
/**
* {@inheritdoc}
*/
public function propertyToColumnName($propertyName, $className = null)
{
return $propertyName;
}
/**
* {@inheritdoc}
*/
public function embeddedFieldToColumnName($propertyName, $embeddedColumnName, $className = null, $embeddedClassName = null)
{
return $propertyName.'_'.$embeddedColumnName;
}
/**
* {@inheritdoc}
*/
public function referenceColumnName()
{
return 'id';
}
/**
* {@inheritdoc}
*/
public function joinColumnName($propertyName, $className = null)
{
return $propertyName . '_' . $this->referenceColumnName();
}
/**
* {@inheritdoc}
*/
public function joinTableName($sourceEntity, $targetEntity, $propertyName = null)
{
return strtolower($this->classToTableName($sourceEntity) . '_' .
$this->classToTableName($targetEntity));
}
/**
* {@inheritdoc}
*/
public function joinKeyColumnName($entityName, $referencedColumnName = null)
{
return strtolower($this->classToTableName($entityName) . '_' .
($referencedColumnName ?: $this->referenceColumnName()));
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/DefaultQuoteStrategy.php 0000664 0000000 0000000 00000013204 13215356457 0024712 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
use Doctrine\DBAL\Platforms\AbstractPlatform;
/**
* A set of rules for determining the physical column, alias and table quotes
*
* @since 2.3
* @author Fabio B. Silva
*/
class DefaultQuoteStrategy implements QuoteStrategy
{
/**
* {@inheritdoc}
*/
public function getColumnName($fieldName, ClassMetadata $class, AbstractPlatform $platform)
{
return isset($class->fieldMappings[$fieldName]['quoted'])
? $platform->quoteIdentifier($class->fieldMappings[$fieldName]['columnName'])
: $class->fieldMappings[$fieldName]['columnName'];
}
/**
* {@inheritdoc}
*
* @todo Table names should be computed in DBAL depending on the platform
*/
public function getTableName(ClassMetadata $class, AbstractPlatform $platform)
{
$tableName = $class->table['name'];
if ( ! empty($class->table['schema'])) {
$tableName = $class->table['schema'] . '.' . $class->table['name'];
if ( ! $platform->supportsSchemas() && $platform->canEmulateSchemas()) {
$tableName = $class->table['schema'] . '__' . $class->table['name'];
}
}
return isset($class->table['quoted'])
? $platform->quoteIdentifier($tableName)
: $tableName;
}
/**
* {@inheritdoc}
*/
public function getSequenceName(array $definition, ClassMetadata $class, AbstractPlatform $platform)
{
return isset($definition['quoted'])
? $platform->quoteIdentifier($definition['sequenceName'])
: $definition['sequenceName'];
}
/**
* {@inheritdoc}
*/
public function getJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform)
{
return isset($joinColumn['quoted'])
? $platform->quoteIdentifier($joinColumn['name'])
: $joinColumn['name'];
}
/**
* {@inheritdoc}
*/
public function getReferencedJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform)
{
return isset($joinColumn['quoted'])
? $platform->quoteIdentifier($joinColumn['referencedColumnName'])
: $joinColumn['referencedColumnName'];
}
/**
* {@inheritdoc}
*/
public function getJoinTableName(array $association, ClassMetadata $class, AbstractPlatform $platform)
{
$schema = '';
if (isset($association['joinTable']['schema'])) {
$schema = $association['joinTable']['schema'] . '.';
}
$tableName = $association['joinTable']['name'];
if (isset($association['joinTable']['quoted'])) {
$tableName = $platform->quoteIdentifier($tableName);
}
return $schema . $tableName;
}
/**
* {@inheritdoc}
*/
public function getIdentifierColumnNames(ClassMetadata $class, AbstractPlatform $platform)
{
$quotedColumnNames = array();
foreach ($class->identifier as $fieldName) {
if (isset($class->fieldMappings[$fieldName])) {
$quotedColumnNames[] = $this->getColumnName($fieldName, $class, $platform);
continue;
}
// Association defined as Id field
$joinColumns = $class->associationMappings[$fieldName]['joinColumns'];
$assocQuotedColumnNames = array_map(
function ($joinColumn) use ($platform)
{
return isset($joinColumn['quoted'])
? $platform->quoteIdentifier($joinColumn['name'])
: $joinColumn['name'];
},
$joinColumns
);
$quotedColumnNames = array_merge($quotedColumnNames, $assocQuotedColumnNames);
}
return $quotedColumnNames;
}
/**
* {@inheritdoc}
*/
public function getColumnAlias($columnName, $counter, AbstractPlatform $platform, ClassMetadata $class = null)
{
// 1 ) Concatenate column name and counter
// 2 ) Trim the column alias to the maximum identifier length of the platform.
// If the alias is to long, characters are cut off from the beginning.
// 3 ) Strip non alphanumeric characters
// 4 ) Prefix with "_" if the result its numeric
$columnName = $columnName . '_' . $counter;
$columnName = substr($columnName, -$platform->getMaxIdentifierLength());
$columnName = preg_replace('/[^A-Za-z0-9_]/', '', $columnName);
$columnName = is_numeric($columnName) ? '_' . $columnName : $columnName;
return $platform->getSQLResultCasing($columnName);
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/DiscriminatorColumn.php 0000664 0000000 0000000 00000002711 13215356457 0024553 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class DiscriminatorColumn implements Annotation
{
/**
* @var string
*/
public $name;
/**
* @var string
*/
public $type;
/**
* @var integer
*/
public $length;
/**
* Field name used in non-object hydration (array/scalar).
*
* @var mixed
*/
public $fieldName;
/**
* @var string
*/
public $columnDefinition;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php 0000664 0000000 0000000 00000002235 13215356457 0024034 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class DiscriminatorMap implements Annotation
{
/**
* @var array
*/
public $value;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/Driver/ 0000775 0000000 0000000 00000000000 13215356457 0021307 5 ustar 00root root 0000000 0000000 doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php 0000664 0000000 0000000 00000067247 13215356457 0025326 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\ORM\Mapping\MappingException;
use Doctrine\ORM\Mapping\JoinColumn;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\Common\Persistence\Mapping\Driver\AnnotationDriver as AbstractAnnotationDriver;
use Doctrine\ORM\Events;
/**
* The AnnotationDriver reads the mapping metadata from docblock annotations.
*
* @since 2.0
* @author Benjamin Eberlei
* @author Guilherme Blanco
* @author Jonathan H. Wage
* @author Roman Borschel
*/
class AnnotationDriver extends AbstractAnnotationDriver
{
/**
* {@inheritDoc}
*/
protected $entityAnnotationClasses = array(
'Doctrine\ORM\Mapping\Entity' => 1,
'Doctrine\ORM\Mapping\MappedSuperclass' => 2,
);
/**
* {@inheritDoc}
*/
public function loadMetadataForClass($className, ClassMetadata $metadata)
{
/* @var $metadata \Doctrine\ORM\Mapping\ClassMetadataInfo */
$class = $metadata->getReflectionClass();
if ( ! $class) {
// this happens when running annotation driver in combination with
// static reflection services. This is not the nicest fix
$class = new \ReflectionClass($metadata->name);
}
$classAnnotations = $this->reader->getClassAnnotations($class);
if ($classAnnotations) {
foreach ($classAnnotations as $key => $annot) {
if ( ! is_numeric($key)) {
continue;
}
$classAnnotations[get_class($annot)] = $annot;
}
}
// Evaluate Entity annotation
if (isset($classAnnotations['Doctrine\ORM\Mapping\Entity'])) {
$entityAnnot = $classAnnotations['Doctrine\ORM\Mapping\Entity'];
if ($entityAnnot->repositoryClass !== null) {
$metadata->setCustomRepositoryClass($entityAnnot->repositoryClass);
}
if ($entityAnnot->readOnly) {
$metadata->markReadOnly();
}
} else if (isset($classAnnotations['Doctrine\ORM\Mapping\MappedSuperclass'])) {
$mappedSuperclassAnnot = $classAnnotations['Doctrine\ORM\Mapping\MappedSuperclass'];
$metadata->setCustomRepositoryClass($mappedSuperclassAnnot->repositoryClass);
$metadata->isMappedSuperclass = true;
} else if (isset($classAnnotations['Doctrine\ORM\Mapping\Embeddable'])) {
$metadata->isEmbeddedClass = true;
} else {
throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
}
// Evaluate Table annotation
if (isset($classAnnotations['Doctrine\ORM\Mapping\Table'])) {
$tableAnnot = $classAnnotations['Doctrine\ORM\Mapping\Table'];
$primaryTable = array(
'name' => $tableAnnot->name,
'schema' => $tableAnnot->schema
);
if ($tableAnnot->indexes !== null) {
foreach ($tableAnnot->indexes as $indexAnnot) {
$index = array('columns' => $indexAnnot->columns);
if ( ! empty($indexAnnot->flags)) {
$index['flags'] = $indexAnnot->flags;
}
if ( ! empty($indexAnnot->options)) {
$index['options'] = $indexAnnot->options;
}
if ( ! empty($indexAnnot->name)) {
$primaryTable['indexes'][$indexAnnot->name] = $index;
} else {
$primaryTable['indexes'][] = $index;
}
}
}
if ($tableAnnot->uniqueConstraints !== null) {
foreach ($tableAnnot->uniqueConstraints as $uniqueConstraintAnnot) {
$uniqueConstraint = array('columns' => $uniqueConstraintAnnot->columns);
if ( ! empty($uniqueConstraintAnnot->options)) {
$uniqueConstraint['options'] = $uniqueConstraintAnnot->options;
}
if ( ! empty($uniqueConstraintAnnot->name)) {
$primaryTable['uniqueConstraints'][$uniqueConstraintAnnot->name] = $uniqueConstraint;
} else {
$primaryTable['uniqueConstraints'][] = $uniqueConstraint;
}
}
}
if ($tableAnnot->options) {
$primaryTable['options'] = $tableAnnot->options;
}
$metadata->setPrimaryTable($primaryTable);
}
// Evaluate @Cache annotation
if (isset($classAnnotations['Doctrine\ORM\Mapping\Cache'])) {
$cacheAnnot = $classAnnotations['Doctrine\ORM\Mapping\Cache'];
$cacheMap = array(
'region' => $cacheAnnot->region,
'usage' => constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $cacheAnnot->usage),
);
$metadata->enableCache($cacheMap);
}
// Evaluate NamedNativeQueries annotation
if (isset($classAnnotations['Doctrine\ORM\Mapping\NamedNativeQueries'])) {
$namedNativeQueriesAnnot = $classAnnotations['Doctrine\ORM\Mapping\NamedNativeQueries'];
foreach ($namedNativeQueriesAnnot->value as $namedNativeQuery) {
$metadata->addNamedNativeQuery(array(
'name' => $namedNativeQuery->name,
'query' => $namedNativeQuery->query,
'resultClass' => $namedNativeQuery->resultClass,
'resultSetMapping' => $namedNativeQuery->resultSetMapping,
));
}
}
// Evaluate SqlResultSetMappings annotation
if (isset($classAnnotations['Doctrine\ORM\Mapping\SqlResultSetMappings'])) {
$sqlResultSetMappingsAnnot = $classAnnotations['Doctrine\ORM\Mapping\SqlResultSetMappings'];
foreach ($sqlResultSetMappingsAnnot->value as $resultSetMapping) {
$entities = array();
$columns = array();
foreach ($resultSetMapping->entities as $entityResultAnnot) {
$entityResult = array(
'fields' => array(),
'entityClass' => $entityResultAnnot->entityClass,
'discriminatorColumn' => $entityResultAnnot->discriminatorColumn,
);
foreach ($entityResultAnnot->fields as $fieldResultAnnot) {
$entityResult['fields'][] = array(
'name' => $fieldResultAnnot->name,
'column' => $fieldResultAnnot->column
);
}
$entities[] = $entityResult;
}
foreach ($resultSetMapping->columns as $columnResultAnnot) {
$columns[] = array(
'name' => $columnResultAnnot->name,
);
}
$metadata->addSqlResultSetMapping(array(
'name' => $resultSetMapping->name,
'entities' => $entities,
'columns' => $columns
));
}
}
// Evaluate NamedQueries annotation
if (isset($classAnnotations['Doctrine\ORM\Mapping\NamedQueries'])) {
$namedQueriesAnnot = $classAnnotations['Doctrine\ORM\Mapping\NamedQueries'];
if ( ! is_array($namedQueriesAnnot->value)) {
throw new \UnexpectedValueException("@NamedQueries should contain an array of @NamedQuery annotations.");
}
foreach ($namedQueriesAnnot->value as $namedQuery) {
if ( ! ($namedQuery instanceof \Doctrine\ORM\Mapping\NamedQuery)) {
throw new \UnexpectedValueException("@NamedQueries should contain an array of @NamedQuery annotations.");
}
$metadata->addNamedQuery(array(
'name' => $namedQuery->name,
'query' => $namedQuery->query
));
}
}
// Evaluate InheritanceType annotation
if (isset($classAnnotations['Doctrine\ORM\Mapping\InheritanceType'])) {
$inheritanceTypeAnnot = $classAnnotations['Doctrine\ORM\Mapping\InheritanceType'];
$metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceTypeAnnot->value));
if ($metadata->inheritanceType != \Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_NONE) {
// Evaluate DiscriminatorColumn annotation
if (isset($classAnnotations['Doctrine\ORM\Mapping\DiscriminatorColumn'])) {
$discrColumnAnnot = $classAnnotations['Doctrine\ORM\Mapping\DiscriminatorColumn'];
$metadata->setDiscriminatorColumn(array(
'name' => $discrColumnAnnot->name,
'type' => $discrColumnAnnot->type,
'length' => $discrColumnAnnot->length,
'columnDefinition' => $discrColumnAnnot->columnDefinition
));
} else {
$metadata->setDiscriminatorColumn(array('name' => 'dtype', 'type' => 'string', 'length' => 255));
}
// Evaluate DiscriminatorMap annotation
if (isset($classAnnotations['Doctrine\ORM\Mapping\DiscriminatorMap'])) {
$discrMapAnnot = $classAnnotations['Doctrine\ORM\Mapping\DiscriminatorMap'];
$metadata->setDiscriminatorMap($discrMapAnnot->value);
}
}
}
// Evaluate DoctrineChangeTrackingPolicy annotation
if (isset($classAnnotations['Doctrine\ORM\Mapping\ChangeTrackingPolicy'])) {
$changeTrackingAnnot = $classAnnotations['Doctrine\ORM\Mapping\ChangeTrackingPolicy'];
$metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_' . $changeTrackingAnnot->value));
}
// Evaluate annotations on properties/fields
/* @var $property \ReflectionProperty */
foreach ($class->getProperties() as $property) {
if ($metadata->isMappedSuperclass && ! $property->isPrivate()
||
$metadata->isInheritedField($property->name)
||
$metadata->isInheritedAssociation($property->name)
||
$metadata->isInheritedEmbeddedClass($property->name)) {
continue;
}
$mapping = array();
$mapping['fieldName'] = $property->getName();
// Check for JoinColumn/JoinColumns annotations
$joinColumns = array();
if ($joinColumnAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinColumn')) {
$joinColumns[] = $this->joinColumnToArray($joinColumnAnnot);
} else if ($joinColumnsAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinColumns')) {
foreach ($joinColumnsAnnot->value as $joinColumn) {
$joinColumns[] = $this->joinColumnToArray($joinColumn);
}
}
// Field can only be annotated with one of:
// @Column, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany
if ($columnAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Column')) {
if ($columnAnnot->type == null) {
throw MappingException::propertyTypeIsRequired($className, $property->getName());
}
$mapping = $this->columnToArray($property->getName(), $columnAnnot);
if ($idAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) {
$mapping['id'] = true;
}
if ($generatedValueAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\GeneratedValue')) {
$metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' . $generatedValueAnnot->strategy));
}
if ($this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Version')) {
$metadata->setVersionMapping($mapping);
}
$metadata->mapField($mapping);
// Check for SequenceGenerator/TableGenerator definition
if ($seqGeneratorAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\SequenceGenerator')) {
$metadata->setSequenceGeneratorDefinition(array(
'sequenceName' => $seqGeneratorAnnot->sequenceName,
'allocationSize' => $seqGeneratorAnnot->allocationSize,
'initialValue' => $seqGeneratorAnnot->initialValue
));
} else if ($this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\TableGenerator')) {
throw MappingException::tableIdGeneratorNotImplemented($className);
} else if ($customGeneratorAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\CustomIdGenerator')) {
$metadata->setCustomGeneratorDefinition(array(
'class' => $customGeneratorAnnot->class
));
}
} else if ($oneToOneAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OneToOne')) {
if ($idAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) {
$mapping['id'] = true;
}
$mapping['targetEntity'] = $oneToOneAnnot->targetEntity;
$mapping['joinColumns'] = $joinColumns;
$mapping['mappedBy'] = $oneToOneAnnot->mappedBy;
$mapping['inversedBy'] = $oneToOneAnnot->inversedBy;
$mapping['cascade'] = $oneToOneAnnot->cascade;
$mapping['orphanRemoval'] = $oneToOneAnnot->orphanRemoval;
$mapping['fetch'] = $this->getFetchMode($className, $oneToOneAnnot->fetch);
$metadata->mapOneToOne($mapping);
} else if ($oneToManyAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OneToMany')) {
$mapping['mappedBy'] = $oneToManyAnnot->mappedBy;
$mapping['targetEntity'] = $oneToManyAnnot->targetEntity;
$mapping['cascade'] = $oneToManyAnnot->cascade;
$mapping['indexBy'] = $oneToManyAnnot->indexBy;
$mapping['orphanRemoval'] = $oneToManyAnnot->orphanRemoval;
$mapping['fetch'] = $this->getFetchMode($className, $oneToManyAnnot->fetch);
if ($orderByAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
$mapping['orderBy'] = $orderByAnnot->value;
}
$metadata->mapOneToMany($mapping);
} else if ($manyToOneAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\ManyToOne')) {
if ($idAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) {
$mapping['id'] = true;
}
$mapping['joinColumns'] = $joinColumns;
$mapping['cascade'] = $manyToOneAnnot->cascade;
$mapping['inversedBy'] = $manyToOneAnnot->inversedBy;
$mapping['targetEntity'] = $manyToOneAnnot->targetEntity;
$mapping['fetch'] = $this->getFetchMode($className, $manyToOneAnnot->fetch);
$metadata->mapManyToOne($mapping);
} else if ($manyToManyAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\ManyToMany')) {
$joinTable = array();
if ($joinTableAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinTable')) {
$joinTable = array(
'name' => $joinTableAnnot->name,
'schema' => $joinTableAnnot->schema
);
foreach ($joinTableAnnot->joinColumns as $joinColumn) {
$joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumn);
}
foreach ($joinTableAnnot->inverseJoinColumns as $joinColumn) {
$joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumn);
}
}
$mapping['joinTable'] = $joinTable;
$mapping['targetEntity'] = $manyToManyAnnot->targetEntity;
$mapping['mappedBy'] = $manyToManyAnnot->mappedBy;
$mapping['inversedBy'] = $manyToManyAnnot->inversedBy;
$mapping['cascade'] = $manyToManyAnnot->cascade;
$mapping['indexBy'] = $manyToManyAnnot->indexBy;
$mapping['orphanRemoval'] = $manyToManyAnnot->orphanRemoval;
$mapping['fetch'] = $this->getFetchMode($className, $manyToManyAnnot->fetch);
if ($orderByAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
$mapping['orderBy'] = $orderByAnnot->value;
}
$metadata->mapManyToMany($mapping);
} else if ($embeddedAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Embedded')) {
$mapping['class'] = $embeddedAnnot->class;
$mapping['columnPrefix'] = $embeddedAnnot->columnPrefix;
$metadata->mapEmbedded($mapping);
}
// Evaluate @Cache annotation
if (($cacheAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Cache')) !== null) {
$metadata->enableAssociationCache($mapping['fieldName'], array(
'usage' => constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $cacheAnnot->usage),
'region' => $cacheAnnot->region,
));
}
}
// Evaluate AssociationOverrides annotation
if (isset($classAnnotations['Doctrine\ORM\Mapping\AssociationOverrides'])) {
$associationOverridesAnnot = $classAnnotations['Doctrine\ORM\Mapping\AssociationOverrides'];
foreach ($associationOverridesAnnot->value as $associationOverride) {
$override = array();
$fieldName = $associationOverride->name;
// Check for JoinColumn/JoinColumns annotations
if ($associationOverride->joinColumns) {
$joinColumns = array();
foreach ($associationOverride->joinColumns as $joinColumn) {
$joinColumns[] = $this->joinColumnToArray($joinColumn);
}
$override['joinColumns'] = $joinColumns;
}
// Check for JoinTable annotations
if ($associationOverride->joinTable) {
$joinTableAnnot = $associationOverride->joinTable;
$joinTable = array(
'name' => $joinTableAnnot->name,
'schema' => $joinTableAnnot->schema
);
foreach ($joinTableAnnot->joinColumns as $joinColumn) {
$joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumn);
}
foreach ($joinTableAnnot->inverseJoinColumns as $joinColumn) {
$joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumn);
}
$override['joinTable'] = $joinTable;
}
$metadata->setAssociationOverride($fieldName, $override);
}
}
// Evaluate AttributeOverrides annotation
if (isset($classAnnotations['Doctrine\ORM\Mapping\AttributeOverrides'])) {
$attributeOverridesAnnot = $classAnnotations['Doctrine\ORM\Mapping\AttributeOverrides'];
foreach ($attributeOverridesAnnot->value as $attributeOverrideAnnot) {
$attributeOverride = $this->columnToArray($attributeOverrideAnnot->name, $attributeOverrideAnnot->column);
$metadata->setAttributeOverride($attributeOverrideAnnot->name, $attributeOverride);
}
}
// Evaluate EntityListeners annotation
if (isset($classAnnotations['Doctrine\ORM\Mapping\EntityListeners'])) {
$entityListenersAnnot = $classAnnotations['Doctrine\ORM\Mapping\EntityListeners'];
foreach ($entityListenersAnnot->value as $item) {
$listenerClassName = $metadata->fullyQualifiedClassName($item);
if ( ! class_exists($listenerClassName)) {
throw MappingException::entityListenerClassNotFound($listenerClassName, $className);
}
$hasMapping = false;
$listenerClass = new \ReflectionClass($listenerClassName);
/* @var $method \ReflectionMethod */
foreach ($listenerClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
// find method callbacks.
$callbacks = $this->getMethodCallbacks($method);
$hasMapping = $hasMapping ?: ( ! empty($callbacks));
foreach ($callbacks as $value) {
$metadata->addEntityListener($value[1], $listenerClassName, $value[0]);
}
}
// Evaluate the listener using naming convention.
if ( ! $hasMapping ) {
EntityListenerBuilder::bindEntityListener($metadata, $listenerClassName);
}
}
}
// Evaluate @HasLifecycleCallbacks annotation
if (isset($classAnnotations['Doctrine\ORM\Mapping\HasLifecycleCallbacks'])) {
/* @var $method \ReflectionMethod */
foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
foreach ($this->getMethodCallbacks($method) as $value) {
$metadata->addLifecycleCallback($value[0], $value[1]);
}
}
}
}
/**
* Attempts to resolve the fetch mode.
*
* @param string $className The class name.
* @param string $fetchMode The fetch mode.
*
* @return integer The fetch mode as defined in ClassMetadata.
*
* @throws MappingException If the fetch mode is not valid.
*/
private function getFetchMode($className, $fetchMode)
{
if( ! defined('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $fetchMode)) {
throw MappingException::invalidFetchMode($className, $fetchMode);
}
return constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $fetchMode);
}
/**
* Parses the given method.
*
* @param \ReflectionMethod $method
*
* @return array
*/
private function getMethodCallbacks(\ReflectionMethod $method)
{
$callbacks = array();
$annotations = $this->reader->getMethodAnnotations($method);
foreach ($annotations as $annot) {
if ($annot instanceof \Doctrine\ORM\Mapping\PrePersist) {
$callbacks[] = array($method->name, Events::prePersist);
}
if ($annot instanceof \Doctrine\ORM\Mapping\PostPersist) {
$callbacks[] = array($method->name, Events::postPersist);
}
if ($annot instanceof \Doctrine\ORM\Mapping\PreUpdate) {
$callbacks[] = array($method->name, Events::preUpdate);
}
if ($annot instanceof \Doctrine\ORM\Mapping\PostUpdate) {
$callbacks[] = array($method->name, Events::postUpdate);
}
if ($annot instanceof \Doctrine\ORM\Mapping\PreRemove) {
$callbacks[] = array($method->name, Events::preRemove);
}
if ($annot instanceof \Doctrine\ORM\Mapping\PostRemove) {
$callbacks[] = array($method->name, Events::postRemove);
}
if ($annot instanceof \Doctrine\ORM\Mapping\PostLoad) {
$callbacks[] = array($method->name, Events::postLoad);
}
if ($annot instanceof \Doctrine\ORM\Mapping\PreFlush) {
$callbacks[] = array($method->name, Events::preFlush);
}
}
return $callbacks;
}
/**
* Parse the given JoinColumn as array
*
* @param JoinColumn $joinColumn
* @return array
*/
private function joinColumnToArray(JoinColumn $joinColumn)
{
return array(
'name' => $joinColumn->name,
'unique' => $joinColumn->unique,
'nullable' => $joinColumn->nullable,
'onDelete' => $joinColumn->onDelete,
'columnDefinition' => $joinColumn->columnDefinition,
'referencedColumnName' => $joinColumn->referencedColumnName,
);
}
/**
* Parse the given Column as array
*
* @param string $fieldName
* @param Column $column
*
* @return array
*/
private function columnToArray($fieldName, Column $column)
{
$mapping = array(
'fieldName' => $fieldName,
'type' => $column->type,
'scale' => $column->scale,
'length' => $column->length,
'unique' => $column->unique,
'nullable' => $column->nullable,
'precision' => $column->precision
);
if ($column->options) {
$mapping['options'] = $column->options;
}
if (isset($column->name)) {
$mapping['columnName'] = $column->name;
}
if (isset($column->columnDefinition)) {
$mapping['columnDefinition'] = $column->columnDefinition;
}
return $mapping;
}
/**
* Factory method for the Annotation Driver.
*
* @param array|string $paths
* @param AnnotationReader|null $reader
*
* @return AnnotationDriver
*/
static public function create($paths = array(), AnnotationReader $reader = null)
{
if ($reader == null) {
$reader = new AnnotationReader();
}
return new self($reader, $paths);
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php 0000664 0000000 0000000 00000043425 13215356457 0024710 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\Common\Util\Inflector;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Doctrine\DBAL\Schema\SchemaException;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\Column;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\Mapping\MappingException;
/**
* The DatabaseDriver reverse engineers the mapping metadata from a database.
*
* @link www.doctrine-project.org
* @since 2.0
* @author Guilherme Blanco
* @author Jonathan Wage
* @author Benjamin Eberlei
*/
class DatabaseDriver implements MappingDriver
{
/**
* @var AbstractSchemaManager
*/
private $_sm;
/**
* @var array|null
*/
private $tables = null;
/**
* @var array
*/
private $classToTableNames = array();
/**
* @var array
*/
private $manyToManyTables = array();
/**
* @var array
*/
private $classNamesForTables = array();
/**
* @var array
*/
private $fieldNamesForColumns = array();
/**
* The namespace for the generated entities.
*
* @var string|null
*/
private $namespace;
/**
* @param AbstractSchemaManager $schemaManager
*/
public function __construct(AbstractSchemaManager $schemaManager)
{
$this->_sm = $schemaManager;
}
/**
* Set the namespace for the generated entities.
*
* @param string $namespace
*
* @return void
*/
public function setNamespace($namespace)
{
$this->namespace = $namespace;
}
/**
* {@inheritDoc}
*/
public function isTransient($className)
{
return true;
}
/**
* {@inheritDoc}
*/
public function getAllClassNames()
{
$this->reverseEngineerMappingFromDatabase();
return array_keys($this->classToTableNames);
}
/**
* Sets class name for a table.
*
* @param string $tableName
* @param string $className
*
* @return void
*/
public function setClassNameForTable($tableName, $className)
{
$this->classNamesForTables[$tableName] = $className;
}
/**
* Sets field name for a column on a specific table.
*
* @param string $tableName
* @param string $columnName
* @param string $fieldName
*
* @return void
*/
public function setFieldNameForColumn($tableName, $columnName, $fieldName)
{
$this->fieldNamesForColumns[$tableName][$columnName] = $fieldName;
}
/**
* Sets tables manually instead of relying on the reverse engineering capabilities of SchemaManager.
*
* @param array $entityTables
* @param array $manyToManyTables
*
* @return void
*/
public function setTables($entityTables, $manyToManyTables)
{
$this->tables = $this->manyToManyTables = $this->classToTableNames = array();
foreach ($entityTables as $table) {
$className = $this->getClassNameForTable($table->getName());
$this->classToTableNames[$className] = $table->getName();
$this->tables[$table->getName()] = $table;
}
foreach ($manyToManyTables as $table) {
$this->manyToManyTables[$table->getName()] = $table;
}
}
/**
* {@inheritDoc}
*/
public function loadMetadataForClass($className, ClassMetadata $metadata)
{
$this->reverseEngineerMappingFromDatabase();
if ( ! isset($this->classToTableNames[$className])) {
throw new \InvalidArgumentException("Unknown class " . $className);
}
$tableName = $this->classToTableNames[$className];
$metadata->name = $className;
$metadata->table['name'] = $tableName;
$this->buildIndexes($metadata);
$this->buildFieldMappings($metadata);
$this->buildToOneAssociationMappings($metadata);
foreach ($this->manyToManyTables as $manyTable) {
foreach ($manyTable->getForeignKeys() as $foreignKey) {
// foreign key maps to the table of the current entity, many to many association probably exists
if ( ! (strtolower($tableName) === strtolower($foreignKey->getForeignTableName()))) {
continue;
}
$myFk = $foreignKey;
$otherFk = null;
foreach ($manyTable->getForeignKeys() as $foreignKey) {
if ($foreignKey != $myFk) {
$otherFk = $foreignKey;
break;
}
}
if ( ! $otherFk) {
// the definition of this many to many table does not contain
// enough foreign key information to continue reverse engineering.
continue;
}
$localColumn = current($myFk->getColumns());
$associationMapping = array();
$associationMapping['fieldName'] = $this->getFieldNameForColumn($manyTable->getName(), current($otherFk->getColumns()), true);
$associationMapping['targetEntity'] = $this->getClassNameForTable($otherFk->getForeignTableName());
if (current($manyTable->getColumns())->getName() == $localColumn) {
$associationMapping['inversedBy'] = $this->getFieldNameForColumn($manyTable->getName(), current($myFk->getColumns()), true);
$associationMapping['joinTable'] = array(
'name' => strtolower($manyTable->getName()),
'joinColumns' => array(),
'inverseJoinColumns' => array(),
);
$fkCols = $myFk->getForeignColumns();
$cols = $myFk->getColumns();
for ($i = 0; $i < count($cols); $i++) {
$associationMapping['joinTable']['joinColumns'][] = array(
'name' => $cols[$i],
'referencedColumnName' => $fkCols[$i],
);
}
$fkCols = $otherFk->getForeignColumns();
$cols = $otherFk->getColumns();
for ($i = 0; $i < count($cols); $i++) {
$associationMapping['joinTable']['inverseJoinColumns'][] = array(
'name' => $cols[$i],
'referencedColumnName' => $fkCols[$i],
);
}
} else {
$associationMapping['mappedBy'] = $this->getFieldNameForColumn($manyTable->getName(), current($myFk->getColumns()), true);
}
$metadata->mapManyToMany($associationMapping);
break;
}
}
}
/**
* @return void
*
* @throws \Doctrine\ORM\Mapping\MappingException
*/
private function reverseEngineerMappingFromDatabase()
{
if ($this->tables !== null) {
return;
}
$tables = array();
foreach ($this->_sm->listTableNames() as $tableName) {
$tables[$tableName] = $this->_sm->listTableDetails($tableName);
}
$this->tables = $this->manyToManyTables = $this->classToTableNames = array();
foreach ($tables as $tableName => $table) {
$foreignKeys = ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints())
? $table->getForeignKeys()
: array();
$allForeignKeyColumns = array();
foreach ($foreignKeys as $foreignKey) {
$allForeignKeyColumns = array_merge($allForeignKeyColumns, $foreignKey->getLocalColumns());
}
if ( ! $table->hasPrimaryKey()) {
throw new MappingException(
"Table " . $table->getName() . " has no primary key. Doctrine does not ".
"support reverse engineering from tables that don't have a primary key."
);
}
$pkColumns = $table->getPrimaryKey()->getColumns();
sort($pkColumns);
sort($allForeignKeyColumns);
if ($pkColumns == $allForeignKeyColumns && count($foreignKeys) == 2) {
$this->manyToManyTables[$tableName] = $table;
} else {
// lower-casing is necessary because of Oracle Uppercase Tablenames,
// assumption is lower-case + underscore separated.
$className = $this->getClassNameForTable($tableName);
$this->tables[$tableName] = $table;
$this->classToTableNames[$className] = $tableName;
}
}
}
/**
* Build indexes from a class metadata.
*
* @param \Doctrine\ORM\Mapping\ClassMetadataInfo $metadata
*/
private function buildIndexes(ClassMetadataInfo $metadata)
{
$tableName = $metadata->table['name'];
$indexes = $this->tables[$tableName]->getIndexes();
foreach($indexes as $index){
if ($index->isPrimary()) {
continue;
}
$indexName = $index->getName();
$indexColumns = $index->getColumns();
$constraintType = $index->isUnique()
? 'uniqueConstraints'
: 'indexes';
$metadata->table[$constraintType][$indexName]['columns'] = $indexColumns;
}
}
/**
* Build field mapping from class metadata.
*
* @param \Doctrine\ORM\Mapping\ClassMetadataInfo $metadata
*/
private function buildFieldMappings(ClassMetadataInfo $metadata)
{
$tableName = $metadata->table['name'];
$columns = $this->tables[$tableName]->getColumns();
$primaryKeys = $this->getTablePrimaryKeys($this->tables[$tableName]);
$foreignKeys = $this->getTableForeignKeys($this->tables[$tableName]);
$allForeignKeys = array();
foreach ($foreignKeys as $foreignKey) {
$allForeignKeys = array_merge($allForeignKeys, $foreignKey->getLocalColumns());
}
$ids = array();
$fieldMappings = array();
foreach ($columns as $column) {
if (in_array($column->getName(), $allForeignKeys)) {
continue;
}
$fieldMapping = $this->buildFieldMapping($tableName, $column);
if ($primaryKeys && in_array($column->getName(), $primaryKeys)) {
$fieldMapping['id'] = true;
$ids[] = $fieldMapping;
}
$fieldMappings[] = $fieldMapping;
}
// We need to check for the columns here, because we might have associations as id as well.
if ($ids && count($primaryKeys) == 1) {
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
}
foreach ($fieldMappings as $fieldMapping) {
$metadata->mapField($fieldMapping);
}
}
/**
* Build field mapping from a schema column definition
*
* @param string $tableName
* @param \Doctrine\DBAL\Schema\Column $column
*
* @return array
*/
private function buildFieldMapping($tableName, Column $column)
{
$fieldMapping = array(
'fieldName' => $this->getFieldNameForColumn($tableName, $column->getName(), false),
'columnName' => $column->getName(),
'type' => $column->getType()->getName(),
'nullable' => ( ! $column->getNotNull()),
);
// Type specific elements
switch ($fieldMapping['type']) {
case Type::TARRAY:
case Type::BLOB:
case Type::GUID:
case Type::JSON_ARRAY:
case Type::OBJECT:
case Type::SIMPLE_ARRAY:
case Type::STRING:
case Type::TEXT:
$fieldMapping['length'] = $column->getLength();
$fieldMapping['options']['fixed'] = $column->getFixed();
break;
case Type::DECIMAL:
case Type::FLOAT:
$fieldMapping['precision'] = $column->getPrecision();
$fieldMapping['scale'] = $column->getScale();
break;
case Type::INTEGER:
case Type::BIGINT:
case Type::SMALLINT:
$fieldMapping['options']['unsigned'] = $column->getUnsigned();
break;
}
// Comment
if (($comment = $column->getComment()) !== null) {
$fieldMapping['options']['comment'] = $comment;
}
// Default
if (($default = $column->getDefault()) !== null) {
$fieldMapping['options']['default'] = $default;
}
return $fieldMapping;
}
/**
* Build to one (one to one, many to one) association mapping from class metadata.
*
* @param \Doctrine\ORM\Mapping\ClassMetadataInfo $metadata
*/
private function buildToOneAssociationMappings(ClassMetadataInfo $metadata)
{
$tableName = $metadata->table['name'];
$primaryKeys = $this->getTablePrimaryKeys($this->tables[$tableName]);
$foreignKeys = $this->getTableForeignKeys($this->tables[$tableName]);
foreach ($foreignKeys as $foreignKey) {
$foreignTableName = $foreignKey->getForeignTableName();
$fkColumns = $foreignKey->getColumns();
$fkForeignColumns = $foreignKey->getForeignColumns();
$localColumn = current($fkColumns);
$associationMapping = array(
'fieldName' => $this->getFieldNameForColumn($tableName, $localColumn, true),
'targetEntity' => $this->getClassNameForTable($foreignTableName),
);
if (isset($metadata->fieldMappings[$associationMapping['fieldName']])) {
$associationMapping['fieldName'] .= '2'; // "foo" => "foo2"
}
if ($primaryKeys && in_array($localColumn, $primaryKeys)) {
$associationMapping['id'] = true;
}
for ($i = 0; $i < count($fkColumns); $i++) {
$associationMapping['joinColumns'][] = array(
'name' => $fkColumns[$i],
'referencedColumnName' => $fkForeignColumns[$i],
);
}
// Here we need to check if $fkColumns are the same as $primaryKeys
if ( ! array_diff($fkColumns, $primaryKeys)) {
$metadata->mapOneToOne($associationMapping);
} else {
$metadata->mapManyToOne($associationMapping);
}
}
}
/**
* Retreive schema table definition foreign keys.
*
* @param \Doctrine\DBAL\Schema\Table $table
*
* @return array
*/
private function getTableForeignKeys(Table $table)
{
return ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints())
? $table->getForeignKeys()
: array();
}
/**
* Retreive schema table definition primary keys.
*
* @param \Doctrine\DBAL\Schema\Table $table
*
* @return array
*/
private function getTablePrimaryKeys(Table $table)
{
try {
return $table->getPrimaryKey()->getColumns();
} catch(SchemaException $e) {
// Do nothing
}
return array();
}
/**
* Returns the mapped class name for a table if it exists. Otherwise return "classified" version.
*
* @param string $tableName
*
* @return string
*/
private function getClassNameForTable($tableName)
{
if (isset($this->classNamesForTables[$tableName])) {
return $this->namespace . $this->classNamesForTables[$tableName];
}
return $this->namespace . Inflector::classify(strtolower($tableName));
}
/**
* Return the mapped field name for a column, if it exists. Otherwise return camelized version.
*
* @param string $tableName
* @param string $columnName
* @param boolean $fk Whether the column is a foreignkey or not.
*
* @return string
*/
private function getFieldNameForColumn($tableName, $columnName, $fk = false)
{
if (isset($this->fieldNamesForColumns[$tableName]) && isset($this->fieldNamesForColumns[$tableName][$columnName])) {
return $this->fieldNamesForColumns[$tableName][$columnName];
}
$columnName = strtolower($columnName);
// Replace _id if it is a foreignkey column
if ($fk) {
$columnName = str_replace('_id', '', $columnName);
}
return Inflector::camelize($columnName);
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php 0000664 0000000 0000000 00000006251 13215356457 0026011 0 ustar 00root root 0000000 0000000 .
*/
require_once __DIR__.'/../Annotation.php';
require_once __DIR__.'/../Entity.php';
require_once __DIR__.'/../Embeddable.php';
require_once __DIR__.'/../Embedded.php';
require_once __DIR__.'/../MappedSuperclass.php';
require_once __DIR__.'/../InheritanceType.php';
require_once __DIR__.'/../DiscriminatorColumn.php';
require_once __DIR__.'/../DiscriminatorMap.php';
require_once __DIR__.'/../Id.php';
require_once __DIR__.'/../GeneratedValue.php';
require_once __DIR__.'/../Version.php';
require_once __DIR__.'/../JoinColumn.php';
require_once __DIR__.'/../JoinColumns.php';
require_once __DIR__.'/../Column.php';
require_once __DIR__.'/../OneToOne.php';
require_once __DIR__.'/../OneToMany.php';
require_once __DIR__.'/../ManyToOne.php';
require_once __DIR__.'/../ManyToMany.php';
require_once __DIR__.'/../Table.php';
require_once __DIR__.'/../UniqueConstraint.php';
require_once __DIR__.'/../Index.php';
require_once __DIR__.'/../JoinTable.php';
require_once __DIR__.'/../SequenceGenerator.php';
require_once __DIR__.'/../CustomIdGenerator.php';
require_once __DIR__.'/../ChangeTrackingPolicy.php';
require_once __DIR__.'/../OrderBy.php';
require_once __DIR__.'/../NamedQueries.php';
require_once __DIR__.'/../NamedQuery.php';
require_once __DIR__.'/../HasLifecycleCallbacks.php';
require_once __DIR__.'/../PrePersist.php';
require_once __DIR__.'/../PostPersist.php';
require_once __DIR__.'/../PreUpdate.php';
require_once __DIR__.'/../PostUpdate.php';
require_once __DIR__.'/../PreRemove.php';
require_once __DIR__.'/../PostRemove.php';
require_once __DIR__.'/../PostLoad.php';
require_once __DIR__.'/../PreFlush.php';
require_once __DIR__.'/../FieldResult.php';
require_once __DIR__.'/../ColumnResult.php';
require_once __DIR__.'/../EntityResult.php';
require_once __DIR__.'/../NamedNativeQuery.php';
require_once __DIR__.'/../NamedNativeQueries.php';
require_once __DIR__.'/../SqlResultSetMapping.php';
require_once __DIR__.'/../SqlResultSetMappings.php';
require_once __DIR__.'/../AssociationOverride.php';
require_once __DIR__.'/../AssociationOverrides.php';
require_once __DIR__.'/../AttributeOverride.php';
require_once __DIR__.'/../AttributeOverrides.php';
require_once __DIR__.'/../EntityListeners.php';
require_once __DIR__.'/../Cache.php';
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/Driver/DriverChain.php 0000664 0000000 0000000 00000002414 13215356457 0024217 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain;
/**
* {@inheritDoc}
*
* @deprecated this driver will be removed. Use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain instead
*/
class DriverChain extends MappingDriverChain
{
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/Driver/PHPDriver.php 0000664 0000000 0000000 00000002410 13215356457 0023620 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\Driver\PHPDriver as CommonPHPDriver;
/**
* {@inheritDoc}
*
* @deprecated this driver will be removed. Use Doctrine\Common\Persistence\Mapping\Driver\PHPDriver instead
*/
class PHPDriver extends CommonPHPDriver
{
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/Driver/SimplifiedXmlDriver.php 0000664 0000000 0000000 00000003205 13215356457 0025742 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\Driver\SymfonyFileLocator;
/**
* XmlDriver that additionally looks for mapping information in a global file.
*
* @author Fabien Potencier
* @author Benjamin Eberlei
* @license MIT
*/
class SimplifiedXmlDriver extends XmlDriver
{
const DEFAULT_FILE_EXTENSION = '.orm.xml';
/**
* {@inheritDoc}
*/
public function __construct($prefixes, $fileExtension = self::DEFAULT_FILE_EXTENSION)
{
$locator = new SymfonyFileLocator((array) $prefixes, $fileExtension);
parent::__construct($locator, $fileExtension);
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/Driver/SimplifiedYamlDriver.php 0000664 0000000 0000000 00000003210 13215356457 0026100 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\Driver\SymfonyFileLocator;
/**
* YamlDriver that additionally looks for mapping information in a global file.
*
* @author Fabien Potencier
* @author Benjamin Eberlei
* @license MIT
*/
class SimplifiedYamlDriver extends YamlDriver
{
const DEFAULT_FILE_EXTENSION = '.orm.yml';
/**
* {@inheritDoc}
*/
public function __construct($prefixes, $fileExtension = self::DEFAULT_FILE_EXTENSION)
{
$locator = new SymfonyFileLocator((array) $prefixes, $fileExtension);
parent::__construct($locator, $fileExtension);
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/Driver/StaticPHPDriver.php 0000664 0000000 0000000 00000002446 13215356457 0025001 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\Driver\StaticPHPDriver as CommonStaticPHPDriver;
/**
* {@inheritDoc}
*
* @deprecated this driver will be removed. Use Doctrine\Common\Persistence\Mapping\Driver\StaticPHPDriver instead
*/
class StaticPHPDriver extends CommonStaticPHPDriver
{
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php 0000664 0000000 0000000 00000104553 13215356457 0023744 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping\Driver;
use SimpleXMLElement;
use Doctrine\Common\Persistence\Mapping\Driver\FileDriver;
use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\MappingException;
/**
* XmlDriver is a metadata driver that enables mapping through XML files.
*
* @license http://www.opensource.org/licenses/mit-license.php MIT
* @link www.doctrine-project.org
* @since 2.0
* @author Benjamin Eberlei
* @author Guilherme Blanco
* @author Jonathan H. Wage
* @author Roman Borschel
*/
class XmlDriver extends FileDriver
{
const DEFAULT_FILE_EXTENSION = '.dcm.xml';
/**
* {@inheritDoc}
*/
public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENSION)
{
parent::__construct($locator, $fileExtension);
}
/**
* {@inheritDoc}
*/
public function loadMetadataForClass($className, ClassMetadata $metadata)
{
/* @var $metadata \Doctrine\ORM\Mapping\ClassMetadataInfo */
/* @var $xmlRoot SimpleXMLElement */
$xmlRoot = $this->getElement($className);
if ($xmlRoot->getName() == 'entity') {
if (isset($xmlRoot['repository-class'])) {
$metadata->setCustomRepositoryClass((string)$xmlRoot['repository-class']);
}
if (isset($xmlRoot['read-only']) && $this->evaluateBoolean($xmlRoot['read-only'])) {
$metadata->markReadOnly();
}
} else if ($xmlRoot->getName() == 'mapped-superclass') {
$metadata->setCustomRepositoryClass(
isset($xmlRoot['repository-class']) ? (string)$xmlRoot['repository-class'] : null
);
$metadata->isMappedSuperclass = true;
} else if ($xmlRoot->getName() == 'embeddable') {
$metadata->isEmbeddedClass = true;
} else {
throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
}
// Evaluate attributes
$primaryTable = array();
if (isset($xmlRoot['table'])) {
$primaryTable['name'] = (string) $xmlRoot['table'];
}
if (isset($xmlRoot['schema'])) {
$primaryTable['schema'] = (string) $xmlRoot['schema'];
}
$metadata->setPrimaryTable($primaryTable);
// Evaluate second level cache
if (isset($xmlRoot->cache)) {
$metadata->enableCache($this->cacheToArray($xmlRoot->cache));
}
// Evaluate named queries
if (isset($xmlRoot->{'named-queries'})) {
foreach ($xmlRoot->{'named-queries'}->{'named-query'} as $namedQueryElement) {
$metadata->addNamedQuery(array(
'name' => (string)$namedQueryElement['name'],
'query' => (string)$namedQueryElement['query']
));
}
}
// Evaluate native named queries
if (isset($xmlRoot->{'named-native-queries'})) {
foreach ($xmlRoot->{'named-native-queries'}->{'named-native-query'} as $nativeQueryElement) {
$metadata->addNamedNativeQuery(array(
'name' => isset($nativeQueryElement['name']) ? (string)$nativeQueryElement['name'] : null,
'query' => isset($nativeQueryElement->query) ? (string)$nativeQueryElement->query : null,
'resultClass' => isset($nativeQueryElement['result-class']) ? (string)$nativeQueryElement['result-class'] : null,
'resultSetMapping' => isset($nativeQueryElement['result-set-mapping']) ? (string)$nativeQueryElement['result-set-mapping'] : null,
));
}
}
// Evaluate sql result set mapping
if (isset($xmlRoot->{'sql-result-set-mappings'})) {
foreach ($xmlRoot->{'sql-result-set-mappings'}->{'sql-result-set-mapping'} as $rsmElement) {
$entities = array();
$columns = array();
foreach ($rsmElement as $entityElement) {
//
if (isset($entityElement['entity-class'])) {
$entityResult = array(
'fields' => array(),
'entityClass' => (string)$entityElement['entity-class'],
'discriminatorColumn' => isset($entityElement['discriminator-column']) ? (string)$entityElement['discriminator-column'] : null,
);
foreach ($entityElement as $fieldElement) {
$entityResult['fields'][] = array(
'name' => isset($fieldElement['name']) ? (string)$fieldElement['name'] : null,
'column' => isset($fieldElement['column']) ? (string)$fieldElement['column'] : null,
);
}
$entities[] = $entityResult;
}
//
if (isset($entityElement['name'])) {
$columns[] = array(
'name' => (string)$entityElement['name'],
);
}
}
$metadata->addSqlResultSetMapping(array(
'name' => (string)$rsmElement['name'],
'entities' => $entities,
'columns' => $columns
));
}
}
if (isset($xmlRoot['inheritance-type'])) {
$inheritanceType = (string)$xmlRoot['inheritance-type'];
$metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceType));
if ($metadata->inheritanceType != \Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_NONE) {
// Evaluate
if (isset($xmlRoot->{'discriminator-column'})) {
$discrColumn = $xmlRoot->{'discriminator-column'};
$metadata->setDiscriminatorColumn(array(
'name' => isset($discrColumn['name']) ? (string)$discrColumn['name'] : null,
'type' => isset($discrColumn['type']) ? (string)$discrColumn['type'] : null,
'length' => isset($discrColumn['length']) ? (string)$discrColumn['length'] : null,
'columnDefinition' => isset($discrColumn['column-definition']) ? (string)$discrColumn['column-definition'] : null
));
} else {
$metadata->setDiscriminatorColumn(array('name' => 'dtype', 'type' => 'string', 'length' => 255));
}
// Evaluate
if (isset($xmlRoot->{'discriminator-map'})) {
$map = array();
foreach ($xmlRoot->{'discriminator-map'}->{'discriminator-mapping'} as $discrMapElement) {
$map[(string)$discrMapElement['value']] = (string)$discrMapElement['class'];
}
$metadata->setDiscriminatorMap($map);
}
}
}
// Evaluate
if (isset($xmlRoot['change-tracking-policy'])) {
$metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_'
. strtoupper((string)$xmlRoot['change-tracking-policy'])));
}
// Evaluate
if (isset($xmlRoot->indexes)) {
$metadata->table['indexes'] = array();
foreach ($xmlRoot->indexes->index as $indexXml) {
$index = array('columns' => explode(',', (string) $indexXml['columns']));
if (isset($indexXml['flags'])) {
$index['flags'] = explode(',', (string) $indexXml['flags']);
}
if (isset($indexXml->options)) {
$index['options'] = $this->_parseOptions($indexXml->options->children());
}
if (isset($indexXml['name'])) {
$metadata->table['indexes'][(string) $indexXml['name']] = $index;
} else {
$metadata->table['indexes'][] = $index;
}
}
}
// Evaluate
if (isset($xmlRoot->{'unique-constraints'})) {
$metadata->table['uniqueConstraints'] = array();
foreach ($xmlRoot->{'unique-constraints'}->{'unique-constraint'} as $uniqueXml) {
$unique = array('columns' => explode(',', (string) $uniqueXml['columns']));
if (isset($uniqueXml->options)) {
$unique['options'] = $this->_parseOptions($uniqueXml->options->children());
}
if (isset($uniqueXml['name'])) {
$metadata->table['uniqueConstraints'][(string)$uniqueXml['name']] = $unique;
} else {
$metadata->table['uniqueConstraints'][] = $unique;
}
}
}
if (isset($xmlRoot->options)) {
$metadata->table['options'] = $this->_parseOptions($xmlRoot->options->children());
}
// The mapping assignment is done in 2 times as a bug might occurs on some php/xml lib versions
// The internal SimpleXmlIterator get resetted, to this generate a duplicate field exception
$mappings = array();
// Evaluate mappings
if (isset($xmlRoot->field)) {
foreach ($xmlRoot->field as $fieldMapping) {
$mapping = $this->columnToArray($fieldMapping);
if (isset($mapping['version'])) {
$metadata->setVersionMapping($mapping);
unset($mapping['version']);
}
$metadata->mapField($mapping);
}
}
if (isset($xmlRoot->embedded)) {
foreach ($xmlRoot->embedded as $embeddedMapping) {
$columnPrefix = isset($embeddedMapping['column-prefix'])
? (string) $embeddedMapping['column-prefix']
: null;
$useColumnPrefix = isset($embeddedMapping['use-column-prefix'])
? $this->evaluateBoolean($embeddedMapping['use-column-prefix'])
: true;
$mapping = array(
'fieldName' => (string) $embeddedMapping['name'],
'class' => (string) $embeddedMapping['class'],
'columnPrefix' => $useColumnPrefix ? $columnPrefix : false
);
$metadata->mapEmbedded($mapping);
}
}
foreach ($mappings as $mapping) {
if (isset($mapping['version'])) {
$metadata->setVersionMapping($mapping);
}
$metadata->mapField($mapping);
}
// Evaluate mappings
$associationIds = array();
foreach ($xmlRoot->id as $idElement) {
if (isset($idElement['association-key']) && $this->evaluateBoolean($idElement['association-key'])) {
$associationIds[(string)$idElement['name']] = true;
continue;
}
$mapping = array(
'id' => true,
'fieldName' => (string)$idElement['name']
);
if (isset($idElement['type'])) {
$mapping['type'] = (string)$idElement['type'];
}
if (isset($idElement['length'])) {
$mapping['length'] = (string)$idElement['length'];
}
if (isset($idElement['column'])) {
$mapping['columnName'] = (string)$idElement['column'];
}
if (isset($idElement['column-definition'])) {
$mapping['columnDefinition'] = (string)$idElement['column-definition'];
}
if (isset($idElement->options)) {
$mapping['options'] = $this->_parseOptions($idElement->options->children());
}
$metadata->mapField($mapping);
if (isset($idElement->generator)) {
$strategy = isset($idElement->generator['strategy']) ?
(string)$idElement->generator['strategy'] : 'AUTO';
$metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_'
. $strategy));
}
// Check for SequenceGenerator/TableGenerator definition
if (isset($idElement->{'sequence-generator'})) {
$seqGenerator = $idElement->{'sequence-generator'};
$metadata->setSequenceGeneratorDefinition(array(
'sequenceName' => (string)$seqGenerator['sequence-name'],
'allocationSize' => (string)$seqGenerator['allocation-size'],
'initialValue' => (string)$seqGenerator['initial-value']
));
} else if (isset($idElement->{'custom-id-generator'})) {
$customGenerator = $idElement->{'custom-id-generator'};
$metadata->setCustomGeneratorDefinition(array(
'class' => (string) $customGenerator['class']
));
} else if (isset($idElement->{'table-generator'})) {
throw MappingException::tableIdGeneratorNotImplemented($className);
}
}
// Evaluate mappings
if (isset($xmlRoot->{'one-to-one'})) {
foreach ($xmlRoot->{'one-to-one'} as $oneToOneElement) {
$mapping = array(
'fieldName' => (string)$oneToOneElement['field'],
'targetEntity' => (string)$oneToOneElement['target-entity']
);
if (isset($associationIds[$mapping['fieldName']])) {
$mapping['id'] = true;
}
if (isset($oneToOneElement['fetch'])) {
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string)$oneToOneElement['fetch']);
}
if (isset($oneToOneElement['mapped-by'])) {
$mapping['mappedBy'] = (string)$oneToOneElement['mapped-by'];
} else {
if (isset($oneToOneElement['inversed-by'])) {
$mapping['inversedBy'] = (string)$oneToOneElement['inversed-by'];
}
$joinColumns = array();
if (isset($oneToOneElement->{'join-column'})) {
$joinColumns[] = $this->joinColumnToArray($oneToOneElement->{'join-column'});
} else if (isset($oneToOneElement->{'join-columns'})) {
foreach ($oneToOneElement->{'join-columns'}->{'join-column'} as $joinColumnElement) {
$joinColumns[] = $this->joinColumnToArray($joinColumnElement);
}
}
$mapping['joinColumns'] = $joinColumns;
}
if (isset($oneToOneElement->cascade)) {
$mapping['cascade'] = $this->_getCascadeMappings($oneToOneElement->cascade);
}
if (isset($oneToOneElement['orphan-removal'])) {
$mapping['orphanRemoval'] = $this->evaluateBoolean($oneToOneElement['orphan-removal']);
}
$metadata->mapOneToOne($mapping);
// Evaluate second level cache
if (isset($oneToOneElement->cache)) {
$metadata->enableAssociationCache($mapping['fieldName'], $this->cacheToArray($oneToOneElement->cache));
}
}
}
// Evaluate mappings
if (isset($xmlRoot->{'one-to-many'})) {
foreach ($xmlRoot->{'one-to-many'} as $oneToManyElement) {
$mapping = array(
'fieldName' => (string)$oneToManyElement['field'],
'targetEntity' => (string)$oneToManyElement['target-entity'],
'mappedBy' => (string)$oneToManyElement['mapped-by']
);
if (isset($oneToManyElement['fetch'])) {
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string)$oneToManyElement['fetch']);
}
if (isset($oneToManyElement->cascade)) {
$mapping['cascade'] = $this->_getCascadeMappings($oneToManyElement->cascade);
}
if (isset($oneToManyElement['orphan-removal'])) {
$mapping['orphanRemoval'] = $this->evaluateBoolean($oneToManyElement['orphan-removal']);
}
if (isset($oneToManyElement->{'order-by'})) {
$orderBy = array();
foreach ($oneToManyElement->{'order-by'}->{'order-by-field'} as $orderByField) {
$orderBy[(string)$orderByField['name']] = (string)$orderByField['direction'];
}
$mapping['orderBy'] = $orderBy;
}
if (isset($oneToManyElement['index-by'])) {
$mapping['indexBy'] = (string)$oneToManyElement['index-by'];
} else if (isset($oneToManyElement->{'index-by'})) {
throw new \InvalidArgumentException(" is not a valid tag");
}
$metadata->mapOneToMany($mapping);
// Evaluate second level cache
if (isset($oneToManyElement->cache)) {
$metadata->enableAssociationCache($mapping['fieldName'], $this->cacheToArray($oneToManyElement->cache));
}
}
}
// Evaluate mappings
if (isset($xmlRoot->{'many-to-one'})) {
foreach ($xmlRoot->{'many-to-one'} as $manyToOneElement) {
$mapping = array(
'fieldName' => (string)$manyToOneElement['field'],
'targetEntity' => (string)$manyToOneElement['target-entity']
);
if (isset($associationIds[$mapping['fieldName']])) {
$mapping['id'] = true;
}
if (isset($manyToOneElement['fetch'])) {
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string)$manyToOneElement['fetch']);
}
if (isset($manyToOneElement['inversed-by'])) {
$mapping['inversedBy'] = (string)$manyToOneElement['inversed-by'];
}
$joinColumns = array();
if (isset($manyToOneElement->{'join-column'})) {
$joinColumns[] = $this->joinColumnToArray($manyToOneElement->{'join-column'});
} else if (isset($manyToOneElement->{'join-columns'})) {
foreach ($manyToOneElement->{'join-columns'}->{'join-column'} as $joinColumnElement) {
$joinColumns[] = $this->joinColumnToArray($joinColumnElement);
}
}
$mapping['joinColumns'] = $joinColumns;
if (isset($manyToOneElement->cascade)) {
$mapping['cascade'] = $this->_getCascadeMappings($manyToOneElement->cascade);
}
$metadata->mapManyToOne($mapping);
// Evaluate second level cache
if (isset($manyToOneElement->cache)) {
$metadata->enableAssociationCache($mapping['fieldName'], $this->cacheToArray($manyToOneElement->cache));
}
}
}
// Evaluate mappings
if (isset($xmlRoot->{'many-to-many'})) {
foreach ($xmlRoot->{'many-to-many'} as $manyToManyElement) {
$mapping = array(
'fieldName' => (string)$manyToManyElement['field'],
'targetEntity' => (string)$manyToManyElement['target-entity']
);
if (isset($manyToManyElement['fetch'])) {
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string)$manyToManyElement['fetch']);
}
if (isset($manyToManyElement['orphan-removal'])) {
$mapping['orphanRemoval'] = $this->evaluateBoolean($manyToManyElement['orphan-removal']);
}
if (isset($manyToManyElement['mapped-by'])) {
$mapping['mappedBy'] = (string)$manyToManyElement['mapped-by'];
} else if (isset($manyToManyElement->{'join-table'})) {
if (isset($manyToManyElement['inversed-by'])) {
$mapping['inversedBy'] = (string)$manyToManyElement['inversed-by'];
}
$joinTableElement = $manyToManyElement->{'join-table'};
$joinTable = array(
'name' => (string)$joinTableElement['name']
);
if (isset($joinTableElement['schema'])) {
$joinTable['schema'] = (string)$joinTableElement['schema'];
}
foreach ($joinTableElement->{'join-columns'}->{'join-column'} as $joinColumnElement) {
$joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement);
}
foreach ($joinTableElement->{'inverse-join-columns'}->{'join-column'} as $joinColumnElement) {
$joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement);
}
$mapping['joinTable'] = $joinTable;
}
if (isset($manyToManyElement->cascade)) {
$mapping['cascade'] = $this->_getCascadeMappings($manyToManyElement->cascade);
}
if (isset($manyToManyElement->{'order-by'})) {
$orderBy = array();
foreach ($manyToManyElement->{'order-by'}->{'order-by-field'} as $orderByField) {
$orderBy[(string)$orderByField['name']] = (string)$orderByField['direction'];
}
$mapping['orderBy'] = $orderBy;
}
if (isset($manyToManyElement['index-by'])) {
$mapping['indexBy'] = (string)$manyToManyElement['index-by'];
} else if (isset($manyToManyElement->{'index-by'})) {
throw new \InvalidArgumentException(" is not a valid tag");
}
$metadata->mapManyToMany($mapping);
// Evaluate second level cache
if (isset($manyToManyElement->cache)) {
$metadata->enableAssociationCache($mapping['fieldName'], $this->cacheToArray($manyToManyElement->cache));
}
}
}
// Evaluate association-overrides
if (isset($xmlRoot->{'attribute-overrides'})) {
foreach ($xmlRoot->{'attribute-overrides'}->{'attribute-override'} as $overrideElement) {
$fieldName = (string) $overrideElement['name'];
foreach ($overrideElement->field as $field) {
$mapping = $this->columnToArray($field);
$mapping['fieldName'] = $fieldName;
$metadata->setAttributeOverride($fieldName, $mapping);
}
}
}
// Evaluate association-overrides
if (isset($xmlRoot->{'association-overrides'})) {
foreach ($xmlRoot->{'association-overrides'}->{'association-override'} as $overrideElement) {
$fieldName = (string) $overrideElement['name'];
$override = array();
// Check for join-columns
if (isset($overrideElement->{'join-columns'})) {
$joinColumns = array();
foreach ($overrideElement->{'join-columns'}->{'join-column'} as $joinColumnElement) {
$joinColumns[] = $this->joinColumnToArray($joinColumnElement);
}
$override['joinColumns'] = $joinColumns;
}
// Check for join-table
if ($overrideElement->{'join-table'}) {
$joinTable = null;
$joinTableElement = $overrideElement->{'join-table'};
$joinTable = array(
'name' => (string) $joinTableElement['name'],
'schema' => (string) $joinTableElement['schema']
);
if (isset($joinTableElement->{'join-columns'})) {
foreach ($joinTableElement->{'join-columns'}->{'join-column'} as $joinColumnElement) {
$joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement);
}
}
if (isset($joinTableElement->{'inverse-join-columns'})) {
foreach ($joinTableElement->{'inverse-join-columns'}->{'join-column'} as $joinColumnElement) {
$joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement);
}
}
$override['joinTable'] = $joinTable;
}
$metadata->setAssociationOverride($fieldName, $override);
}
}
// Evaluate
if (isset($xmlRoot->{'lifecycle-callbacks'})) {
foreach ($xmlRoot->{'lifecycle-callbacks'}->{'lifecycle-callback'} as $lifecycleCallback) {
$metadata->addLifecycleCallback((string)$lifecycleCallback['method'], constant('Doctrine\ORM\Events::' . (string)$lifecycleCallback['type']));
}
}
// Evaluate entity listener
if (isset($xmlRoot->{'entity-listeners'})) {
foreach ($xmlRoot->{'entity-listeners'}->{'entity-listener'} as $listenerElement) {
$className = (string) $listenerElement['class'];
// Evaluate the listener using naming convention.
if($listenerElement->count() === 0) {
EntityListenerBuilder::bindEntityListener($metadata, $className);
continue;
}
foreach ($listenerElement as $callbackElement) {
$eventName = (string) $callbackElement['type'];
$methodName = (string) $callbackElement['method'];
$metadata->addEntityListener($eventName, $className, $methodName);
}
}
}
}
/**
* Parses (nested) option elements.
*
* @param SimpleXMLElement $options The XML element.
*
* @return array The options array.
*/
private function _parseOptions(SimpleXMLElement $options)
{
$array = array();
/* @var $option SimpleXMLElement */
foreach ($options as $option) {
if ($option->count()) {
$value = $this->_parseOptions($option->children());
} else {
$value = (string) $option;
}
$attr = $option->attributes();
if (isset($attr->name)) {
$array[(string) $attr->name] = $value;
} else {
$array[] = $value;
}
}
return $array;
}
/**
* Constructs a joinColumn mapping array based on the information
* found in the given SimpleXMLElement.
*
* @param SimpleXMLElement $joinColumnElement The XML element.
*
* @return array The mapping array.
*/
private function joinColumnToArray(SimpleXMLElement $joinColumnElement)
{
$joinColumn = array(
'name' => (string)$joinColumnElement['name'],
'referencedColumnName' => (string)$joinColumnElement['referenced-column-name']
);
if (isset($joinColumnElement['unique'])) {
$joinColumn['unique'] = $this->evaluateBoolean($joinColumnElement['unique']);
}
if (isset($joinColumnElement['nullable'])) {
$joinColumn['nullable'] = $this->evaluateBoolean($joinColumnElement['nullable']);
}
if (isset($joinColumnElement['on-delete'])) {
$joinColumn['onDelete'] = (string)$joinColumnElement['on-delete'];
}
if (isset($joinColumnElement['column-definition'])) {
$joinColumn['columnDefinition'] = (string)$joinColumnElement['column-definition'];
}
return $joinColumn;
}
/**
* Parses the given field as array.
*
* @param SimpleXMLElement $fieldMapping
*
* @return array
*/
private function columnToArray(SimpleXMLElement $fieldMapping)
{
$mapping = array(
'fieldName' => (string) $fieldMapping['name'],
);
if (isset($fieldMapping['type'])) {
$mapping['type'] = (string) $fieldMapping['type'];
}
if (isset($fieldMapping['column'])) {
$mapping['columnName'] = (string) $fieldMapping['column'];
}
if (isset($fieldMapping['length'])) {
$mapping['length'] = (int) $fieldMapping['length'];
}
if (isset($fieldMapping['precision'])) {
$mapping['precision'] = (int) $fieldMapping['precision'];
}
if (isset($fieldMapping['scale'])) {
$mapping['scale'] = (int) $fieldMapping['scale'];
}
if (isset($fieldMapping['unique'])) {
$mapping['unique'] = $this->evaluateBoolean($fieldMapping['unique']);
}
if (isset($fieldMapping['nullable'])) {
$mapping['nullable'] = $this->evaluateBoolean($fieldMapping['nullable']);
}
if (isset($fieldMapping['version']) && $fieldMapping['version']) {
$mapping['version'] = $this->evaluateBoolean($fieldMapping['version']);
}
if (isset($fieldMapping['column-definition'])) {
$mapping['columnDefinition'] = (string) $fieldMapping['column-definition'];
}
if (isset($fieldMapping->options)) {
$mapping['options'] = $this->_parseOptions($fieldMapping->options->children());
}
return $mapping;
}
/**
* Parse / Normalize the cache configuration
*
* @param SimpleXMLElement $cacheMapping
*
* @return array
*/
private function cacheToArray(SimpleXMLElement $cacheMapping)
{
$region = isset($cacheMapping['region']) ? (string) $cacheMapping['region'] : null;
$usage = isset($cacheMapping['usage']) ? strtoupper($cacheMapping['usage']) : null;
if ($usage && ! defined('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $usage)) {
throw new \InvalidArgumentException(sprintf('Invalid cache usage "%s"', $usage));
}
if ($usage) {
$usage = constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $usage);
}
return array(
'usage' => $usage,
'region' => $region,
);
}
/**
* Gathers a list of cascade options found in the given cascade element.
*
* @param SimpleXMLElement $cascadeElement The cascade element.
*
* @return array The list of cascade options.
*/
private function _getCascadeMappings(SimpleXMLElement $cascadeElement)
{
$cascades = array();
/* @var $action SimpleXmlElement */
foreach ($cascadeElement->children() as $action) {
// According to the JPA specifications, XML uses "cascade-persist"
// instead of "persist". Here, both variations
// are supported because both YAML and Annotation use "persist"
// and we want to make sure that this driver doesn't need to know
// anything about the supported cascading actions
$cascades[] = str_replace('cascade-', '', $action->getName());
}
return $cascades;
}
/**
* {@inheritDoc}
*/
protected function loadMappingFile($file)
{
$result = array();
// Note: we do not use `simplexml_load_file()` because of https://bugs.php.net/bug.php?id=62577
$xmlElement = simplexml_load_string(file_get_contents($file));
if (isset($xmlElement->entity)) {
foreach ($xmlElement->entity as $entityElement) {
$entityName = (string)$entityElement['name'];
$result[$entityName] = $entityElement;
}
} else if (isset($xmlElement->{'mapped-superclass'})) {
foreach ($xmlElement->{'mapped-superclass'} as $mappedSuperClass) {
$className = (string)$mappedSuperClass['name'];
$result[$className] = $mappedSuperClass;
}
} else if (isset($xmlElement->embeddable)) {
foreach ($xmlElement->embeddable as $embeddableElement) {
$embeddableName = (string) $embeddableElement['name'];
$result[$embeddableName] = $embeddableElement;
}
}
return $result;
}
/**
* @param mixed $element
*
* @return bool
*/
protected function evaluateBoolean($element)
{
$flag = (string)$element;
return ($flag == "true" || $flag == "1");
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php 0000664 0000000 0000000 00000075505 13215356457 0024112 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
use Doctrine\Common\Persistence\Mapping\Driver\FileDriver;
use Doctrine\ORM\Mapping\MappingException;
use Symfony\Component\Yaml\Yaml;
/**
* The YamlDriver reads the mapping metadata from yaml schema files.
*
* @since 2.0
* @author Benjamin Eberlei
* @author Guilherme Blanco
* @author Jonathan H. Wage
* @author Roman Borschel
*/
class YamlDriver extends FileDriver
{
const DEFAULT_FILE_EXTENSION = '.dcm.yml';
/**
* {@inheritDoc}
*/
public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENSION)
{
parent::__construct($locator, $fileExtension);
}
/**
* {@inheritDoc}
*/
public function loadMetadataForClass($className, ClassMetadata $metadata)
{
/* @var $metadata \Doctrine\ORM\Mapping\ClassMetadataInfo */
$element = $this->getElement($className);
if ($element['type'] == 'entity') {
if (isset($element['repositoryClass'])) {
$metadata->setCustomRepositoryClass($element['repositoryClass']);
}
if (isset($element['readOnly']) && $element['readOnly'] == true) {
$metadata->markReadOnly();
}
} else if ($element['type'] == 'mappedSuperclass') {
$metadata->setCustomRepositoryClass(
isset($element['repositoryClass']) ? $element['repositoryClass'] : null
);
$metadata->isMappedSuperclass = true;
} else if ($element['type'] == 'embeddable') {
$metadata->isEmbeddedClass = true;
} else {
throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
}
// Evaluate root level properties
$primaryTable = array();
if (isset($element['table'])) {
$primaryTable['name'] = $element['table'];
}
if (isset($element['schema'])) {
$primaryTable['schema'] = $element['schema'];
}
// Evaluate second level cache
if (isset($element['cache'])) {
$metadata->enableCache($this->cacheToArray($element['cache']));
}
$metadata->setPrimaryTable($primaryTable);
// Evaluate named queries
if (isset($element['namedQueries'])) {
foreach ($element['namedQueries'] as $name => $queryMapping) {
if (is_string($queryMapping)) {
$queryMapping = array('query' => $queryMapping);
}
if ( ! isset($queryMapping['name'])) {
$queryMapping['name'] = $name;
}
$metadata->addNamedQuery($queryMapping);
}
}
// Evaluate named native queries
if (isset($element['namedNativeQueries'])) {
foreach ($element['namedNativeQueries'] as $name => $mappingElement) {
if (!isset($mappingElement['name'])) {
$mappingElement['name'] = $name;
}
$metadata->addNamedNativeQuery(array(
'name' => $mappingElement['name'],
'query' => isset($mappingElement['query']) ? $mappingElement['query'] : null,
'resultClass' => isset($mappingElement['resultClass']) ? $mappingElement['resultClass'] : null,
'resultSetMapping' => isset($mappingElement['resultSetMapping']) ? $mappingElement['resultSetMapping'] : null,
));
}
}
// Evaluate sql result set mappings
if (isset($element['sqlResultSetMappings'])) {
foreach ($element['sqlResultSetMappings'] as $name => $resultSetMapping) {
if (!isset($resultSetMapping['name'])) {
$resultSetMapping['name'] = $name;
}
$entities = array();
$columns = array();
if (isset($resultSetMapping['entityResult'])) {
foreach ($resultSetMapping['entityResult'] as $entityResultElement) {
$entityResult = array(
'fields' => array(),
'entityClass' => isset($entityResultElement['entityClass']) ? $entityResultElement['entityClass'] : null,
'discriminatorColumn' => isset($entityResultElement['discriminatorColumn']) ? $entityResultElement['discriminatorColumn'] : null,
);
if (isset($entityResultElement['fieldResult'])) {
foreach ($entityResultElement['fieldResult'] as $fieldResultElement) {
$entityResult['fields'][] = array(
'name' => isset($fieldResultElement['name']) ? $fieldResultElement['name'] : null,
'column' => isset($fieldResultElement['column']) ? $fieldResultElement['column'] : null,
);
}
}
$entities[] = $entityResult;
}
}
if (isset($resultSetMapping['columnResult'])) {
foreach ($resultSetMapping['columnResult'] as $columnResultAnnot) {
$columns[] = array(
'name' => isset($columnResultAnnot['name']) ? $columnResultAnnot['name'] : null,
);
}
}
$metadata->addSqlResultSetMapping(array(
'name' => $resultSetMapping['name'],
'entities' => $entities,
'columns' => $columns
));
}
}
if (isset($element['inheritanceType'])) {
$metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . strtoupper($element['inheritanceType'])));
if ($metadata->inheritanceType != \Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_NONE) {
// Evaluate discriminatorColumn
if (isset($element['discriminatorColumn'])) {
$discrColumn = $element['discriminatorColumn'];
$metadata->setDiscriminatorColumn(array(
'name' => isset($discrColumn['name']) ? (string)$discrColumn['name'] : null,
'type' => isset($discrColumn['type']) ? (string)$discrColumn['type'] : null,
'length' => isset($discrColumn['length']) ? (string)$discrColumn['length'] : null,
'columnDefinition' => isset($discrColumn['columnDefinition']) ? (string)$discrColumn['columnDefinition'] : null
));
} else {
$metadata->setDiscriminatorColumn(array('name' => 'dtype', 'type' => 'string', 'length' => 255));
}
// Evaluate discriminatorMap
if (isset($element['discriminatorMap'])) {
$metadata->setDiscriminatorMap($element['discriminatorMap']);
}
}
}
// Evaluate changeTrackingPolicy
if (isset($element['changeTrackingPolicy'])) {
$metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_'
. strtoupper($element['changeTrackingPolicy'])));
}
// Evaluate indexes
if (isset($element['indexes'])) {
foreach ($element['indexes'] as $name => $indexYml) {
if ( ! isset($indexYml['name'])) {
$indexYml['name'] = $name;
}
if (is_string($indexYml['columns'])) {
$index = array('columns' => array_map('trim', explode(',', $indexYml['columns'])));
} else {
$index = array('columns' => $indexYml['columns']);
}
if (isset($indexYml['flags'])) {
if (is_string($indexYml['flags'])) {
$index['flags'] = array_map('trim', explode(',', $indexYml['flags']));
} else {
$index['flags'] = $indexYml['flags'];
}
}
if (isset($indexYml['options'])) {
$index['options'] = $indexYml['options'];
}
$metadata->table['indexes'][$indexYml['name']] = $index;
}
}
// Evaluate uniqueConstraints
if (isset($element['uniqueConstraints'])) {
foreach ($element['uniqueConstraints'] as $name => $uniqueYml) {
if ( ! isset($uniqueYml['name'])) {
$uniqueYml['name'] = $name;
}
if (is_string($uniqueYml['columns'])) {
$unique = array('columns' => array_map('trim', explode(',', $uniqueYml['columns'])));
} else {
$unique = array('columns' => $uniqueYml['columns']);
}
if (isset($uniqueYml['options'])) {
$unique['options'] = $uniqueYml['options'];
}
$metadata->table['uniqueConstraints'][$uniqueYml['name']] = $unique;
}
}
if (isset($element['options'])) {
$metadata->table['options'] = $element['options'];
}
$associationIds = array();
if (isset($element['id'])) {
// Evaluate identifier settings
foreach ($element['id'] as $name => $idElement) {
if (isset($idElement['associationKey']) && $idElement['associationKey'] == true) {
$associationIds[$name] = true;
continue;
}
$mapping = array(
'id' => true,
'fieldName' => $name
);
if (isset($idElement['type'])) {
$mapping['type'] = $idElement['type'];
}
if (isset($idElement['column'])) {
$mapping['columnName'] = $idElement['column'];
}
if (isset($idElement['length'])) {
$mapping['length'] = $idElement['length'];
}
if (isset($idElement['columnDefinition'])) {
$mapping['columnDefinition'] = $idElement['columnDefinition'];
}
if (isset($idElement['options'])) {
$mapping['options'] = $idElement['options'];
}
$metadata->mapField($mapping);
if (isset($idElement['generator'])) {
$metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_'
. strtoupper($idElement['generator']['strategy'])));
}
// Check for SequenceGenerator/TableGenerator definition
if (isset($idElement['sequenceGenerator'])) {
$metadata->setSequenceGeneratorDefinition($idElement['sequenceGenerator']);
} else if (isset($idElement['customIdGenerator'])) {
$customGenerator = $idElement['customIdGenerator'];
$metadata->setCustomGeneratorDefinition(array(
'class' => (string) $customGenerator['class']
));
} else if (isset($idElement['tableGenerator'])) {
throw MappingException::tableIdGeneratorNotImplemented($className);
}
}
}
// Evaluate fields
if (isset($element['fields'])) {
foreach ($element['fields'] as $name => $fieldMapping) {
$mapping = $this->columnToArray($name, $fieldMapping);
if (isset($fieldMapping['id'])) {
$mapping['id'] = true;
if (isset($fieldMapping['generator']['strategy'])) {
$metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_'
. strtoupper($fieldMapping['generator']['strategy'])));
}
}
if (isset($mapping['version'])) {
$metadata->setVersionMapping($mapping);
unset($mapping['version']);
}
$metadata->mapField($mapping);
}
}
if (isset($element['embedded'])) {
foreach ($element['embedded'] as $name => $embeddedMapping) {
$mapping = array(
'fieldName' => $name,
'class' => $embeddedMapping['class'],
'columnPrefix' => isset($embeddedMapping['columnPrefix']) ? $embeddedMapping['columnPrefix'] : null,
);
$metadata->mapEmbedded($mapping);
}
}
// Evaluate oneToOne relationships
if (isset($element['oneToOne'])) {
foreach ($element['oneToOne'] as $name => $oneToOneElement) {
$mapping = array(
'fieldName' => $name,
'targetEntity' => $oneToOneElement['targetEntity']
);
if (isset($associationIds[$mapping['fieldName']])) {
$mapping['id'] = true;
}
if (isset($oneToOneElement['fetch'])) {
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToOneElement['fetch']);
}
if (isset($oneToOneElement['mappedBy'])) {
$mapping['mappedBy'] = $oneToOneElement['mappedBy'];
} else {
if (isset($oneToOneElement['inversedBy'])) {
$mapping['inversedBy'] = $oneToOneElement['inversedBy'];
}
$joinColumns = array();
if (isset($oneToOneElement['joinColumn'])) {
$joinColumns[] = $this->joinColumnToArray($oneToOneElement['joinColumn']);
} else if (isset($oneToOneElement['joinColumns'])) {
foreach ($oneToOneElement['joinColumns'] as $joinColumnName => $joinColumnElement) {
if ( ! isset($joinColumnElement['name'])) {
$joinColumnElement['name'] = $joinColumnName;
}
$joinColumns[] = $this->joinColumnToArray($joinColumnElement);
}
}
$mapping['joinColumns'] = $joinColumns;
}
if (isset($oneToOneElement['cascade'])) {
$mapping['cascade'] = $oneToOneElement['cascade'];
}
if (isset($oneToOneElement['orphanRemoval'])) {
$mapping['orphanRemoval'] = (bool)$oneToOneElement['orphanRemoval'];
}
$metadata->mapOneToOne($mapping);
// Evaluate second level cache
if (isset($oneToOneElement['cache'])) {
$metadata->enableAssociationCache($mapping['fieldName'], $this->cacheToArray($oneToOneElement['cache']));
}
}
}
// Evaluate oneToMany relationships
if (isset($element['oneToMany'])) {
foreach ($element['oneToMany'] as $name => $oneToManyElement) {
$mapping = array(
'fieldName' => $name,
'targetEntity' => $oneToManyElement['targetEntity'],
'mappedBy' => $oneToManyElement['mappedBy']
);
if (isset($oneToManyElement['fetch'])) {
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToManyElement['fetch']);
}
if (isset($oneToManyElement['cascade'])) {
$mapping['cascade'] = $oneToManyElement['cascade'];
}
if (isset($oneToManyElement['orphanRemoval'])) {
$mapping['orphanRemoval'] = (bool)$oneToManyElement['orphanRemoval'];
}
if (isset($oneToManyElement['orderBy'])) {
$mapping['orderBy'] = $oneToManyElement['orderBy'];
}
if (isset($oneToManyElement['indexBy'])) {
$mapping['indexBy'] = $oneToManyElement['indexBy'];
}
$metadata->mapOneToMany($mapping);
// Evaluate second level cache
if (isset($oneToManyElement['cache'])) {
$metadata->enableAssociationCache($mapping['fieldName'], $this->cacheToArray($oneToManyElement['cache']));
}
}
}
// Evaluate manyToOne relationships
if (isset($element['manyToOne'])) {
foreach ($element['manyToOne'] as $name => $manyToOneElement) {
$mapping = array(
'fieldName' => $name,
'targetEntity' => $manyToOneElement['targetEntity']
);
if (isset($associationIds[$mapping['fieldName']])) {
$mapping['id'] = true;
}
if (isset($manyToOneElement['fetch'])) {
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToOneElement['fetch']);
}
if (isset($manyToOneElement['inversedBy'])) {
$mapping['inversedBy'] = $manyToOneElement['inversedBy'];
}
$joinColumns = array();
if (isset($manyToOneElement['joinColumn'])) {
$joinColumns[] = $this->joinColumnToArray($manyToOneElement['joinColumn']);
} else if (isset($manyToOneElement['joinColumns'])) {
foreach ($manyToOneElement['joinColumns'] as $joinColumnName => $joinColumnElement) {
if ( ! isset($joinColumnElement['name'])) {
$joinColumnElement['name'] = $joinColumnName;
}
$joinColumns[] = $this->joinColumnToArray($joinColumnElement);
}
}
$mapping['joinColumns'] = $joinColumns;
if (isset($manyToOneElement['cascade'])) {
$mapping['cascade'] = $manyToOneElement['cascade'];
}
$metadata->mapManyToOne($mapping);
// Evaluate second level cache
if (isset($manyToOneElement['cache'])) {
$metadata->enableAssociationCache($mapping['fieldName'], $this->cacheToArray($manyToOneElement['cache']));
}
}
}
// Evaluate manyToMany relationships
if (isset($element['manyToMany'])) {
foreach ($element['manyToMany'] as $name => $manyToManyElement) {
$mapping = array(
'fieldName' => $name,
'targetEntity' => $manyToManyElement['targetEntity']
);
if (isset($manyToManyElement['fetch'])) {
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToManyElement['fetch']);
}
if (isset($manyToManyElement['mappedBy'])) {
$mapping['mappedBy'] = $manyToManyElement['mappedBy'];
} else if (isset($manyToManyElement['joinTable'])) {
$joinTableElement = $manyToManyElement['joinTable'];
$joinTable = array(
'name' => $joinTableElement['name']
);
if (isset($joinTableElement['schema'])) {
$joinTable['schema'] = $joinTableElement['schema'];
}
if (isset($joinTableElement['joinColumns'])) {
foreach ($joinTableElement['joinColumns'] as $joinColumnName => $joinColumnElement) {
if ( ! isset($joinColumnElement['name'])) {
$joinColumnElement['name'] = $joinColumnName;
}
$joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement);
}
}
if (isset($joinTableElement['inverseJoinColumns'])) {
foreach ($joinTableElement['inverseJoinColumns'] as $joinColumnName => $joinColumnElement) {
if ( ! isset($joinColumnElement['name'])) {
$joinColumnElement['name'] = $joinColumnName;
}
$joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement);
}
}
$mapping['joinTable'] = $joinTable;
}
if (isset($manyToManyElement['inversedBy'])) {
$mapping['inversedBy'] = $manyToManyElement['inversedBy'];
}
if (isset($manyToManyElement['cascade'])) {
$mapping['cascade'] = $manyToManyElement['cascade'];
}
if (isset($manyToManyElement['orderBy'])) {
$mapping['orderBy'] = $manyToManyElement['orderBy'];
}
if (isset($manyToManyElement['indexBy'])) {
$mapping['indexBy'] = $manyToManyElement['indexBy'];
}
if (isset($manyToManyElement['orphanRemoval'])) {
$mapping['orphanRemoval'] = (bool)$manyToManyElement['orphanRemoval'];
}
$metadata->mapManyToMany($mapping);
// Evaluate second level cache
if (isset($manyToManyElement['cache'])) {
$metadata->enableAssociationCache($mapping['fieldName'], $this->cacheToArray($manyToManyElement['cache']));
}
}
}
// Evaluate associationOverride
if (isset($element['associationOverride']) && is_array($element['associationOverride'])) {
foreach ($element['associationOverride'] as $fieldName => $associationOverrideElement) {
$override = array();
// Check for joinColumn
if (isset($associationOverrideElement['joinColumn'])) {
$joinColumns = array();
foreach ($associationOverrideElement['joinColumn'] as $name => $joinColumnElement) {
if ( ! isset($joinColumnElement['name'])) {
$joinColumnElement['name'] = $name;
}
$joinColumns[] = $this->joinColumnToArray($joinColumnElement);
}
$override['joinColumns'] = $joinColumns;
}
// Check for joinTable
if (isset($associationOverrideElement['joinTable'])) {
$joinTableElement = $associationOverrideElement['joinTable'];
$joinTable = array(
'name' => $joinTableElement['name']
);
if (isset($joinTableElement['schema'])) {
$joinTable['schema'] = $joinTableElement['schema'];
}
foreach ($joinTableElement['joinColumns'] as $name => $joinColumnElement) {
if ( ! isset($joinColumnElement['name'])) {
$joinColumnElement['name'] = $name;
}
$joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement);
}
foreach ($joinTableElement['inverseJoinColumns'] as $name => $joinColumnElement) {
if ( ! isset($joinColumnElement['name'])) {
$joinColumnElement['name'] = $name;
}
$joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement);
}
$override['joinTable'] = $joinTable;
}
$metadata->setAssociationOverride($fieldName, $override);
}
}
// Evaluate associationOverride
if (isset($element['attributeOverride']) && is_array($element['attributeOverride'])) {
foreach ($element['attributeOverride'] as $fieldName => $attributeOverrideElement) {
$mapping = $this->columnToArray($fieldName, $attributeOverrideElement);
$metadata->setAttributeOverride($fieldName, $mapping);
}
}
// Evaluate lifeCycleCallbacks
if (isset($element['lifecycleCallbacks'])) {
foreach ($element['lifecycleCallbacks'] as $type => $methods) {
foreach ($methods as $method) {
$metadata->addLifecycleCallback($method, constant('Doctrine\ORM\Events::' . $type));
}
}
}
// Evaluate entityListeners
if (isset($element['entityListeners'])) {
foreach ($element['entityListeners'] as $className => $entityListener) {
// Evaluate the listener using naming convention.
if (empty($entityListener)) {
EntityListenerBuilder::bindEntityListener($metadata, $className);
continue;
}
foreach ($entityListener as $eventName => $callbackElement){
foreach ($callbackElement as $methodName) {
$metadata->addEntityListener($eventName, $className, $methodName);
}
}
}
}
}
/**
* Constructs a joinColumn mapping array based on the information
* found in the given join column element.
*
* @param array $joinColumnElement The array join column element.
*
* @return array The mapping array.
*/
private function joinColumnToArray($joinColumnElement)
{
$joinColumn = array();
if (isset($joinColumnElement['referencedColumnName'])) {
$joinColumn['referencedColumnName'] = (string) $joinColumnElement['referencedColumnName'];
}
if (isset($joinColumnElement['name'])) {
$joinColumn['name'] = (string) $joinColumnElement['name'];
}
if (isset($joinColumnElement['fieldName'])) {
$joinColumn['fieldName'] = (string) $joinColumnElement['fieldName'];
}
if (isset($joinColumnElement['unique'])) {
$joinColumn['unique'] = (bool) $joinColumnElement['unique'];
}
if (isset($joinColumnElement['nullable'])) {
$joinColumn['nullable'] = (bool) $joinColumnElement['nullable'];
}
if (isset($joinColumnElement['onDelete'])) {
$joinColumn['onDelete'] = $joinColumnElement['onDelete'];
}
if (isset($joinColumnElement['columnDefinition'])) {
$joinColumn['columnDefinition'] = $joinColumnElement['columnDefinition'];
}
return $joinColumn;
}
/**
* Parses the given column as array.
*
* @param string $fieldName
* @param array $column
*
* @return array
*/
private function columnToArray($fieldName, $column)
{
$mapping = array(
'fieldName' => $fieldName
);
if (isset($column['type'])) {
$params = explode('(', $column['type']);
$column['type'] = $params[0];
$mapping['type'] = $column['type'];
if (isset($params[1])) {
$column['length'] = (integer) substr($params[1], 0, strlen($params[1]) - 1);
}
}
if (isset($column['column'])) {
$mapping['columnName'] = $column['column'];
}
if (isset($column['length'])) {
$mapping['length'] = $column['length'];
}
if (isset($column['precision'])) {
$mapping['precision'] = $column['precision'];
}
if (isset($column['scale'])) {
$mapping['scale'] = $column['scale'];
}
if (isset($column['unique'])) {
$mapping['unique'] = (bool)$column['unique'];
}
if (isset($column['options'])) {
$mapping['options'] = $column['options'];
}
if (isset($column['nullable'])) {
$mapping['nullable'] = $column['nullable'];
}
if (isset($column['version']) && $column['version']) {
$mapping['version'] = $column['version'];
}
if (isset($column['columnDefinition'])) {
$mapping['columnDefinition'] = $column['columnDefinition'];
}
return $mapping;
}
/**
* Parse / Normalize the cache configuration
*
* @param array $cacheMapping
*
* @return array
*/
private function cacheToArray($cacheMapping)
{
$region = isset($cacheMapping['region']) ? (string) $cacheMapping['region'] : null;
$usage = isset($cacheMapping['usage']) ? strtoupper($cacheMapping['usage']) : null;
if ($usage && ! defined('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $usage)) {
throw new \InvalidArgumentException(sprintf('Invalid cache usage "%s"', $usage));
}
if ($usage) {
$usage = constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $usage);
}
return array(
'usage' => $usage,
'region' => $region,
);
}
/**
* {@inheritDoc}
*/
protected function loadMappingFile($file)
{
return Yaml::parse(file_get_contents($file));
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/Embeddable.php 0000664 0000000 0000000 00000002132 13215356457 0022567 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class Embeddable implements Annotation
{
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/Embedded.php 0000664 0000000 0000000 00000002337 13215356457 0022263 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class Embedded implements Annotation
{
/**
* @Required
* @var string
*/
public $class;
/**
* @var mixed
*/
public $columnPrefix;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/Entity.php 0000664 0000000 0000000 00000002331 13215356457 0022040 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class Entity implements Annotation
{
/**
* @var string
*/
public $repositoryClass;
/**
* @var boolean
*/
public $readOnly = false;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/EntityListenerResolver.php 0000664 0000000 0000000 00000003430 13215356457 0025271 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* A resolver is used to instantiate an entity listener.
*
* @since 2.4
* @author Fabio B. Silva
*/
interface EntityListenerResolver
{
/**
* Clear all instances from the set, or a specific class when given.
*
* @param string $className The fully-qualified class name
*
* @return void
*/
function clear($className = null);
/**
* Returns a entity listener instance for the given class name.
*
* @param string $className The fully-qualified class name
*
* @return object An entity listener
*/
function resolve($className);
/**
* Register a entity listener instance.
*
* @param object $object An entity listener
*/
function register($object);
} doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/EntityListeners.php 0000664 0000000 0000000 00000003001 13215356457 0023724 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* The EntityListeners annotation specifies the callback listener classes to be used for an entity or mapped superclass.
* The EntityListeners annotation may be applied to an entity class or mapped superclass.
*
* @author Fabio B. Silva
* @since 2.4
*
* @Annotation
* @Target("CLASS")
*/
final class EntityListeners implements Annotation
{
/**
* Specifies the names of the entity listeners.
*
* @var array
*/
public $value = array();
} doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/EntityResult.php 0000664 0000000 0000000 00000003770 13215356457 0023247 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* References an entity in the SELECT clause of a SQL query.
* If this annotation is used, the SQL statement should select all of the columns that are mapped to the entity object.
* This should include foreign key columns to related entities.
* The results obtained when insufficient data is available are undefined.
*
* @author Fabio B. Silva
* @since 2.3
*
* @Annotation
* @Target("ANNOTATION")
*/
final class EntityResult implements Annotation
{
/**
* The class of the result.
*
* @var string
*/
public $entityClass;
/**
* Maps the columns specified in the SELECT list of the query to the properties or fields of the entity class.
*
* @var array<\Doctrine\ORM\Mapping\FieldResult>
*/
public $fields = array();
/**
* Specifies the column name of the column in the SELECT list that is used to determine the type of the entity instance.
*
* @var string
*/
public $discriminatorColumn;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/FieldResult.php 0000664 0000000 0000000 00000003017 13215356457 0023010 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* Is used to map the columns specified in the SELECT list of the query to the properties or fields of the entity class.
*
* @author Fabio B. Silva
* @since 2.3
*
* @Annotation
* @Target("ANNOTATION")
*/
final class FieldResult implements Annotation
{
/**
* Name of the column in the SELECT clause.
*
* @var string
*/
public $name;
/**
* Name of the persistent field or property of the class.
*
* @var string
*/
public $column;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/GeneratedValue.php 0000664 0000000 0000000 00000002444 13215356457 0023464 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class GeneratedValue implements Annotation
{
/**
* The type of Id generator.
*
* @var string
*
* @Enum({"AUTO", "SEQUENCE", "TABLE", "IDENTITY", "NONE", "UUID", "CUSTOM"})
*/
public $strategy = 'AUTO';
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/HasLifecycleCallbacks.php 0000664 0000000 0000000 00000002145 13215356457 0024722 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class HasLifecycleCallbacks implements Annotation
{
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/Id.php 0000664 0000000 0000000 00000002125 13215356457 0021121 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class Id implements Annotation
{
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/Index.php 0000664 0000000 0000000 00000002505 13215356457 0021636 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("ANNOTATION")
*/
final class Index implements Annotation
{
/**
* @var string
*/
public $name;
/**
* @var array
*/
public $columns;
/**
* @var array
*/
public $flags;
/**
* @var array
*/
public $options;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/InheritanceType.php 0000664 0000000 0000000 00000002451 13215356457 0023662 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class InheritanceType implements Annotation
{
/**
* The inheritance type used by the class and its subclasses.
*
* @var string
*
* @Enum({"NONE", "JOINED", "SINGLE_TABLE", "TABLE_PER_CLASS"})
*/
public $value;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/JoinColumn.php 0000664 0000000 0000000 00000003155 13215356457 0022646 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target({"PROPERTY","ANNOTATION"})
*/
final class JoinColumn implements Annotation
{
/**
* @var string
*/
public $name;
/**
* @var string
*/
public $referencedColumnName = 'id';
/**
* @var boolean
*/
public $unique = false;
/**
* @var boolean
*/
public $nullable = true;
/**
* @var mixed
*/
public $onDelete;
/**
* @var string
*/
public $columnDefinition;
/**
* Field name used in non-object hydration (array/scalar).
*
* @var string
*/
public $fieldName;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/JoinColumns.php 0000664 0000000 0000000 00000002265 13215356457 0023032 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class JoinColumns implements Annotation
{
/**
* @var array<\Doctrine\ORM\Mapping\JoinColumn>
*/
public $value;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/JoinTable.php 0000664 0000000 0000000 00000002657 13215356457 0022446 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target({"PROPERTY","ANNOTATION"})
*/
final class JoinTable implements Annotation
{
/**
* @var string
*/
public $name;
/**
* @var string
*/
public $schema;
/**
* @var array<\Doctrine\ORM\Mapping\JoinColumn>
*/
public $joinColumns = array();
/**
* @var array<\Doctrine\ORM\Mapping\JoinColumn>
*/
public $inverseJoinColumns = array();
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/ManyToMany.php 0000664 0000000 0000000 00000003206 13215356457 0022622 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class ManyToMany implements Annotation
{
/**
* @var string
*/
public $targetEntity;
/**
* @var string
*/
public $mappedBy;
/**
* @var string
*/
public $inversedBy;
/**
* @var array
*/
public $cascade;
/**
* The fetching strategy to use for the association.
*
* @var string
*
* @Enum({"LAZY", "EAGER", "EXTRA_LAZY"})
*/
public $fetch = 'LAZY';
/**
* @var boolean
*/
public $orphanRemoval = false;
/**
* @var string
*/
public $indexBy;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/ManyToOne.php 0000664 0000000 0000000 00000002712 13215356457 0022440 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class ManyToOne implements Annotation
{
/**
* @var string
*/
public $targetEntity;
/**
* @var array
*/
public $cascade;
/**
* The fetching strategy to use for the association.
*
* @var string
*
* @Enum({"LAZY", "EAGER", "EXTRA_LAZY"})
*/
public $fetch = 'LAZY';
/**
* @var string
*/
public $inversedBy;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/MappedSuperclass.php 0000664 0000000 0000000 00000002240 13215356457 0024036 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class MappedSuperclass implements Annotation
{
/**
* @var string
*/
public $repositoryClass;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/MappingException.php 0000664 0000000 0000000 00000061364 13215356457 0024051 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* A MappingException indicates that something is wrong with the mapping setup.
*
* @since 2.0
*/
class MappingException extends \Doctrine\ORM\ORMException
{
/**
* @return MappingException
*/
public static function pathRequired()
{
return new self("Specifying the paths to your entities is required ".
"in the AnnotationDriver to retrieve all class names.");
}
/**
* @param string $entityName
*
* @return MappingException
*/
public static function identifierRequired($entityName)
{
if (false !== ($parent = get_parent_class($entityName))) {
return new self(sprintf(
'No identifier/primary key specified for Entity "%s" sub class of "%s". Every Entity must have an identifier/primary key.',
$entityName, $parent
));
}
return new self(sprintf(
'No identifier/primary key specified for Entity "%s". Every Entity must have an identifier/primary key.',
$entityName
));
}
/**
* @param string $entityName
* @param string $type
*
* @return MappingException
*/
public static function invalidInheritanceType($entityName, $type)
{
return new self("The inheritance type '$type' specified for '$entityName' does not exist.");
}
/**
* @return MappingException
*/
public static function generatorNotAllowedWithCompositeId()
{
return new self("Id generators can't be used with a composite id.");
}
/**
* @param string $entity
*
* @return MappingException
*/
public static function missingFieldName($entity)
{
return new self("The field or association mapping misses the 'fieldName' attribute in entity '$entity'.");
}
/**
* @param string $fieldName
*
* @return MappingException
*/
public static function missingTargetEntity($fieldName)
{
return new self("The association mapping '$fieldName' misses the 'targetEntity' attribute.");
}
/**
* @param string $fieldName
*
* @return MappingException
*/
public static function missingSourceEntity($fieldName)
{
return new self("The association mapping '$fieldName' misses the 'sourceEntity' attribute.");
}
/**
* @param string $fieldName
*
* @return MappingException
*/
public static function missingEmbeddedClass($fieldName)
{
return new self("The embed mapping '$fieldName' misses the 'class' attribute.");
}
/**
* @param string $entityName
* @param string $fileName
*
* @return MappingException
*/
public static function mappingFileNotFound($entityName, $fileName)
{
return new self("No mapping file found named '$fileName' for class '$entityName'.");
}
/**
* Exception for invalid property name override.
*
* @param string $className The entity's name.
* @param string $fieldName
*
* @return MappingException
*/
public static function invalidOverrideFieldName($className, $fieldName)
{
return new self("Invalid field override named '$fieldName' for class '$className'.");
}
/**
* Exception for invalid property type override.
*
* @param string $className The entity's name.
* @param string $fieldName
*
* @return MappingException
*/
public static function invalidOverrideFieldType($className, $fieldName)
{
return new self("The column type of attribute '$fieldName' on class '$className' could not be changed.");
}
/**
* @param string $className
* @param string $fieldName
*
* @return MappingException
*/
public static function mappingNotFound($className, $fieldName)
{
return new self("No mapping found for field '$fieldName' on class '$className'.");
}
/**
* @param string $className
* @param string $queryName
*
* @return MappingException
*/
public static function queryNotFound($className, $queryName)
{
return new self("No query found named '$queryName' on class '$className'.");
}
/**
* @param string $className
* @param string $resultName
*
* @return MappingException
*/
public static function resultMappingNotFound($className, $resultName)
{
return new self("No result set mapping found named '$resultName' on class '$className'.");
}
/**
* @param string $entity
* @param string $queryName
*
* @return MappingException
*/
public static function emptyQueryMapping($entity, $queryName)
{
return new self('Query named "'.$queryName.'" in "'.$entity.'" could not be empty.');
}
/**
* @param string $className
*
* @return MappingException
*/
public static function nameIsMandatoryForQueryMapping($className)
{
return new self("Query name on entity class '$className' is not defined.");
}
/**
* @param string $entity
* @param string $queryName
*
* @return MappingException
*/
public static function missingQueryMapping($entity, $queryName)
{
return new self('Query named "'.$queryName.'" in "'.$entity.' requires a result class or result set mapping.');
}
/**
* @param string $entity
* @param string $resultName
*
* @return MappingException
*/
public static function missingResultSetMappingEntity($entity, $resultName)
{
return new self('Result set mapping named "'.$resultName.'" in "'.$entity.' requires a entity class name.');
}
/**
* @param string $entity
* @param string $resultName
*
* @return MappingException
*/
public static function missingResultSetMappingFieldName($entity, $resultName)
{
return new self('Result set mapping named "'.$resultName.'" in "'.$entity.' requires a field name.');
}
/**
* @param string $className
*
* @return MappingException
*/
public static function nameIsMandatoryForSqlResultSetMapping($className)
{
return new self("Result set mapping name on entity class '$className' is not defined.");
}
/**
* @param string $fieldName
*
* @return MappingException
*/
public static function oneToManyRequiresMappedBy($fieldName)
{
return new self("OneToMany mapping on field '$fieldName' requires the 'mappedBy' attribute.");
}
/**
* @param string $fieldName
*
* @return MappingException
*/
public static function joinTableRequired($fieldName)
{
return new self("The mapping of field '$fieldName' requires an the 'joinTable' attribute.");
}
/**
* Called if a required option was not found but is required
*
* @param string $field Which field cannot be processed?
* @param string $expectedOption Which option is required
* @param string $hint Can optionally be used to supply a tip for common mistakes,
* e.g. "Did you think of the plural s?"
*
* @return MappingException
*/
static function missingRequiredOption($field, $expectedOption, $hint = '')
{
$message = "The mapping of field '{$field}' is invalid: The option '{$expectedOption}' is required.";
if ( ! empty($hint)) {
$message .= ' (Hint: ' . $hint . ')';
}
return new self($message);
}
/**
* Generic exception for invalid mappings.
*
* @param string $fieldName
*
* @return MappingException
*/
public static function invalidMapping($fieldName)
{
return new self("The mapping of field '$fieldName' is invalid.");
}
/**
* Exception for reflection exceptions - adds the entity name,
* because there might be long classnames that will be shortened
* within the stacktrace
*
* @param string $entity The entity's name
* @param \ReflectionException $previousException
*
* @return MappingException
*/
public static function reflectionFailure($entity, \ReflectionException $previousException)
{
return new self('An error occurred in ' . $entity, 0, $previousException);
}
/**
* @param string $className
* @param string $joinColumn
*
* @return MappingException
*/
public static function joinColumnMustPointToMappedField($className, $joinColumn)
{
return new self('The column ' . $joinColumn . ' must be mapped to a field in class '
. $className . ' since it is referenced by a join column of another class.');
}
/**
* @param string $className
*
* @return MappingException
*/
public static function classIsNotAValidEntityOrMappedSuperClass($className)
{
if (false !== ($parent = get_parent_class($className))) {
return new self(sprintf(
'Class "%s" sub class of "%s" is not a valid entity or mapped super class.',
$className, $parent
));
}
return new self(sprintf(
'Class "%s" is not a valid entity or mapped super class.',
$className
));
}
/**
* @param string $className
* @param string $propertyName
*
* @return MappingException
*/
public static function propertyTypeIsRequired($className, $propertyName)
{
return new self("The attribute 'type' is required for the column description of property ".$className."::\$".$propertyName.".");
}
/**
* @param string $className
*
* @return MappingException
*/
public static function tableIdGeneratorNotImplemented($className)
{
return new self("TableIdGenerator is not yet implemented for use with class ".$className);
}
/**
* @param string $entity The entity's name.
* @param string $fieldName The name of the field that was already declared.
*
* @return MappingException
*/
public static function duplicateFieldMapping($entity, $fieldName)
{
return new self('Property "'.$fieldName.'" in "'.$entity.'" was already declared, but it must be declared only once');
}
/**
* @param string $entity
* @param string $fieldName
*
* @return MappingException
*/
public static function duplicateAssociationMapping($entity, $fieldName)
{
return new self('Property "'.$fieldName.'" in "'.$entity.'" was already declared, but it must be declared only once');
}
/**
* @param string $entity
* @param string $queryName
*
* @return MappingException
*/
public static function duplicateQueryMapping($entity, $queryName)
{
return new self('Query named "'.$queryName.'" in "'.$entity.'" was already declared, but it must be declared only once');
}
/**
* @param string $entity
* @param string $resultName
*
* @return MappingException
*/
public static function duplicateResultSetMapping($entity, $resultName)
{
return new self('Result set mapping named "'.$resultName.'" in "'.$entity.'" was already declared, but it must be declared only once');
}
/**
* @param string $entity
*
* @return MappingException
*/
public static function singleIdNotAllowedOnCompositePrimaryKey($entity)
{
return new self('Single id is not allowed on composite primary key in entity '.$entity);
}
/**
* @param string $entity
* @param string $fieldName
* @param string $unsupportedType
*
* @return MappingException
*/
public static function unsupportedOptimisticLockingType($entity, $fieldName, $unsupportedType)
{
return new self('Locking type "'.$unsupportedType.'" (specified in "'.$entity.'", field "'.$fieldName.'") '
.'is not supported by Doctrine.'
);
}
/**
* @param string|null $path
*
* @return MappingException
*/
public static function fileMappingDriversRequireConfiguredDirectoryPath($path = null)
{
if ( ! empty($path)) {
$path = '[' . $path . ']';
}
return new self(
'File mapping drivers must have a valid directory path, ' .
'however the given path ' . $path . ' seems to be incorrect!'
);
}
/**
* Returns an exception that indicates that a class used in a discriminator map does not exist.
* An example would be an outdated (maybe renamed) classname.
*
* @param string $className The class that could not be found
* @param string $owningClass The class that declares the discriminator map.
*
* @return MappingException
*/
public static function invalidClassInDiscriminatorMap($className, $owningClass)
{
return new self(
"Entity class '$className' used in the discriminator map of class '$owningClass' ".
"does not exist."
);
}
/**
* @param string $className
* @param array $entries
* @param array $map
*
* @return MappingException
*/
public static function duplicateDiscriminatorEntry($className, array $entries, array $map)
{
return new self(
"The entries " . implode(', ', $entries) . " in discriminator map of class '" . $className . "' is duplicated. " .
"If the discriminator map is automatically generated you have to convert it to an explicit discriminator map now. " .
"The entries of the current map are: @DiscriminatorMap({" . implode(', ', array_map(
function($a, $b) { return "'$a': '$b'"; }, array_keys($map), array_values($map)
)) . "})"
);
}
/**
* @param string $className
*
* @return MappingException
*/
public static function missingDiscriminatorMap($className)
{
return new self("Entity class '$className' is using inheritance but no discriminator map was defined.");
}
/**
* @param string $className
*
* @return MappingException
*/
public static function missingDiscriminatorColumn($className)
{
return new self("Entity class '$className' is using inheritance but no discriminator column was defined.");
}
/**
* @param string $className
* @param string $type
*
* @return MappingException
*/
public static function invalidDiscriminatorColumnType($className, $type)
{
return new self("Discriminator column type on entity class '$className' is not allowed to be '$type'. 'string' or 'integer' type variables are suggested!");
}
/**
* @param string $className
*
* @return MappingException
*/
public static function nameIsMandatoryForDiscriminatorColumns($className)
{
return new self("Discriminator column name on entity class '$className' is not defined.");
}
/**
* @param string $className
* @param string $fieldName
*
* @return MappingException
*/
public static function cannotVersionIdField($className, $fieldName)
{
return new self("Setting Id field '$fieldName' as versionable in entity class '$className' is not supported.");
}
/**
* @param string $className
* @param string $fieldName
* @param string $type
*
* @return MappingException
*/
public static function sqlConversionNotAllowedForIdentifiers($className, $fieldName, $type)
{
return new self("It is not possible to set id field '$fieldName' to type '$type' in entity class '$className'. The type '$type' requires conversion SQL which is not allowed for identifiers.");
}
/**
* @param string $className
* @param string $columnName
*
* @return MappingException
*/
public static function duplicateColumnName($className, $columnName)
{
return new self("Duplicate definition of column '".$columnName."' on entity '".$className."' in a field or discriminator column mapping.");
}
/**
* @param string $className
* @param string $field
*
* @return MappingException
*/
public static function illegalToManyAssociationOnMappedSuperclass($className, $field)
{
return new self("It is illegal to put an inverse side one-to-many or many-to-many association on mapped superclass '".$className."#".$field."'.");
}
/**
* @param string $className
* @param string $targetEntity
* @param string $targetField
*
* @return MappingException
*/
public static function cannotMapCompositePrimaryKeyEntitiesAsForeignId($className, $targetEntity, $targetField)
{
return new self("It is not possible to map entity '".$className."' with a composite primary key ".
"as part of the primary key of another entity '".$targetEntity."#".$targetField."'.");
}
/**
* @param string $className
* @param string $field
*
* @return MappingException
*/
public static function noSingleAssociationJoinColumnFound($className, $field)
{
return new self("'$className#$field' is not an association with a single join column.");
}
/**
* @param string $className
* @param string $column
*
* @return MappingException
*/
public static function noFieldNameFoundForColumn($className, $column)
{
return new self("Cannot find a field on '$className' that is mapped to column '$column'. Either the ".
"field does not exist or an association exists but it has multiple join columns.");
}
/**
* @param string $className
* @param string $field
*
* @return MappingException
*/
public static function illegalOrphanRemovalOnIdentifierAssociation($className, $field)
{
return new self("The orphan removal option is not allowed on an association that is ".
"part of the identifier in '$className#$field'.");
}
/**
* @param string $className
* @param string $field
*
* @return MappingException
*/
public static function illegalOrphanRemoval($className, $field)
{
return new self("Orphan removal is only allowed on one-to-one and one-to-many ".
"associations, but " . $className."#" .$field . " is not.");
}
/**
* @param string $className
* @param string $field
*
* @return MappingException
*/
public static function illegalInverseIdentifierAssociation($className, $field)
{
return new self("An inverse association is not allowed to be identifier in '$className#$field'.");
}
/**
* @param string $className
* @param string $field
*
* @return MappingException
*/
public static function illegalToManyIdentifierAssociation($className, $field)
{
return new self("Many-to-many or one-to-many associations are not allowed to be identifier in '$className#$field'.");
}
/**
* @param string $className
*
* @return MappingException
*/
public static function noInheritanceOnMappedSuperClass($className)
{
return new self("It is not supported to define inheritance information on a mapped superclass '" . $className . "'.");
}
/**
* @param string $className
* @param string $rootClassName
*
* @return MappingException
*/
public static function mappedClassNotPartOfDiscriminatorMap($className, $rootClassName)
{
return new self(
"Entity '" . $className . "' has to be part of the discriminator map of '" . $rootClassName . "' " .
"to be properly mapped in the inheritance hierarchy. Alternatively you can make '".$className."' an abstract class " .
"to avoid this exception from occurring."
);
}
/**
* @param string $className
* @param string $methodName
*
* @return MappingException
*/
public static function lifecycleCallbackMethodNotFound($className, $methodName)
{
return new self("Entity '" . $className . "' has no method '" . $methodName . "' to be registered as lifecycle callback.");
}
/**
* @param string $listenerName
* @param string $className
*
* @return \Doctrine\ORM\Mapping\MappingException
*/
public static function entityListenerClassNotFound($listenerName, $className)
{
return new self(sprintf('Entity Listener "%s" declared on "%s" not found.', $listenerName, $className));
}
/**
* @param string $listenerName
* @param string $methodName
* @param string $className
*
* @return \Doctrine\ORM\Mapping\MappingException
*/
public static function entityListenerMethodNotFound($listenerName, $methodName, $className)
{
return new self(sprintf('Entity Listener "%s" declared on "%s" has no method "%s".', $listenerName, $className, $methodName));
}
/**
* @param string $listenerName
* @param string $methodName
* @param string $className
*
* @return \Doctrine\ORM\Mapping\MappingException
*/
public static function duplicateEntityListener($listenerName, $methodName, $className)
{
return new self(sprintf('Entity Listener "%s#%s()" in "%s" was already declared, but it must be declared only once.', $listenerName, $methodName, $className));
}
/**
* @param string $className
* @param string $annotation
*
* @return MappingException
*/
public static function invalidFetchMode($className, $annotation)
{
return new self("Entity '" . $className . "' has a mapping with invalid fetch mode '" . $annotation . "'");
}
/**
* @param string $className
*
* @return MappingException
*/
public static function compositeKeyAssignedIdGeneratorRequired($className)
{
return new self("Entity '". $className . "' has a composite identifier but uses an ID generator other than manually assigning (Identity, Sequence). This is not supported.");
}
/**
* @param string $targetEntity
* @param string $sourceEntity
* @param string $associationName
*
* @return MappingException
*/
public static function invalidTargetEntityClass($targetEntity, $sourceEntity, $associationName)
{
return new self("The target-entity " . $targetEntity . " cannot be found in '" . $sourceEntity."#".$associationName."'.");
}
/**
* @param array $cascades
* @param string $className
* @param string $propertyName
*
* @return MappingException
*/
public static function invalidCascadeOption(array $cascades, $className, $propertyName)
{
$cascades = implode(", ", array_map(function ($e) { return "'" . $e . "'"; }, $cascades));
return new self(sprintf(
"You have specified invalid cascade options for %s::$%s: %s; available options: 'remove', 'persist', 'refresh', 'merge', and 'detach'",
$className,
$propertyName,
$cascades
));
}
/**
* @param string $className
*
* @return MappingException
*/
public static function missingSequenceName($className)
{
return new self(
sprintf('Missing "sequenceName" attribute for sequence id generator definition on class "%s".', $className)
);
}
/**
* @param string $className
* @param string $propertyName
*
* @return MappingException
*/
public static function infiniteEmbeddableNesting($className, $propertyName)
{
return new self(
sprintf(
'Infinite nesting detected for embedded property %s::%s. ' .
'You cannot embed an embeddable from the same type inside an embeddable.',
$className,
$propertyName
)
);
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/NamedNativeQueries.php 0000664 0000000 0000000 00000002742 13215356457 0024323 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* Is used to specify an array of native SQL named queries.
* The NamedNativeQueries annotation can be applied to an entity or mapped superclass.
*
* @author Fabio B. Silva
* @since 2.3
*
* @Annotation
* @Target("CLASS")
*/
final class NamedNativeQueries implements Annotation
{
/**
* One or more NamedNativeQuery annotations.
*
* @var array<\Doctrine\ORM\Mapping\NamedNativeQuery>
*/
public $value = array();
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/NamedNativeQuery.php 0000664 0000000 0000000 00000003444 13215356457 0024013 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* Is used to specify a native SQL named query.
* The NamedNativeQuery annotation can be applied to an entity or mapped superclass.
*
* @author Fabio B. Silva
* @since 2.3
*
* @Annotation
* @Target("ANNOTATION")
*/
final class NamedNativeQuery implements Annotation
{
/**
* The name used to refer to the query with the EntityManager methods that create query objects.
*
* @var string
*/
public $name;
/**
* The SQL query string.
*
* @var string
*/
public $query;
/**
* The class of the result.
*
* @var string
*/
public $resultClass;
/**
* The name of a SqlResultSetMapping, as defined in metadata.
*
* @var string
*/
public $resultSetMapping;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/NamedQueries.php 0000664 0000000 0000000 00000002263 13215356457 0023152 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class NamedQueries implements Annotation
{
/**
* @var array<\Doctrine\ORM\Mapping\NamedQuery>
*/
public $value;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/NamedQuery.php 0000664 0000000 0000000 00000002313 13215356457 0022636 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("ANNOTATION")
*/
final class NamedQuery implements Annotation
{
/**
* @var string
*/
public $name;
/**
* @var string
*/
public $query;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/NamingStrategy.php 0000664 0000000 0000000 00000006411 13215356457 0023523 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* A set of rules for determining the physical column and table names
*
*
* @link www.doctrine-project.org
* @since 2.3
* @author Fabio B. Silva
*/
interface NamingStrategy
{
/**
* Returns a table name for an entity class.
*
* @param string $className The fully-qualified class name.
*
* @return string A table name.
*/
function classToTableName($className);
/**
* Returns a column name for a property.
*
* @param string $propertyName A property name.
* @param string|null $className The fully-qualified class name.
*
* @return string A column name.
*/
function propertyToColumnName($propertyName, $className = null);
/**
* Returns a column name for an embedded property.
*
* @param string $propertyName
* @param string $embeddedColumnName
*
* @return string
*/
function embeddedFieldToColumnName($propertyName, $embeddedColumnName, $className = null, $embeddedClassName = null);
/**
* Returns the default reference column name.
*
* @return string A column name.
*/
function referenceColumnName();
/**
* Returns a join column name for a property.
*
* @param string $propertyName A property name.
* @param string|null $className The fully-qualified class name.
* This parameter is omitted from the signature due to BC
*
* @return string A join column name.
*/
function joinColumnName($propertyName/*, $className = null*/);
/**
* Returns a join table name.
*
* @param string $sourceEntity The source entity.
* @param string $targetEntity The target entity.
* @param string|null $propertyName A property name.
*
* @return string A join table name.
*/
function joinTableName($sourceEntity, $targetEntity, $propertyName = null);
/**
* Returns the foreign key column name for the given parameters.
*
* @param string $entityName An entity.
* @param string|null $referencedColumnName A property.
*
* @return string A join column name.
*/
function joinKeyColumnName($entityName, $referencedColumnName = null);
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/OneToMany.php 0000664 0000000 0000000 00000003111 13215356457 0022432 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class OneToMany implements Annotation
{
/**
* @var string
*/
public $mappedBy;
/**
* @var string
*/
public $targetEntity;
/**
* @var array
*/
public $cascade;
/**
* The fetching strategy to use for the association.
*
* @var string
*
* @Enum({"LAZY", "EAGER", "EXTRA_LAZY"})
*/
public $fetch = 'LAZY';
/**
* @var boolean
*/
public $orphanRemoval = false;
/**
* @var string
*/
public $indexBy;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/OneToOne.php 0000664 0000000 0000000 00000003113 13215356457 0022251 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class OneToOne implements Annotation
{
/**
* @var string
*/
public $targetEntity;
/**
* @var string
*/
public $mappedBy;
/**
* @var string
*/
public $inversedBy;
/**
* @var array
*/
public $cascade;
/**
* The fetching strategy to use for the association.
*
* @var string
*
* @Enum({"LAZY", "EAGER", "EXTRA_LAZY"})
*/
public $fetch = 'LAZY';
/**
* @var boolean
*/
public $orphanRemoval = false;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/OrderBy.php 0000664 0000000 0000000 00000002227 13215356457 0022136 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class OrderBy implements Annotation
{
/**
* @var array
*/
public $value;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/PostLoad.php 0000664 0000000 0000000 00000002131 13215356457 0022307 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PostLoad implements Annotation
{
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/PostPersist.php 0000664 0000000 0000000 00000002134 13215356457 0023064 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PostPersist implements Annotation
{
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/PostRemove.php 0000664 0000000 0000000 00000002133 13215356457 0022667 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PostRemove implements Annotation
{
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/PostUpdate.php 0000664 0000000 0000000 00000002133 13215356457 0022654 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PostUpdate implements Annotation
{
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/PreFlush.php 0000664 0000000 0000000 00000002131 13215356457 0022312 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PreFlush implements Annotation
{
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/PrePersist.php 0000664 0000000 0000000 00000002133 13215356457 0022664 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PrePersist implements Annotation
{
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/PreRemove.php 0000664 0000000 0000000 00000002132 13215356457 0022467 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PreRemove implements Annotation
{
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/PreUpdate.php 0000664 0000000 0000000 00000002132 13215356457 0022454 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PreUpdate implements Annotation
{
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/QuoteStrategy.php 0000664 0000000 0000000 00000007520 13215356457 0023411 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
use Doctrine\DBAL\Platforms\AbstractPlatform;
/**
* A set of rules for determining the column, alias and table quotes.
*
* @since 2.3
* @author Fabio B. Silva
*/
interface QuoteStrategy
{
/**
* Gets the (possibly quoted) column name for safe use in an SQL statement.
*
* @param string $fieldName
* @param ClassMetadata $class
* @param AbstractPlatform $platform
*
* @return string
*/
function getColumnName($fieldName, ClassMetadata $class, AbstractPlatform $platform);
/**
* Gets the (possibly quoted) primary table name for safe use in an SQL statement.
*
* @param ClassMetadata $class
* @param AbstractPlatform $platform
*
* @return string
*/
function getTableName(ClassMetadata $class, AbstractPlatform $platform);
/**
* Gets the (possibly quoted) sequence name for safe use in an SQL statement.
*
* @param array $definition
* @param ClassMetadata $class
* @param AbstractPlatform $platform
*
* @return string
*/
function getSequenceName(array $definition, ClassMetadata $class, AbstractPlatform $platform);
/**
* Gets the (possibly quoted) name of the join table.
*
* @param array $association
* @param ClassMetadata $class
* @param AbstractPlatform $platform
*
* @return string
*/
function getJoinTableName(array $association, ClassMetadata $class, AbstractPlatform $platform);
/**
* Gets the (possibly quoted) join column name.
*
* @param array $joinColumn
* @param ClassMetadata $class
* @param AbstractPlatform $platform
*
* @return string
*/
function getJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform);
/**
* Gets the (possibly quoted) join column name.
*
* @param array $joinColumn
* @param ClassMetadata $class
* @param AbstractPlatform $platform
*
* @return string
*/
function getReferencedJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform);
/**
* Gets the (possibly quoted) identifier column names for safe use in an SQL statement.
*
* @param ClassMetadata $class
* @param AbstractPlatform $platform
*
* @return array
*/
function getIdentifierColumnNames(ClassMetadata $class, AbstractPlatform $platform);
/**
* Gets the column alias.
*
* @param string $columnName
* @param integer $counter
* @param AbstractPlatform $platform
* @param ClassMetadata|null $class
*
* @return string
*/
function getColumnAlias($columnName, $counter, AbstractPlatform $platform, ClassMetadata $class = null);
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/Reflection/ 0000775 0000000 0000000 00000000000 13215356457 0022146 5 ustar 00root root 0000000 0000000 doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/Reflection/ReflectionPropertiesGetter.php 0000664 0000000 0000000 00000011260 13215356457 0030201 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping\Reflection;
use Doctrine\Common\Persistence\Mapping\ReflectionService;
use ReflectionClass;
use ReflectionProperty;
/**
* Utility class to retrieve all reflection instance properties of a given class, including
* private inherited properties and transient properties.
*
* @private This API is for internal use only
*
* @author Marco Pivetta
*/
final class ReflectionPropertiesGetter
{
/**
* @var ReflectionProperty[][] indexed by class name and property internal name
*/
private $properties = [];
/**
* @var ReflectionService
*/
private $reflectionService;
/**
* @param ReflectionService $reflectionService
*/
public function __construct(ReflectionService $reflectionService)
{
$this->reflectionService = $reflectionService;
}
/**
* @param $className
*
* @return ReflectionProperty[] indexed by property internal name
*/
public function getProperties($className)
{
if (isset($this->properties[$className])) {
return $this->properties[$className];
}
return $this->properties[$className] = call_user_func_array(
'array_merge',
// first merge because `array_merge` expects >= 1 params
array_merge(
[[]],
array_map(
[$this, 'getClassProperties'],
$this->getHierarchyClasses($className)
)
)
);
}
/**
* @param string $className
*
* @return ReflectionClass[]
*/
private function getHierarchyClasses($className)
{
$classes = [];
$parentClassName = $className;
while ($parentClassName && $currentClass = $this->reflectionService->getClass($parentClassName)) {
$classes[] = $currentClass;
$parentClassName = null;
if ($parentClass = $currentClass->getParentClass()) {
$parentClassName = $parentClass->getName();
}
}
return $classes;
}
/**
* @param ReflectionClass $reflectionClass
*
* @return ReflectionProperty[]
*/
private function getClassProperties(ReflectionClass $reflectionClass)
{
$properties = $reflectionClass->getProperties();
return array_filter(
array_filter(array_map(
[$this, 'getAccessibleProperty'],
array_combine(
array_map([$this, 'getLogicalName'], $properties),
$properties
)
)),
[$this, 'isInstanceProperty']
);
}
/**
* @param ReflectionProperty $reflectionProperty
*
* @return bool
*/
private function isInstanceProperty(ReflectionProperty $reflectionProperty)
{
return ! $reflectionProperty->isStatic();
}
/**
* @param ReflectionProperty $property
*
* @return null|ReflectionProperty
*/
private function getAccessibleProperty(ReflectionProperty $property)
{
return $this->reflectionService->getAccessibleProperty(
$property->getDeclaringClass()->getName(),
$property->getName()
);
}
/**
* @param ReflectionProperty $property
*
* @return string
*/
private function getLogicalName(ReflectionProperty $property)
{
$propertyName = $property->getName();
if ($property->isPublic()) {
return $propertyName;
}
if ($property->isProtected()) {
return "\0*\0" . $propertyName;
}
return "\0" . $property->getDeclaringClass()->getName() . "\0" . $propertyName;
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/ReflectionEmbeddedProperty.php 0000664 0000000 0000000 00000006306 13215356457 0026043 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
use Doctrine\Instantiator\Instantiator;
use ReflectionProperty;
/**
* Acts as a proxy to a nested Property structure, making it look like
* just a single scalar property.
*
* This way value objects "just work" without UnitOfWork, Persisters or Hydrators
* needing any changes.
*
* TODO: Move this class into Common\Reflection
*/
class ReflectionEmbeddedProperty extends ReflectionProperty
{
/**
* @var ReflectionProperty reflection property of the class where the embedded object has to be put
*/
private $parentProperty;
/**
* @var ReflectionProperty reflection property of the embedded object
*/
private $childProperty;
/**
* @var string name of the embedded class to be eventually instantiated
*/
private $embeddedClass;
/**
* @var Instantiator|null
*/
private $instantiator;
/**
* @param ReflectionProperty $parentProperty
* @param ReflectionProperty $childProperty
* @param string $embeddedClass
*/
public function __construct(ReflectionProperty $parentProperty, ReflectionProperty $childProperty, $embeddedClass)
{
$this->parentProperty = $parentProperty;
$this->childProperty = $childProperty;
$this->embeddedClass = (string) $embeddedClass;
parent::__construct($childProperty->getDeclaringClass()->getName(), $childProperty->getName());
}
/**
* {@inheritDoc}
*/
public function getValue($object = null)
{
$embeddedObject = $this->parentProperty->getValue($object);
if (null === $embeddedObject) {
return null;
}
return $this->childProperty->getValue($embeddedObject);
}
/**
* {@inheritDoc}
*/
public function setValue($object, $value = null)
{
$embeddedObject = $this->parentProperty->getValue($object);
if (null === $embeddedObject) {
$this->instantiator = $this->instantiator ?: new Instantiator();
$embeddedObject = $this->instantiator->instantiate($this->embeddedClass);
$this->parentProperty->setValue($object, $embeddedObject);
}
$this->childProperty->setValue($embeddedObject, $value);
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/SequenceGenerator.php 0000664 0000000 0000000 00000002451 13215356457 0024206 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class SequenceGenerator implements Annotation
{
/**
* @var string
*/
public $sequenceName;
/**
* @var integer
*/
public $allocationSize = 1;
/**
* @var integer
*/
public $initialValue = 1;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/SqlResultSetMapping.php 0000664 0000000 0000000 00000003551 13215356457 0024517 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* The SqlResultSetMapping annotation is used to specify the mapping of the result of a native SQL query.
* The SqlResultSetMapping annotation can be applied to an entity or mapped superclass.
*
* @author Fabio B. Silva
* @since 2.3
*
* @Annotation
* @Target("ANNOTATION")
*/
final class SqlResultSetMapping implements Annotation
{
/**
* The name given to the result set mapping, and used to refer to it in the methods of the Query API.
*
* @var string
*/
public $name;
/**
* Specifies the result set mapping to entities.
*
* @var array<\Doctrine\ORM\Mapping\EntityResult>
*/
public $entities = array();
/**
* Specifies the result set mapping to scalar values.
*
* @var array<\Doctrine\ORM\Mapping\ColumnResult>
*/
public $columns = array();
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/SqlResultSetMappings.php 0000664 0000000 0000000 00000002734 13215356457 0024704 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* Is used to specify an array of mappings.
* The SqlResultSetMappings annotation can be applied to an entity or mapped superclass.
*
* @author Fabio B. Silva
* @since 2.3
*
* @Annotation
* @Target("CLASS")
*/
final class SqlResultSetMappings implements Annotation
{
/**
* One or more SqlResultSetMapping annotations.
*
* @var array<\Doctrine\ORM\Mapping\SqlResultSetMapping>
*/
public $value = array();
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/Table.php 0000664 0000000 0000000 00000002703 13215356457 0021616 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class Table implements Annotation
{
/**
* @var string
*/
public $name;
/**
* @var string
*/
public $schema;
/**
* @var array<\Doctrine\ORM\Mapping\Index>
*/
public $indexes;
/**
* @var array<\Doctrine\ORM\Mapping\UniqueConstraint>
*/
public $uniqueConstraints;
/**
* @var array
*/
public $options = array();
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/UnderscoreNamingStrategy.php 0000664 0000000 0000000 00000007476 13215356457 0025571 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* Naming strategy implementing the underscore naming convention.
* Converts 'MyEntity' to 'my_entity' or 'MY_ENTITY'.
*
*
* @link www.doctrine-project.org
* @since 2.3
* @author Fabio B. Silva
*/
class UnderscoreNamingStrategy implements NamingStrategy
{
/**
* @var integer
*/
private $case;
/**
* Underscore naming strategy construct.
*
* @param integer $case CASE_LOWER | CASE_UPPER
*/
public function __construct($case = CASE_LOWER)
{
$this->case = $case;
}
/**
* @return integer CASE_LOWER | CASE_UPPER
*/
public function getCase()
{
return $this->case;
}
/**
* Sets string case CASE_LOWER | CASE_UPPER.
* Alphabetic characters converted to lowercase or uppercase.
*
* @param integer $case
*
* @return void
*/
public function setCase($case)
{
$this->case = $case;
}
/**
* {@inheritdoc}
*/
public function classToTableName($className)
{
if (strpos($className, '\\') !== false) {
$className = substr($className, strrpos($className, '\\') + 1);
}
return $this->underscore($className);
}
/**
* {@inheritdoc}
*/
public function propertyToColumnName($propertyName, $className = null)
{
return $this->underscore($propertyName);
}
/**
* {@inheritdoc}
*/
public function embeddedFieldToColumnName($propertyName, $embeddedColumnName, $className = null, $embeddedClassName = null)
{
return $this->underscore($propertyName).'_'.$embeddedColumnName;
}
/**
* {@inheritdoc}
*/
public function referenceColumnName()
{
return $this->case === CASE_UPPER ? 'ID' : 'id';
}
/**
* {@inheritdoc}
*/
public function joinColumnName($propertyName, $className = null)
{
return $this->underscore($propertyName) . '_' . $this->referenceColumnName();
}
/**
* {@inheritdoc}
*/
public function joinTableName($sourceEntity, $targetEntity, $propertyName = null)
{
return $this->classToTableName($sourceEntity) . '_' . $this->classToTableName($targetEntity);
}
/**
* {@inheritdoc}
*/
public function joinKeyColumnName($entityName, $referencedColumnName = null)
{
return $this->classToTableName($entityName) . '_' .
($referencedColumnName ?: $this->referenceColumnName());
}
/**
* @param string $string
*
* @return string
*/
private function underscore($string)
{
$string = preg_replace('/(?<=[a-z])([A-Z])/', '_$1', $string);
if ($this->case === CASE_UPPER) {
return strtoupper($string);
}
return strtolower($string);
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/UniqueConstraint.php 0000664 0000000 0000000 00000002422 13215356457 0024100 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("ANNOTATION")
*/
final class UniqueConstraint implements Annotation
{
/**
* @var string
*/
public $name;
/**
* @var array
*/
public $columns;
/**
* @var array
*/
public $options;
}
doctrine2-2.5.14/lib/Doctrine/ORM/Mapping/Version.php 0000664 0000000 0000000 00000002132 13215356457 0022210 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class Version implements Annotation
{
}
doctrine2-2.5.14/lib/Doctrine/ORM/NativeQuery.php 0000664 0000000 0000000 00000005104 13215356457 0021446 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM;
/**
* Represents a native SQL query.
*
* @author Roman Borschel
* @since 2.0
*/
final class NativeQuery extends AbstractQuery
{
/**
* @var string
*/
private $_sql;
/**
* Sets the SQL of the query.
*
* @param string $sql
*
* @return NativeQuery This query instance.
*/
public function setSQL($sql)
{
$this->_sql = $sql;
return $this;
}
/**
* Gets the SQL query.
*
* @return mixed The built SQL query or an array of all SQL queries.
*
* @override
*/
public function getSQL()
{
return $this->_sql;
}
/**
* {@inheritdoc}
*/
protected function _doExecute()
{
$parameters = array();
$types = array();
foreach ($this->getParameters() as $parameter) {
$name = $parameter->getName();
$value = $this->processParameterValue($parameter->getValue());
$type = ($parameter->getValue() === $value)
? $parameter->getType()
: Query\ParameterTypeInferer::inferType($value);
$parameters[$name] = $value;
$types[$name] = $type;
}
if ($parameters && is_int(key($parameters))) {
ksort($parameters);
ksort($types);
$parameters = array_values($parameters);
$types = array_values($types);
}
return $this->_em->getConnection()->executeQuery(
$this->_sql, $parameters, $types, $this->_queryCacheProfile
);
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/NoResultException.php 0000664 0000000 0000000 00000002545 13215356457 0022632 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM;
/**
* Exception thrown when an ORM query unexpectedly does not return any results.
*
* @author robo
* @since 2.0
*/
class NoResultException extends UnexpectedResultException
{
/**
* Constructor.
*/
public function __construct()
{
parent::__construct('No result was found for query although at least one row was expected.');
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/NonUniqueResultException.php 0000664 0000000 0000000 00000002265 13215356457 0024176 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM;
/**
* Exception thrown when an ORM query unexpectedly returns more than one result.
*
* @author robo
* @since 2.0
*/
class NonUniqueResultException extends UnexpectedResultException
{
}
doctrine2-2.5.14/lib/Doctrine/ORM/ORMException.php 0000664 0000000 0000000 00000022735 13215356457 0021517 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM;
use Doctrine\Common\Cache\Cache as CacheDriver;
use Exception;
/**
* Base exception class for all ORM exceptions.
*
* @author Roman Borschel
* @since 2.0
*/
class ORMException extends Exception
{
/**
* @return ORMException
*/
public static function missingMappingDriverImpl()
{
return new self("It's a requirement to specify a Metadata Driver and pass it ".
"to Doctrine\\ORM\\Configuration::setMetadataDriverImpl().");
}
/**
* @param string $queryName
*
* @return ORMException
*/
public static function namedQueryNotFound($queryName)
{
return new self('Could not find a named query by the name "' . $queryName . '"');
}
/**
* @param string $nativeQueryName
*
* @return ORMException
*/
public static function namedNativeQueryNotFound($nativeQueryName)
{
return new self('Could not find a named native query by the name "' . $nativeQueryName . '"');
}
/**
* @param object $entity
* @param object $relatedEntity
*
* @return ORMException
*/
public static function entityMissingForeignAssignedId($entity, $relatedEntity)
{
return new self(
"Entity of type " . get_class($entity) . " has identity through a foreign entity " . get_class($relatedEntity) . ", " .
"however this entity has no identity itself. You have to call EntityManager#persist() on the related entity " .
"and make sure that an identifier was generated before trying to persist '" . get_class($entity) . "'. In case " .
"of Post Insert ID Generation (such as MySQL Auto-Increment) this means you have to call " .
"EntityManager#flush() between both persist operations."
);
}
/**
* @param object $entity
* @param string $field
*
* @return ORMException
*/
public static function entityMissingAssignedIdForField($entity, $field)
{
return new self("Entity of type " . get_class($entity) . " is missing an assigned ID for field '" . $field . "'. " .
"The identifier generation strategy for this entity requires the ID field to be populated before ".
"EntityManager#persist() is called. If you want automatically generated identifiers instead " .
"you need to adjust the metadata mapping accordingly."
);
}
/**
* @param string $field
*
* @return ORMException
*/
public static function unrecognizedField($field)
{
return new self("Unrecognized field: $field");
}
/**
*
* @param string $class
* @param string $association
* @param string $given
* @param string $expected
*
* @return \Doctrine\ORM\ORMInvalidArgumentException
*/
public static function unexpectedAssociationValue($class, $association, $given, $expected)
{
return new self(sprintf('Found entity of type %s on association %s#%s, but expecting %s', $given, $class, $association, $expected));
}
/**
* @param string $className
* @param string $field
*
* @return ORMException
*/
public static function invalidOrientation($className, $field)
{
return new self("Invalid order by orientation specified for " . $className . "#" . $field);
}
/**
* @param string $mode
*
* @return ORMException
*/
public static function invalidFlushMode($mode)
{
return new self("'$mode' is an invalid flush mode.");
}
/**
* @return ORMException
*/
public static function entityManagerClosed()
{
return new self("The EntityManager is closed.");
}
/**
* @param string $mode
*
* @return ORMException
*/
public static function invalidHydrationMode($mode)
{
return new self("'$mode' is an invalid hydration mode.");
}
/**
* @return ORMException
*/
public static function mismatchedEventManager()
{
return new self("Cannot use different EventManager instances for EntityManager and Connection.");
}
/**
* @param string $methodName
*
* @return ORMException
*/
public static function findByRequiresParameter($methodName)
{
return new self("You need to pass a parameter to '".$methodName."'");
}
/**
* @param string $entityName
* @param string $fieldName
* @param string $method
*
* @return ORMException
*/
public static function invalidFindByCall($entityName, $fieldName, $method)
{
return new self(
"Entity '".$entityName."' has no field '".$fieldName."'. ".
"You can therefore not call '".$method."' on the entities' repository"
);
}
/**
* @param string $entityName
* @param string $associationFieldName
*
* @return ORMException
*/
public static function invalidFindByInverseAssociation($entityName, $associationFieldName)
{
return new self(
"You cannot search for the association field '".$entityName."#".$associationFieldName."', ".
"because it is the inverse side of an association. Find methods only work on owning side associations."
);
}
/**
* @return ORMException
*/
public static function invalidResultCacheDriver()
{
return new self("Invalid result cache driver; it must implement Doctrine\\Common\\Cache\\Cache.");
}
/**
* @return ORMException
*/
public static function notSupported()
{
return new self("This behaviour is (currently) not supported by Doctrine 2");
}
/**
* @return ORMException
*/
public static function queryCacheNotConfigured()
{
return new self('Query Cache is not configured.');
}
/**
* @return ORMException
*/
public static function metadataCacheNotConfigured()
{
return new self('Class Metadata Cache is not configured.');
}
/**
* @param \Doctrine\Common\Cache\Cache $cache
*
* @return ORMException
*/
public static function queryCacheUsesNonPersistentCache(CacheDriver $cache)
{
return new self('Query Cache uses a non-persistent cache driver, ' . get_class($cache) . '.');
}
/**
* @param \Doctrine\Common\Cache\Cache $cache
*
* @return ORMException
*/
public static function metadataCacheUsesNonPersistentCache(CacheDriver $cache)
{
return new self('Metadata Cache uses a non-persistent cache driver, ' . get_class($cache) . '.');
}
/**
* @return ORMException
*/
public static function proxyClassesAlwaysRegenerating()
{
return new self('Proxy Classes are always regenerating.');
}
/**
* @param string $entityNamespaceAlias
*
* @return ORMException
*/
public static function unknownEntityNamespace($entityNamespaceAlias)
{
return new self(
"Unknown Entity namespace alias '$entityNamespaceAlias'."
);
}
/**
* @param string $className
*
* @return ORMException
*/
public static function invalidEntityRepository($className)
{
return new self("Invalid repository class '".$className."'. It must be a Doctrine\Common\Persistence\ObjectRepository.");
}
/**
* @param string $className
* @param string $fieldName
*
* @return ORMException
*/
public static function missingIdentifierField($className, $fieldName)
{
return new self("The identifier $fieldName is missing for a query of " . $className);
}
/**
* @param string $className
* @param string $fieldName
*
* @return ORMException
*/
public static function unrecognizedIdentifierFields($className, $fieldNames)
{
return new self(
"Unrecognized identifier fields: '" . implode("', '", $fieldNames) . "' " .
"are not present on class '" . $className . "'."
);
}
/**
* @param string $functionName
*
* @return ORMException
*/
public static function overwriteInternalDQLFunctionNotAllowed($functionName)
{
return new self("It is not allowed to overwrite internal function '$functionName' in the DQL parser through user-defined functions.");
}
/**
* @return ORMException
*/
public static function cantUseInOperatorOnCompositeKeys()
{
return new self("Can't use IN operator on entities that have composite keys.");
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/ORMInvalidArgumentException.php 0000664 0000000 0000000 00000017366 13215356457 0024535 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM;
use Doctrine\ORM\Mapping\ClassMetadata;
/**
* Contains exception messages for all invalid lifecycle state exceptions inside UnitOfWork
*
* @author Benjamin Eberlei
*/
class ORMInvalidArgumentException extends \InvalidArgumentException
{
/**
* @param object $entity
*
* @return ORMInvalidArgumentException
*/
static public function scheduleInsertForManagedEntity($entity)
{
return new self("A managed+dirty entity " . self::objToStr($entity) . " can not be scheduled for insertion.");
}
/**
* @param object $entity
*
* @return ORMInvalidArgumentException
*/
static public function scheduleInsertForRemovedEntity($entity)
{
return new self("Removed entity " . self::objToStr($entity) . " can not be scheduled for insertion.");
}
/**
* @param object $entity
*
* @return ORMInvalidArgumentException
*/
static public function scheduleInsertTwice($entity)
{
return new self("Entity " . self::objToStr($entity) . " can not be scheduled for insertion twice.");
}
/**
* @param string $className
* @param object $entity
*
* @return ORMInvalidArgumentException
*/
static public function entityWithoutIdentity($className, $entity)
{
return new self(
"The given entity of type '" . $className . "' (".self::objToStr($entity).") has no identity/no " .
"id values set. It cannot be added to the identity map."
);
}
/**
* @param object $entity
*
* @return ORMInvalidArgumentException
*/
static public function readOnlyRequiresManagedEntity($entity)
{
return new self("Only managed entities can be marked or checked as read only. But " . self::objToStr($entity) . " is not");
}
/**
* @param array $assoc
* @param object $entry
*
* @return ORMInvalidArgumentException
*/
static public function newEntityFoundThroughRelationship(array $assoc, $entry)
{
return new self("A new entity was found through the relationship '"
. $assoc['sourceEntity'] . "#" . $assoc['fieldName'] . "' that was not"
. " configured to cascade persist operations for entity: " . self::objToStr($entry) . "."
. " To solve this issue: Either explicitly call EntityManager#persist()"
. " on this unknown entity or configure cascade persist "
. " this association in the mapping for example @ManyToOne(..,cascade={\"persist\"})."
. (method_exists($entry, '__toString') ?
"":
" If you cannot find out which entity causes the problem"
." implement '" . $assoc['targetEntity'] . "#__toString()' to get a clue."));
}
/**
* @param array $assoc
* @param object $entry
*
* @return ORMInvalidArgumentException
*/
static public function detachedEntityFoundThroughRelationship(array $assoc, $entry)
{
return new self("A detached entity of type " . $assoc['targetEntity'] . " (" . self::objToStr($entry) . ") "
. " was found through the relationship '" . $assoc['sourceEntity'] . "#" . $assoc['fieldName'] . "' "
. "during cascading a persist operation.");
}
/**
* @param object $entity
*
* @return ORMInvalidArgumentException
*/
static public function entityNotManaged($entity)
{
return new self("Entity " . self::objToStr($entity) . " is not managed. An entity is managed if its fetched " .
"from the database or registered as new through EntityManager#persist");
}
/**
* @param object $entity
* @param string $operation
*
* @return ORMInvalidArgumentException
*/
static public function entityHasNoIdentity($entity, $operation)
{
return new self("Entity has no identity, therefore " . $operation ." cannot be performed. " . self::objToStr($entity));
}
/**
* @param object $entity
* @param string $operation
*
* @return ORMInvalidArgumentException
*/
static public function entityIsRemoved($entity, $operation)
{
return new self("Entity is removed, therefore " . $operation ." cannot be performed. " . self::objToStr($entity));
}
/**
* @param object $entity
* @param string $operation
*
* @return ORMInvalidArgumentException
*/
static public function detachedEntityCannot($entity, $operation)
{
return new self("Detached entity " . self::objToStr($entity) . " cannot be " . $operation);
}
/**
* @param string $context
* @param mixed $given
* @param int $parameterIndex
*
* @return ORMInvalidArgumentException
*/
public static function invalidObject($context, $given, $parameterIndex = 1)
{
return new self($context . ' expects parameter ' . $parameterIndex .
' to be an entity object, '. gettype($given) . ' given.');
}
/**
* @return ORMInvalidArgumentException
*/
public static function invalidCompositeIdentifier()
{
return new self("Binding an entity with a composite primary key to a query is not supported. " .
"You should split the parameter into the explicit fields and bind them separately.");
}
/**
* @return ORMInvalidArgumentException
*/
public static function invalidIdentifierBindingEntity()
{
return new self("Binding entities to query parameters only allowed for entities that have an identifier.");
}
/**
* @param ClassMetadata $targetClass
* @param array $assoc
* @param mixed $actualValue
*
* @return self
*/
public static function invalidAssociation(ClassMetadata $targetClass, $assoc, $actualValue)
{
$expectedType = 'Doctrine\Common\Collections\Collection|array';
if (($assoc['type'] & ClassMetadata::TO_ONE) > 0) {
$expectedType = $targetClass->getName();
}
return new self(sprintf(
'Expected value of type "%s" for association field "%s#$%s", got "%s" instead.',
$expectedType,
$assoc['sourceEntity'],
$assoc['fieldName'],
is_object($actualValue) ? get_class($actualValue) : gettype($actualValue)
));
}
/**
* Helper method to show an object as string.
*
* @param object $obj
*
* @return string
*/
private static function objToStr($obj)
{
return method_exists($obj, '__toString') ? (string)$obj : get_class($obj).'@'.spl_object_hash($obj);
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/OptimisticLockException.php 0000664 0000000 0000000 00000005631 13215356457 0024013 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM;
/**
* An OptimisticLockException is thrown when a version check on an object
* that uses optimistic locking through a version field fails.
*
* @author Roman Borschel
* @author Benjamin Eberlei
* @since 2.0
*/
class OptimisticLockException extends ORMException
{
/**
* @var object|null
*/
private $entity;
/**
* @param string $msg
* @param object $entity
*/
public function __construct($msg, $entity)
{
parent::__construct($msg);
$this->entity = $entity;
}
/**
* Gets the entity that caused the exception.
*
* @return object|null
*/
public function getEntity()
{
return $this->entity;
}
/**
* @param object $entity
*
* @return OptimisticLockException
*/
public static function lockFailed($entity)
{
return new self("The optimistic lock on an entity failed.", $entity);
}
/**
* @param object $entity
* @param int $expectedLockVersion
* @param int $actualLockVersion
*
* @return OptimisticLockException
*/
public static function lockFailedVersionMismatch($entity, $expectedLockVersion, $actualLockVersion)
{
$expectedLockVersion = ($expectedLockVersion instanceof \DateTime) ? $expectedLockVersion->getTimestamp() : $expectedLockVersion;
$actualLockVersion = ($actualLockVersion instanceof \DateTime) ? $actualLockVersion->getTimestamp() : $actualLockVersion;
return new self("The optimistic lock failed, version " . $expectedLockVersion . " was expected, but is actually ".$actualLockVersion, $entity);
}
/**
* @param string $entityName
*
* @return OptimisticLockException
*/
public static function notVersioned($entityName)
{
return new self("Cannot obtain optimistic lock on unversioned entity " . $entityName, null);
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/PersistentCollection.php 0000664 0000000 0000000 00000051507 13215356457 0023356 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM;
use Doctrine\Common\Collections\AbstractLazyCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Selectable;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
/**
* A PersistentCollection represents a collection of elements that have persistent state.
*
* Collections of entities represent only the associations (links) to those entities.
* That means, if the collection is part of a many-many mapping and you remove
* entities from the collection, only the links in the relation table are removed (on flush).
* Similarly, if you remove entities from a collection that is part of a one-many
* mapping this will only result in the nulling out of the foreign keys on flush.
*
* @since 2.0
* @author Konsta Vesterinen
* @author Roman Borschel
* @author Giorgio Sironi
* @author Stefano Rodriguez
*/
final class PersistentCollection extends AbstractLazyCollection implements Selectable
{
/**
* A snapshot of the collection at the moment it was fetched from the database.
* This is used to create a diff of the collection at commit time.
*
* @var array
*/
private $snapshot = array();
/**
* The entity that owns this collection.
*
* @var object
*/
private $owner;
/**
* The association mapping the collection belongs to.
* This is currently either a OneToManyMapping or a ManyToManyMapping.
*
* @var array
*/
private $association;
/**
* The EntityManager that manages the persistence of the collection.
*
* @var \Doctrine\ORM\EntityManagerInterface
*/
private $em;
/**
* The name of the field on the target entities that points to the owner
* of the collection. This is only set if the association is bi-directional.
*
* @var string
*/
private $backRefFieldName;
/**
* The class descriptor of the collection's entity type.
*
* @var ClassMetadata
*/
private $typeClass;
/**
* Whether the collection is dirty and needs to be synchronized with the database
* when the UnitOfWork that manages its persistent state commits.
*
* @var boolean
*/
private $isDirty = false;
/**
* Creates a new persistent collection.
*
* @param EntityManagerInterface $em The EntityManager the collection will be associated with.
* @param ClassMetadata $class The class descriptor of the entity type of this collection.
* @param Collection $collection The collection elements.
*/
public function __construct(EntityManagerInterface $em, $class, Collection $collection)
{
$this->collection = $collection;
$this->em = $em;
$this->typeClass = $class;
$this->initialized = true;
}
/**
* INTERNAL:
* Sets the collection's owning entity together with the AssociationMapping that
* describes the association between the owner and the elements of the collection.
*
* @param object $entity
* @param array $assoc
*
* @return void
*/
public function setOwner($entity, array $assoc)
{
$this->owner = $entity;
$this->association = $assoc;
$this->backRefFieldName = $assoc['inversedBy'] ?: $assoc['mappedBy'];
}
/**
* INTERNAL:
* Gets the collection owner.
*
* @return object
*/
public function getOwner()
{
return $this->owner;
}
/**
* @return Mapping\ClassMetadata
*/
public function getTypeClass()
{
return $this->typeClass;
}
/**
* INTERNAL:
* Adds an element to a collection during hydration. This will automatically
* complete bidirectional associations in the case of a one-to-many association.
*
* @param mixed $element The element to add.
*
* @return void
*/
public function hydrateAdd($element)
{
$this->collection->add($element);
// If _backRefFieldName is set and its a one-to-many association,
// we need to set the back reference.
if ($this->backRefFieldName && $this->association['type'] === ClassMetadata::ONE_TO_MANY) {
// Set back reference to owner
$this->typeClass->reflFields[$this->backRefFieldName]->setValue(
$element, $this->owner
);
$this->em->getUnitOfWork()->setOriginalEntityProperty(
spl_object_hash($element), $this->backRefFieldName, $this->owner
);
}
}
/**
* INTERNAL:
* Sets a keyed element in the collection during hydration.
*
* @param mixed $key The key to set.
* @param mixed $element The element to set.
*
* @return void
*/
public function hydrateSet($key, $element)
{
$this->collection->set($key, $element);
// If _backRefFieldName is set, then the association is bidirectional
// and we need to set the back reference.
if ($this->backRefFieldName && $this->association['type'] === ClassMetadata::ONE_TO_MANY) {
// Set back reference to owner
$this->typeClass->reflFields[$this->backRefFieldName]->setValue(
$element, $this->owner
);
}
}
/**
* Initializes the collection by loading its contents from the database
* if the collection is not yet initialized.
*
* @return void
*/
public function initialize()
{
if ($this->initialized || ! $this->association) {
return;
}
$this->doInitialize();
$this->initialized = true;
}
/**
* INTERNAL:
* Tells this collection to take a snapshot of its current state.
*
* @return void
*/
public function takeSnapshot()
{
$this->snapshot = $this->collection->toArray();
$this->isDirty = false;
}
/**
* INTERNAL:
* Returns the last snapshot of the elements in the collection.
*
* @return array The last snapshot of the elements.
*/
public function getSnapshot()
{
return $this->snapshot;
}
/**
* INTERNAL:
* getDeleteDiff
*
* @return array
*/
public function getDeleteDiff()
{
return array_udiff_assoc(
$this->snapshot,
$this->collection->toArray(),
function($a, $b) { return $a === $b ? 0 : 1; }
);
}
/**
* INTERNAL:
* getInsertDiff
*
* @return array
*/
public function getInsertDiff()
{
return array_udiff_assoc(
$this->collection->toArray(),
$this->snapshot,
function($a, $b) { return $a === $b ? 0 : 1; }
);
}
/**
* INTERNAL: Gets the association mapping of the collection.
*
* @return array
*/
public function getMapping()
{
return $this->association;
}
/**
* Marks this collection as changed/dirty.
*
* @return void
*/
private function changed()
{
if ($this->isDirty) {
return;
}
$this->isDirty = true;
if ($this->association !== null &&
$this->association['isOwningSide'] &&
$this->association['type'] === ClassMetadata::MANY_TO_MANY &&
$this->owner &&
$this->em->getClassMetadata(get_class($this->owner))->isChangeTrackingNotify()) {
$this->em->getUnitOfWork()->scheduleForDirtyCheck($this->owner);
}
}
/**
* Gets a boolean flag indicating whether this collection is dirty which means
* its state needs to be synchronized with the database.
*
* @return boolean TRUE if the collection is dirty, FALSE otherwise.
*/
public function isDirty()
{
return $this->isDirty;
}
/**
* Sets a boolean flag, indicating whether this collection is dirty.
*
* @param boolean $dirty Whether the collection should be marked dirty or not.
*
* @return void
*/
public function setDirty($dirty)
{
$this->isDirty = $dirty;
}
/**
* Sets the initialized flag of the collection, forcing it into that state.
*
* @param boolean $bool
*
* @return void
*/
public function setInitialized($bool)
{
$this->initialized = $bool;
}
/**
* {@inheritdoc}
*/
public function remove($key)
{
// TODO: If the keys are persistent as well (not yet implemented)
// and the collection is not initialized and orphanRemoval is
// not used we can issue a straight SQL delete/update on the
// association (table). Without initializing the collection.
$removed = parent::remove($key);
if ( ! $removed) {
return $removed;
}
$this->changed();
if ($this->association !== null &&
$this->association['type'] & ClassMetadata::TO_MANY &&
$this->owner &&
$this->association['orphanRemoval']) {
$this->em->getUnitOfWork()->scheduleOrphanRemoval($removed);
}
return $removed;
}
/**
* {@inheritdoc}
*/
public function removeElement($element)
{
if ( ! $this->initialized && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
if ($this->collection->contains($element)) {
return $this->collection->removeElement($element);
}
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
return $persister->removeElement($this, $element);
}
$removed = parent::removeElement($element);
if ( ! $removed) {
return $removed;
}
$this->changed();
if ($this->association !== null &&
$this->association['type'] & ClassMetadata::TO_MANY &&
$this->owner &&
$this->association['orphanRemoval']) {
$this->em->getUnitOfWork()->scheduleOrphanRemoval($element);
}
return $removed;
}
/**
* {@inheritdoc}
*/
public function containsKey($key)
{
if (! $this->initialized && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY
&& isset($this->association['indexBy'])) {
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
return $this->collection->containsKey($key) || $persister->containsKey($this, $key);
}
return parent::containsKey($key);
}
/**
* {@inheritdoc}
*/
public function contains($element)
{
if ( ! $this->initialized && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
return $this->collection->contains($element) || $persister->contains($this, $element);
}
return parent::contains($element);
}
/**
* {@inheritdoc}
*/
public function get($key)
{
if ( ! $this->initialized
&& $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY
&& isset($this->association['indexBy'])
) {
if (!$this->typeClass->isIdentifierComposite && $this->typeClass->isIdentifier($this->association['indexBy'])) {
return $this->em->find($this->typeClass->name, $key);
}
return $this->em->getUnitOfWork()->getCollectionPersister($this->association)->get($this, $key);
}
return parent::get($key);
}
/**
* {@inheritdoc}
*/
public function count()
{
if ( ! $this->initialized && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
return $persister->count($this) + ($this->isDirty ? $this->collection->count() : 0);
}
return parent::count();
}
/**
* {@inheritdoc}
*/
public function set($key, $value)
{
parent::set($key, $value);
$this->changed();
}
/**
* {@inheritdoc}
*/
public function add($value)
{
$this->collection->add($value);
$this->changed();
return true;
}
/* ArrayAccess implementation */
/**
* {@inheritdoc}
*/
public function offsetExists($offset)
{
return $this->containsKey($offset);
}
/**
* {@inheritdoc}
*/
public function offsetGet($offset)
{
return $this->get($offset);
}
/**
* {@inheritdoc}
*/
public function offsetSet($offset, $value)
{
if ( ! isset($offset)) {
return $this->add($value);
}
return $this->set($offset, $value);
}
/**
* {@inheritdoc}
*/
public function offsetUnset($offset)
{
return $this->remove($offset);
}
/**
* {@inheritdoc}
*/
public function isEmpty()
{
return $this->collection->isEmpty() && $this->count() === 0;
}
/**
* {@inheritdoc}
*/
public function clear()
{
if ($this->initialized && $this->isEmpty()) {
$this->collection->clear();
return;
}
$uow = $this->em->getUnitOfWork();
if ($this->association['type'] & ClassMetadata::TO_MANY &&
$this->association['orphanRemoval'] &&
$this->owner) {
// we need to initialize here, as orphan removal acts like implicit cascadeRemove,
// hence for event listeners we need the objects in memory.
$this->initialize();
foreach ($this->collection as $element) {
$uow->scheduleOrphanRemoval($element);
}
}
$this->collection->clear();
$this->initialized = true; // direct call, {@link initialize()} is too expensive
if ($this->association['isOwningSide'] && $this->owner) {
$this->changed();
$uow->scheduleCollectionDeletion($this);
$this->takeSnapshot();
}
}
/**
* Called by PHP when this collection is serialized. Ensures that only the
* elements are properly serialized.
*
* Internal note: Tried to implement Serializable first but that did not work well
* with circular references. This solution seems simpler and works well.
*
* @return array
*/
public function __sleep()
{
return array('collection', 'initialized');
}
/**
* Extracts a slice of $length elements starting at position $offset from the Collection.
*
* If $length is null it returns all elements from $offset to the end of the Collection.
* Keys have to be preserved by this method. Calling this method will only return the
* selected slice and NOT change the elements contained in the collection slice is called on.
*
* @param int $offset
* @param int|null $length
*
* @return array
*/
public function slice($offset, $length = null)
{
if ( ! $this->initialized && ! $this->isDirty && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
return $persister->slice($this, $offset, $length);
}
return parent::slice($offset, $length);
}
/**
* Cleans up internal state of cloned persistent collection.
*
* The following problems have to be prevented:
* 1. Added entities are added to old PC
* 2. New collection is not dirty, if reused on other entity nothing
* changes.
* 3. Snapshot leads to invalid diffs being generated.
* 4. Lazy loading grabs entities from old owner object.
* 5. New collection is connected to old owner and leads to duplicate keys.
*
* @return void
*/
public function __clone()
{
if (is_object($this->collection)) {
$this->collection = clone $this->collection;
}
$this->initialize();
$this->owner = null;
$this->snapshot = array();
$this->changed();
}
/**
* Selects all elements from a selectable that match the expression and
* return a new collection containing these elements.
*
* @param \Doctrine\Common\Collections\Criteria $criteria
*
* @return Collection
*
* @throws \RuntimeException
*/
public function matching(Criteria $criteria)
{
if ($this->isDirty) {
$this->initialize();
}
if ($this->initialized) {
return $this->collection->matching($criteria);
}
if ($this->association['type'] === ClassMetadata::MANY_TO_MANY) {
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
return new ArrayCollection($persister->loadCriteria($this, $criteria));
}
$builder = Criteria::expr();
$ownerExpression = $builder->eq($this->backRefFieldName, $this->owner);
$expression = $criteria->getWhereExpression();
$expression = $expression ? $builder->andX($expression, $ownerExpression) : $ownerExpression;
$criteria = clone $criteria;
$criteria->where($expression);
$persister = $this->em->getUnitOfWork()->getEntityPersister($this->association['targetEntity']);
return ($this->association['fetch'] === ClassMetadataInfo::FETCH_EXTRA_LAZY)
? new LazyCriteriaCollection($persister, $criteria)
: new ArrayCollection($persister->loadCriteria($criteria));
}
/**
* Retrieves the wrapped Collection instance.
*
* @return \Doctrine\Common\Collections\Collection
*/
public function unwrap()
{
return $this->collection;
}
/**
* {@inheritdoc}
*/
protected function doInitialize()
{
// Has NEW objects added through add(). Remember them.
$newlyAddedDirtyObjects = array();
if ($this->isDirty) {
$newlyAddedDirtyObjects = $this->collection->toArray();
}
$this->collection->clear();
$this->em->getUnitOfWork()->loadCollection($this);
$this->takeSnapshot();
if ($newlyAddedDirtyObjects) {
$this->restoreNewObjectsInDirtyCollection($newlyAddedDirtyObjects);
}
}
/**
* @param object[] $newObjects
*
* @return void
*
* Note: the only reason why this entire looping/complexity is performed via `spl_object_hash`
* is because we want to prevent using `array_udiff()`, which is likely to cause very
* high overhead (complexity of O(n^2)). `array_diff_key()` performs the operation in
* core, which is faster than using a callback for comparisons
*/
private function restoreNewObjectsInDirtyCollection(array $newObjects)
{
$loadedObjects = $this->collection->toArray();
$newObjectsByOid = \array_combine(\array_map('spl_object_hash', $newObjects), $newObjects);
$loadedObjectsByOid = \array_combine(\array_map('spl_object_hash', $loadedObjects), $loadedObjects);
$newObjectsThatWereNotLoaded = \array_diff_key($newObjectsByOid, $loadedObjectsByOid);
if ($newObjectsThatWereNotLoaded) {
// Reattach NEW objects added through add(), if any.
\array_walk($newObjectsThatWereNotLoaded, [$this->collection, 'add']);
$this->isDirty = true;
}
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Persisters/ 0000775 0000000 0000000 00000000000 13215356457 0020624 5 ustar 00root root 0000000 0000000 doctrine2-2.5.14/lib/Doctrine/ORM/Persisters/Collection/ 0000775 0000000 0000000 00000000000 13215356457 0022717 5 ustar 00root root 0000000 0000000 doctrine2-2.5.14/lib/Doctrine/ORM/Persisters/Collection/AbstractCollectionPersister.php 0000664 0000000 0000000 00000005604 13215356457 0031115 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Persisters\Collection;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\UnitOfWork;
/**
* Base class for all collection persisters.
*
* @since 2.0
* @author Roman Borschel
*/
abstract class AbstractCollectionPersister implements CollectionPersister
{
/**
* @var EntityManagerInterface
*/
protected $em;
/**
* @var \Doctrine\DBAL\Connection
*/
protected $conn;
/**
* @var UnitOfWork
*/
protected $uow;
/**
* The database platform.
*
* @var \Doctrine\DBAL\Platforms\AbstractPlatform
*/
protected $platform;
/**
* The quote strategy.
*
* @var \Doctrine\ORM\Mapping\QuoteStrategy
*/
protected $quoteStrategy;
/**
* Initializes a new instance of a class derived from AbstractCollectionPersister.
*
* @param EntityManagerInterface $em
*/
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
$this->uow = $em->getUnitOfWork();
$this->conn = $em->getConnection();
$this->platform = $this->conn->getDatabasePlatform();
$this->quoteStrategy = $em->getConfiguration()->getQuoteStrategy();
}
/**
* Check if entity is in a valid state for operations.
*
* @param object $entity
*
* @return bool
*/
protected function isValidEntityState($entity)
{
$entityState = $this->uow->getEntityState($entity, UnitOfWork::STATE_NEW);
if ($entityState === UnitOfWork::STATE_NEW) {
return false;
}
// If Entity is scheduled for inclusion, it is not in this collection.
// We can assure that because it would have return true before on array check
return ! ($entityState === UnitOfWork::STATE_MANAGED && $this->uow->isScheduledForInsert($entity));
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Persisters/Collection/CollectionPersister.php 0000664 0000000 0000000 00000007526 13215356457 0027436 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Persisters\Collection;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\PersistentCollection;
/**
* Collection persister interface
* Define the behavior that should be implemented by all collection persisters.
*
* @author Fabio B. Silva
* @since 2.5
*/
interface CollectionPersister
{
/**
* Deletes the persistent state represented by the given collection.
*
* @param \Doctrine\ORM\PersistentCollection $collection
*
* @return void
*/
public function delete(PersistentCollection $collection);
/**
* Updates the given collection, synchronizing its state with the database
* by inserting, updating and deleting individual elements.
*
* @param \Doctrine\ORM\PersistentCollection $collection
*
* @return void
*/
public function update(PersistentCollection $collection);
/**
* Counts the size of this persistent collection.
*
* @param \Doctrine\ORM\PersistentCollection $collection
*
* @return integer
*/
public function count(PersistentCollection $collection);
/**
* Slices elements.
*
* @param \Doctrine\ORM\PersistentCollection $collection
* @param integer $offset
* @param integer $length
*
* @return array
*/
public function slice(PersistentCollection $collection, $offset, $length = null);
/**
* Checks for existence of an element.
*
* @param \Doctrine\ORM\PersistentCollection $collection
* @param object $element
*
* @return boolean
*/
public function contains(PersistentCollection $collection, $element);
/**
* Checks for existence of a key.
*
* @param \Doctrine\ORM\PersistentCollection $collection
* @param mixed $key
*
* @return boolean
*/
public function containsKey(PersistentCollection $collection, $key);
/**
* Removes an element.
*
* @param \Doctrine\ORM\PersistentCollection $collection
* @param object $element
*
* @return mixed
*/
public function removeElement(PersistentCollection $collection, $element);
/**
* Gets an element by key.
*
* @param \Doctrine\ORM\PersistentCollection $collection
* @param mixed $index
*
* @return mixed
*/
public function get(PersistentCollection $collection, $index);
/**
* Loads association entities matching the given Criteria object.
*
* @param \Doctrine\ORM\PersistentCollection $collection
* @param \Doctrine\Common\Collections\Criteria $criteria
*
* @return array
*/
public function loadCriteria(PersistentCollection $collection, Criteria $criteria);
}
doctrine2-2.5.14/lib/Doctrine/ORM/Persisters/Collection/ManyToManyPersister.php 0000664 0000000 0000000 00000070567 13215356457 0027404 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Persisters\Collection;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Persisters\SqlExpressionVisitor;
use Doctrine\ORM\Persisters\SqlValueVisitor;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Query;
use Doctrine\ORM\Utility\PersisterHelper;
/**
* Persister for many-to-many collections.
*
* @author Roman Borschel
* @author Guilherme Blanco
* @author Alexander
* @since 2.0
*/
class ManyToManyPersister extends AbstractCollectionPersister
{
/**
* {@inheritdoc}
*/
public function delete(PersistentCollection $collection)
{
$mapping = $collection->getMapping();
if ( ! $mapping['isOwningSide']) {
return; // ignore inverse side
}
$this->conn->executeUpdate($this->getDeleteSQL($collection), $this->getDeleteSQLParameters($collection));
}
/**
* {@inheritdoc}
*/
public function update(PersistentCollection $collection)
{
$mapping = $collection->getMapping();
if ( ! $mapping['isOwningSide']) {
return; // ignore inverse side
}
list($deleteSql, $deleteTypes) = $this->getDeleteRowSQL($collection);
list($insertSql, $insertTypes) = $this->getInsertRowSQL($collection);
foreach ($collection->getDeleteDiff() as $element) {
$this->conn->executeUpdate(
$deleteSql,
$this->getDeleteRowSQLParameters($collection, $element),
$deleteTypes
);
}
foreach ($collection->getInsertDiff() as $element) {
$this->conn->executeUpdate(
$insertSql,
$this->getInsertRowSQLParameters($collection, $element),
$insertTypes
);
}
}
/**
* {@inheritdoc}
*/
public function get(PersistentCollection $collection, $index)
{
$mapping = $collection->getMapping();
if ( ! isset($mapping['indexBy'])) {
throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections.");
}
$persister = $this->uow->getEntityPersister($mapping['targetEntity']);
$mappedKey = $mapping['isOwningSide']
? $mapping['inversedBy']
: $mapping['mappedBy'];
return $persister->load(array($mappedKey => $collection->getOwner(), $mapping['indexBy'] => $index), null, $mapping, array(), 0, 1);
}
/**
* {@inheritdoc}
*/
public function count(PersistentCollection $collection)
{
$conditions = array();
$params = array();
$types = array();
$mapping = $collection->getMapping();
$id = $this->uow->getEntityIdentifier($collection->getOwner());
$sourceClass = $this->em->getClassMetadata($mapping['sourceEntity']);
$targetClass = $this->em->getClassMetadata($mapping['targetEntity']);
$association = ( ! $mapping['isOwningSide'])
? $targetClass->associationMappings[$mapping['mappedBy']]
: $mapping;
$joinTableName = $this->quoteStrategy->getJoinTableName($association, $sourceClass, $this->platform);
$joinColumns = ( ! $mapping['isOwningSide'])
? $association['joinTable']['inverseJoinColumns']
: $association['joinTable']['joinColumns'];
foreach ($joinColumns as $joinColumn) {
$columnName = $this->quoteStrategy->getJoinColumnName($joinColumn, $sourceClass, $this->platform);
$referencedName = $joinColumn['referencedColumnName'];
$conditions[] = 't.' . $columnName . ' = ?';
$params[] = $id[$sourceClass->getFieldForColumn($referencedName)];
$types[] = PersisterHelper::getTypeOfColumn($referencedName, $sourceClass, $this->em);
}
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($mapping);
if ($filterSql) {
$conditions[] = $filterSql;
}
// If there is a provided criteria, make part of conditions
// @todo Fix this. Current SQL returns something like:
//
/*if ($criteria && ($expression = $criteria->getWhereExpression()) !== null) {
// A join is needed on the target entity
$targetTableName = $this->quoteStrategy->getTableName($targetClass, $this->platform);
$targetJoinSql = ' JOIN ' . $targetTableName . ' te'
. ' ON' . implode(' AND ', $this->getOnConditionSQL($association));
// And criteria conditions needs to be added
$persister = $this->uow->getEntityPersister($targetClass->name);
$visitor = new SqlExpressionVisitor($persister, $targetClass);
$conditions[] = $visitor->dispatch($expression);
$joinTargetEntitySQL = $targetJoinSql . $joinTargetEntitySQL;
}*/
$sql = 'SELECT COUNT(*)'
. ' FROM ' . $joinTableName . ' t'
. $joinTargetEntitySQL
. ' WHERE ' . implode(' AND ', $conditions);
return $this->conn->fetchColumn($sql, $params, 0, $types);
}
/**
* {@inheritDoc}
*/
public function slice(PersistentCollection $collection, $offset, $length = null)
{
$mapping = $collection->getMapping();
$persister = $this->uow->getEntityPersister($mapping['targetEntity']);
return $persister->getManyToManyCollection($mapping, $collection->getOwner(), $offset, $length);
}
/**
* {@inheritdoc}
*/
public function containsKey(PersistentCollection $collection, $key)
{
$mapping = $collection->getMapping();
if ( ! isset($mapping['indexBy'])) {
throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections.");
}
list($quotedJoinTable, $whereClauses, $params, $types) = $this->getJoinTableRestrictionsWithKey($collection, $key, true);
$sql = 'SELECT 1 FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses);
return (bool) $this->conn->fetchColumn($sql, $params, 0, $types);
}
/**
* {@inheritDoc}
*/
public function contains(PersistentCollection $collection, $element)
{
if ( ! $this->isValidEntityState($element)) {
return false;
}
list($quotedJoinTable, $whereClauses, $params, $types) = $this->getJoinTableRestrictions($collection, $element, true);
$sql = 'SELECT 1 FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses);
return (bool) $this->conn->fetchColumn($sql, $params, 0, $types);
}
/**
* {@inheritDoc}
*/
public function removeElement(PersistentCollection $collection, $element)
{
if ( ! $this->isValidEntityState($element)) {
return false;
}
list($quotedJoinTable, $whereClauses, $params, $types) = $this->getJoinTableRestrictions($collection, $element, false);
$sql = 'DELETE FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses);
return (bool) $this->conn->executeUpdate($sql, $params, $types);
}
/**
* {@inheritDoc}
*/
public function loadCriteria(PersistentCollection $collection, Criteria $criteria)
{
$mapping = $collection->getMapping();
$owner = $collection->getOwner();
$ownerMetadata = $this->em->getClassMetadata(get_class($owner));
$whereClauses = $params = array();
foreach ($mapping['relationToSourceKeyColumns'] as $key => $value) {
$whereClauses[] = sprintf('t.%s = ?', $key);
$params[] = $ownerMetadata->getFieldValue($owner, $value);
}
$parameters = $this->expandCriteriaParameters($criteria);
foreach ($parameters as $parameter) {
list($name, $value, $operator) = $parameter;
$whereClauses[] = sprintf('te.%s %s ?', $name, $operator);
$params[] = $value;
}
$mapping = $collection->getMapping();
$targetClass = $this->em->getClassMetadata($mapping['targetEntity']);
$tableName = $this->quoteStrategy->getTableName($targetClass, $this->platform);
$joinTable = $this->quoteStrategy->getJoinTableName($mapping, $ownerMetadata, $this->platform);
$onConditions = $this->getOnConditionSQL($mapping);
$rsm = new Query\ResultSetMappingBuilder($this->em);
$rsm->addRootEntityFromClassMetadata($mapping['targetEntity'], 'te');
$sql = 'SELECT ' . $rsm->generateSelectClause()
. ' FROM ' . $tableName . ' te'
. ' JOIN ' . $joinTable . ' t ON'
. implode(' AND ', $onConditions)
. ' WHERE ' . implode(' AND ', $whereClauses);
$stmt = $this->conn->executeQuery($sql, $params);
return $this
->em
->newHydrator(Query::HYDRATE_OBJECT)
->hydrateAll($stmt, $rsm);
}
/**
* Generates the filter SQL for a given mapping.
*
* This method is not used for actually grabbing the related entities
* but when the extra-lazy collection methods are called on a filtered
* association. This is why besides the many to many table we also
* have to join in the actual entities table leading to additional
* JOIN.
*
* @param array $mapping Array containing mapping information.
*
* @return string[] ordered tuple:
* - JOIN condition to add to the SQL
* - WHERE condition to add to the SQL
*/
public function getFilterSql($mapping)
{
$targetClass = $this->em->getClassMetadata($mapping['targetEntity']);
$rootClass = $this->em->getClassMetadata($targetClass->rootEntityName);
$filterSql = $this->generateFilterConditionSQL($rootClass, 'te');
if ('' === $filterSql) {
return array('', '');
}
// A join is needed if there is filtering on the target entity
$tableName = $this->quoteStrategy->getTableName($rootClass, $this->platform);
$joinSql = ' JOIN ' . $tableName . ' te'
. ' ON' . implode(' AND ', $this->getOnConditionSQL($mapping));
return array($joinSql, $filterSql);
}
/**
* Generates the filter SQL for a given entity and table alias.
*
* @param ClassMetadata $targetEntity Metadata of the target entity.
* @param string $targetTableAlias The table alias of the joined/selected table.
*
* @return string The SQL query part to add to a query.
*/
protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias)
{
$filterClauses = array();
foreach ($this->em->getFilters()->getEnabledFilters() as $filter) {
if ($filterExpr = $filter->addFilterConstraint($targetEntity, $targetTableAlias)) {
$filterClauses[] = '(' . $filterExpr . ')';
}
}
return $filterClauses
? '(' . implode(' AND ', $filterClauses) . ')'
: '';
}
/**
* Generate ON condition
*
* @param array $mapping
*
* @return array
*/
protected function getOnConditionSQL($mapping)
{
$targetClass = $this->em->getClassMetadata($mapping['targetEntity']);
$association = ( ! $mapping['isOwningSide'])
? $targetClass->associationMappings[$mapping['mappedBy']]
: $mapping;
$joinColumns = $mapping['isOwningSide']
? $association['joinTable']['inverseJoinColumns']
: $association['joinTable']['joinColumns'];
$conditions = array();
foreach ($joinColumns as $joinColumn) {
$joinColumnName = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform);
$refColumnName = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $targetClass, $this->platform);
$conditions[] = ' t.' . $joinColumnName . ' = ' . 'te.' . $refColumnName;
}
return $conditions;
}
/**
* {@inheritdoc}
*
* @override
*/
protected function getDeleteSQL(PersistentCollection $collection)
{
$columns = array();
$mapping = $collection->getMapping();
$class = $this->em->getClassMetadata(get_class($collection->getOwner()));
$joinTable = $this->quoteStrategy->getJoinTableName($mapping, $class, $this->platform);
foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) {
$columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform);
}
return 'DELETE FROM ' . $joinTable
. ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?';
}
/**
* {@inheritdoc}
*
* Internal note: Order of the parameters must be the same as the order of the columns in getDeleteSql.
* @override
*/
protected function getDeleteSQLParameters(PersistentCollection $collection)
{
$mapping = $collection->getMapping();
$identifier = $this->uow->getEntityIdentifier($collection->getOwner());
// Optimization for single column identifier
if (count($mapping['relationToSourceKeyColumns']) === 1) {
return array(reset($identifier));
}
// Composite identifier
$sourceClass = $this->em->getClassMetadata($mapping['sourceEntity']);
$params = array();
foreach ($mapping['relationToSourceKeyColumns'] as $columnName => $refColumnName) {
$params[] = isset($sourceClass->fieldNames[$refColumnName])
? $identifier[$sourceClass->fieldNames[$refColumnName]]
: $identifier[$sourceClass->getFieldForColumn($columnName)];
}
return $params;
}
/**
* Gets the SQL statement used for deleting a row from the collection.
*
* @param \Doctrine\ORM\PersistentCollection $collection
*
* @return string[]|string[][] ordered tuple containing the SQL to be executed and an array
* of types for bound parameters
*/
protected function getDeleteRowSQL(PersistentCollection $collection)
{
$mapping = $collection->getMapping();
$class = $this->em->getClassMetadata($mapping['sourceEntity']);
$targetClass = $this->em->getClassMetadata($mapping['targetEntity']);
$columns = array();
$types = array();
foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) {
$columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform);
$types[] = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $class, $this->em);
}
foreach ($mapping['joinTable']['inverseJoinColumns'] as $joinColumn) {
$columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform);
$types[] = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $targetClass, $this->em);
}
return array(
'DELETE FROM ' . $this->quoteStrategy->getJoinTableName($mapping, $class, $this->platform)
. ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?',
$types,
);
}
/**
* Gets the SQL parameters for the corresponding SQL statement to delete the given
* element from the given collection.
*
* Internal note: Order of the parameters must be the same as the order of the columns in getDeleteRowSql.
*
* @param \Doctrine\ORM\PersistentCollection $collection
* @param mixed $element
*
* @return array
*/
protected function getDeleteRowSQLParameters(PersistentCollection $collection, $element)
{
return $this->collectJoinTableColumnParameters($collection, $element);
}
/**
* Gets the SQL statement used for inserting a row in the collection.
*
* @param \Doctrine\ORM\PersistentCollection $collection
*
* @return string[]|string[][] ordered tuple containing the SQL to be executed and an array
* of types for bound parameters
*/
protected function getInsertRowSQL(PersistentCollection $collection)
{
$columns = array();
$types = array();
$mapping = $collection->getMapping();
$class = $this->em->getClassMetadata($mapping['sourceEntity']);
$targetClass = $this->em->getClassMetadata($mapping['targetEntity']);
foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) {
$columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform);
$types[] = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $class, $this->em);
}
foreach ($mapping['joinTable']['inverseJoinColumns'] as $joinColumn) {
$columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform);
$types[] = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $targetClass, $this->em);
}
return array(
'INSERT INTO ' . $this->quoteStrategy->getJoinTableName($mapping, $class, $this->platform)
. ' (' . implode(', ', $columns) . ')'
. ' VALUES'
. ' (' . implode(', ', array_fill(0, count($columns), '?')) . ')',
$types,
);
}
/**
* Gets the SQL parameters for the corresponding SQL statement to insert the given
* element of the given collection into the database.
*
* Internal note: Order of the parameters must be the same as the order of the columns in getInsertRowSql.
*
* @param \Doctrine\ORM\PersistentCollection $collection
* @param mixed $element
*
* @return array
*/
protected function getInsertRowSQLParameters(PersistentCollection $collection, $element)
{
return $this->collectJoinTableColumnParameters($collection, $element);
}
/**
* Collects the parameters for inserting/deleting on the join table in the order
* of the join table columns as specified in ManyToManyMapping#joinTableColumns.
*
* @param \Doctrine\ORM\PersistentCollection $collection
* @param object $element
*
* @return array
*/
private function collectJoinTableColumnParameters(PersistentCollection $collection, $element)
{
$params = array();
$mapping = $collection->getMapping();
$isComposite = count($mapping['joinTableColumns']) > 2;
$identifier1 = $this->uow->getEntityIdentifier($collection->getOwner());
$identifier2 = $this->uow->getEntityIdentifier($element);
if ($isComposite) {
$class1 = $this->em->getClassMetadata(get_class($collection->getOwner()));
$class2 = $collection->getTypeClass();
}
foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
$isRelationToSource = isset($mapping['relationToSourceKeyColumns'][$joinTableColumn]);
if ( ! $isComposite) {
$params[] = $isRelationToSource ? array_pop($identifier1) : array_pop($identifier2);
continue;
}
if ($isRelationToSource) {
$params[] = $identifier1[$class1->getFieldForColumn($mapping['relationToSourceKeyColumns'][$joinTableColumn])];
continue;
}
$params[] = $identifier2[$class2->getFieldForColumn($mapping['relationToTargetKeyColumns'][$joinTableColumn])];
}
return $params;
}
/**
* @param \Doctrine\ORM\PersistentCollection $collection
* @param string $key
* @param boolean $addFilters Whether the filter SQL should be included or not.
*
* @return array ordered vector:
* - quoted join table name
* - where clauses to be added for filtering
* - parameters to be bound for filtering
* - types of the parameters to be bound for filtering
*/
private function getJoinTableRestrictionsWithKey(PersistentCollection $collection, $key, $addFilters)
{
$filterMapping = $collection->getMapping();
$mapping = $filterMapping;
$indexBy = $mapping['indexBy'];
$id = $this->uow->getEntityIdentifier($collection->getOwner());
$sourceClass = $this->em->getClassMetadata($mapping['sourceEntity']);
$targetClass = $this->em->getClassMetadata($mapping['targetEntity']);
if (! $mapping['isOwningSide']) {
$associationSourceClass = $this->em->getClassMetadata($mapping['targetEntity']);
$mapping = $associationSourceClass->associationMappings[$mapping['mappedBy']];
$joinColumns = $mapping['joinTable']['joinColumns'];
$sourceRelationMode = 'relationToTargetKeyColumns';
$targetRelationMode = 'relationToSourceKeyColumns';
} else {
$associationSourceClass = $this->em->getClassMetadata($mapping['sourceEntity']);
$joinColumns = $mapping['joinTable']['inverseJoinColumns'];
$sourceRelationMode = 'relationToSourceKeyColumns';
$targetRelationMode = 'relationToTargetKeyColumns';
}
$quotedJoinTable = $this->quoteStrategy->getJoinTableName($mapping, $associationSourceClass, $this->platform). ' t';
$whereClauses = array();
$params = array();
$types = array();
$joinNeeded = ! in_array($indexBy, $targetClass->identifier);
if ($joinNeeded) { // extra join needed if indexBy is not a @id
$joinConditions = array();
foreach ($joinColumns as $joinTableColumn) {
$joinConditions[] = 't.' . $joinTableColumn['name'] . ' = tr.' . $joinTableColumn['referencedColumnName'];
}
$tableName = $this->quoteStrategy->getTableName($targetClass, $this->platform);
$quotedJoinTable .= ' JOIN ' . $tableName . ' tr ON ' . implode(' AND ', $joinConditions);
$columnName = $targetClass->getColumnName($indexBy);
$whereClauses[] = 'tr.' . $columnName . ' = ?';
$params[] = $key;
$types[] = PersisterHelper::getTypeOfColumn($columnName, $targetClass, $this->em);
}
foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
if (isset($mapping[$sourceRelationMode][$joinTableColumn])) {
$column = $mapping[$sourceRelationMode][$joinTableColumn];
$whereClauses[] = 't.' . $joinTableColumn . ' = ?';
$params[] = $sourceClass->containsForeignIdentifier
? $id[$sourceClass->getFieldForColumn($column)]
: $id[$sourceClass->fieldNames[$column]];
$types[] = PersisterHelper::getTypeOfColumn($column, $sourceClass, $this->em);
} elseif ( ! $joinNeeded) {
$column = $mapping[$targetRelationMode][$joinTableColumn];
$whereClauses[] = 't.' . $joinTableColumn . ' = ?';
$params[] = $key;
$types[] = PersisterHelper::getTypeOfColumn($column, $targetClass, $this->em);
}
}
if ($addFilters) {
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($filterMapping);
if ($filterSql) {
$quotedJoinTable .= ' ' . $joinTargetEntitySQL;
$whereClauses[] = $filterSql;
}
}
return array($quotedJoinTable, $whereClauses, $params, $types);
}
/**
* @param \Doctrine\ORM\PersistentCollection $collection
* @param object $element
* @param boolean $addFilters Whether the filter SQL should be included or not.
*
* @return array ordered vector:
* - quoted join table name
* - where clauses to be added for filtering
* - parameters to be bound for filtering
* - types of the parameters to be bound for filtering
*/
private function getJoinTableRestrictions(PersistentCollection $collection, $element, $addFilters)
{
$filterMapping = $collection->getMapping();
$mapping = $filterMapping;
if ( ! $mapping['isOwningSide']) {
$sourceClass = $this->em->getClassMetadata($mapping['targetEntity']);
$targetClass = $this->em->getClassMetadata($mapping['sourceEntity']);
$sourceId = $this->uow->getEntityIdentifier($element);
$targetId = $this->uow->getEntityIdentifier($collection->getOwner());
$mapping = $sourceClass->associationMappings[$mapping['mappedBy']];
} else {
$sourceClass = $this->em->getClassMetadata($mapping['sourceEntity']);
$targetClass = $this->em->getClassMetadata($mapping['targetEntity']);
$sourceId = $this->uow->getEntityIdentifier($collection->getOwner());
$targetId = $this->uow->getEntityIdentifier($element);
}
$quotedJoinTable = $this->quoteStrategy->getJoinTableName($mapping, $sourceClass, $this->platform);
$whereClauses = array();
$params = array();
$types = array();
foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
$whereClauses[] = ($addFilters ? 't.' : '') . $joinTableColumn . ' = ?';
if (isset($mapping['relationToTargetKeyColumns'][$joinTableColumn])) {
$targetColumn = $mapping['relationToTargetKeyColumns'][$joinTableColumn];
$params[] = $targetId[$targetClass->getFieldForColumn($targetColumn)];
$types[] = PersisterHelper::getTypeOfColumn($targetColumn, $targetClass, $this->em);
continue;
}
// relationToSourceKeyColumns
$targetColumn = $mapping['relationToSourceKeyColumns'][$joinTableColumn];
$params[] = $sourceId[$sourceClass->getFieldForColumn($targetColumn)];
$types[] = PersisterHelper::getTypeOfColumn($targetColumn, $sourceClass, $this->em);
}
if ($addFilters) {
$quotedJoinTable .= ' t';
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($filterMapping);
if ($filterSql) {
$quotedJoinTable .= ' ' . $joinTargetEntitySQL;
$whereClauses[] = $filterSql;
}
}
return array($quotedJoinTable, $whereClauses, $params, $types);
}
/**
* Expands Criteria Parameters by walking the expressions and grabbing all
* parameters and types from it.
*
* @param \Doctrine\Common\Collections\Criteria $criteria
*
* @return array
*/
private function expandCriteriaParameters(Criteria $criteria)
{
$expression = $criteria->getWhereExpression();
if ($expression === null) {
return array();
}
$valueVisitor = new SqlValueVisitor();
$valueVisitor->dispatch($expression);
list($values, $types) = $valueVisitor->getParamsAndTypes();
return $types;
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Persisters/Collection/OneToManyPersister.php 0000664 0000000 0000000 00000013752 13215356457 0027212 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Persisters\Collection;
use Doctrine\Common\Collections\Criteria;
use Doctrine\Common\Proxy\Proxy;
use Doctrine\ORM\PersistentCollection;
/**
* Persister for one-to-many collections.
*
* @author Roman Borschel
* @author Guilherme Blanco
* @author Alexander
* @since 2.0
*/
class OneToManyPersister extends AbstractCollectionPersister
{
/**
* {@inheritdoc}
*/
public function delete(PersistentCollection $collection)
{
// This can never happen. One to many can only be inverse side.
// For owning side one to many, it is required to have a join table,
// then classifying it as a ManyToManyPersister.
return;
}
/**
* {@inheritdoc}
*/
public function update(PersistentCollection $collection)
{
// This can never happen. One to many can only be inverse side.
// For owning side one to many, it is required to have a join table,
// then classifying it as a ManyToManyPersister.
return;
}
/**
* {@inheritdoc}
*/
public function get(PersistentCollection $collection, $index)
{
$mapping = $collection->getMapping();
if ( ! isset($mapping['indexBy'])) {
throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections.");
}
$persister = $this->uow->getEntityPersister($mapping['targetEntity']);
return $persister->load(
array(
$mapping['mappedBy'] => $collection->getOwner(),
$mapping['indexBy'] => $index
),
null,
$mapping,
array(),
null,
1
);
}
/**
* {@inheritdoc}
*/
public function count(PersistentCollection $collection)
{
$mapping = $collection->getMapping();
$persister = $this->uow->getEntityPersister($mapping['targetEntity']);
// only works with single id identifier entities. Will throw an
// exception in Entity Persisters if that is not the case for the
// 'mappedBy' field.
$criteria = new Criteria(Criteria::expr()->eq($mapping['mappedBy'], $collection->getOwner()));
return $persister->count($criteria);
}
/**
* {@inheritdoc}
*/
public function slice(PersistentCollection $collection, $offset, $length = null)
{
$mapping = $collection->getMapping();
$persister = $this->uow->getEntityPersister($mapping['targetEntity']);
return $persister->getOneToManyCollection($mapping, $collection->getOwner(), $offset, $length);
}
/**
* {@inheritdoc}
*/
public function containsKey(PersistentCollection $collection, $key)
{
$mapping = $collection->getMapping();
if ( ! isset($mapping['indexBy'])) {
throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections.");
}
$persister = $this->uow->getEntityPersister($mapping['targetEntity']);
// only works with single id identifier entities. Will throw an
// exception in Entity Persisters if that is not the case for the
// 'mappedBy' field.
$criteria = new Criteria();
$criteria->andWhere(Criteria::expr()->eq($mapping['mappedBy'], $collection->getOwner()));
$criteria->andWhere(Criteria::expr()->eq($mapping['indexBy'], $key));
return (bool) $persister->count($criteria);
}
/**
* {@inheritdoc}
*/
public function contains(PersistentCollection $collection, $element)
{
if ( ! $this->isValidEntityState($element)) {
return false;
}
$mapping = $collection->getMapping();
$persister = $this->uow->getEntityPersister($mapping['targetEntity']);
// only works with single id identifier entities. Will throw an
// exception in Entity Persisters if that is not the case for the
// 'mappedBy' field.
$criteria = new Criteria(Criteria::expr()->eq($mapping['mappedBy'], $collection->getOwner()));
return $persister->exists($element, $criteria);
}
/**
* {@inheritdoc}
*/
public function removeElement(PersistentCollection $collection, $element)
{
$mapping = $collection->getMapping();
if ( ! $mapping['orphanRemoval']) {
// no-op: this is not the owning side, therefore no operations should be applied
return false;
}
if ( ! $this->isValidEntityState($element)) {
return false;
}
return $this
->uow
->getEntityPersister($mapping['targetEntity'])
->delete($element);
}
/**
* {@inheritdoc}
*/
public function loadCriteria(PersistentCollection $collection, Criteria $criteria)
{
throw new \BadMethodCallException("Filtering a collection by Criteria is not supported by this CollectionPersister.");
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Persisters/Entity/ 0000775 0000000 0000000 00000000000 13215356457 0022100 5 ustar 00root root 0000000 0000000 doctrine2-2.5.14/lib/Doctrine/ORM/Persisters/Entity/AbstractEntityInheritancePersister.php 0000664 0000000 0000000 00000006777 13215356457 0031645 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Persisters\Entity;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\DBAL\Types\Type;
/**
* Base class for entity persisters that implement a certain inheritance mapping strategy.
* All these persisters are assumed to use a discriminator column to discriminate entity
* types in the hierarchy.
*
* @author Roman Borschel
* @author Benjamin Eberlei
* @since 2.0
*/
abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
{
/**
* {@inheritdoc}
*/
protected function prepareInsertData($entity)
{
$data = parent::prepareInsertData($entity);
// Populate the discriminator column
$discColumn = $this->class->discriminatorColumn;
$this->columnTypes[$discColumn['name']] = $discColumn['type'];
$data[$this->getDiscriminatorColumnTableName()][$discColumn['name']] = $this->class->discriminatorValue;
return $data;
}
/**
* Gets the name of the table that contains the discriminator column.
*
* @return string The table name.
*/
abstract protected function getDiscriminatorColumnTableName();
/**
* {@inheritdoc}
*/
protected function getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r')
{
$tableAlias = $alias == 'r' ? '' : $alias;
$columnName = $class->columnNames[$field];
$columnAlias = $this->getSQLColumnAlias($columnName);
$sql = $this->getSQLTableAlias($class->name, $tableAlias) . '.'
. $this->quoteStrategy->getColumnName($field, $class, $this->platform);
$this->currentPersisterContext->rsm->addFieldResult($alias, $columnAlias, $field, $class->name);
if (isset($class->fieldMappings[$field]['requireSQLConversion'])) {
$type = Type::getType($class->getTypeOfField($field));
$sql = $type->convertToPHPValueSQL($sql, $this->platform);
}
return $sql . ' AS ' . $columnAlias;
}
/**
* @param string $tableAlias
* @param string $joinColumnName
* @param string $className
* @param string $type
*
* @return string
*/
protected function getSelectJoinColumnSQL($tableAlias, $joinColumnName, $className, $type)
{
$columnAlias = $this->getSQLColumnAlias($joinColumnName);
$this->currentPersisterContext->rsm->addMetaResult('r', $columnAlias, $joinColumnName, false, $type);
return $tableAlias . '.' . $joinColumnName . ' AS ' . $columnAlias;
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php 0000664 0000000 0000000 00000222042 13215356457 0026732 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Persisters\Entity;
use Doctrine\Common\Collections\Criteria;
use Doctrine\Common\Collections\Expr\Comparison;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\LockMode;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\MappingException;
use Doctrine\ORM\OptimisticLockException;
use Doctrine\ORM\ORMException;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Persisters\SqlExpressionVisitor;
use Doctrine\ORM\Persisters\SqlValueVisitor;
use Doctrine\ORM\Query;
use Doctrine\ORM\UnitOfWork;
use Doctrine\ORM\Utility\IdentifierFlattener;
use Doctrine\ORM\Utility\PersisterHelper;
/**
* A BasicEntityPersister maps an entity to a single table in a relational database.
*
* A persister is always responsible for a single entity type.
*
* EntityPersisters are used during a UnitOfWork to apply any changes to the persistent
* state of entities onto a relational database when the UnitOfWork is committed,
* as well as for basic querying of entities and their associations (not DQL).
*
* The persisting operations that are invoked during a commit of a UnitOfWork to
* persist the persistent entity state are:
*
* - {@link addInsert} : To schedule an entity for insertion.
* - {@link executeInserts} : To execute all scheduled insertions.
* - {@link update} : To update the persistent state of an entity.
* - {@link delete} : To delete the persistent state of an entity.
*
* As can be seen from the above list, insertions are batched and executed all at once
* for increased efficiency.
*
* The querying operations invoked during a UnitOfWork, either through direct find
* requests or lazy-loading, are the following:
*
* - {@link load} : Loads (the state of) a single, managed entity.
* - {@link loadAll} : Loads multiple, managed entities.
* - {@link loadOneToOneEntity} : Loads a one/many-to-one entity association (lazy-loading).
* - {@link loadOneToManyCollection} : Loads a one-to-many entity association (lazy-loading).
* - {@link loadManyToManyCollection} : Loads a many-to-many entity association (lazy-loading).
*
* The BasicEntityPersister implementation provides the default behavior for
* persisting and querying entities that are mapped to a single database table.
*
* Subclasses can be created to provide custom persisting and querying strategies,
* i.e. spanning multiple tables.
*
* @author Roman Borschel
* @author Giorgio Sironi
* @author Benjamin Eberlei
* @author Alexander
* @author Fabio B. Silva
* @author Rob Caiger
* @since 2.0
*/
class BasicEntityPersister implements EntityPersister
{
/**
* @var array
*/
static private $comparisonMap = array(
Comparison::EQ => '= %s',
Comparison::IS => '= %s',
Comparison::NEQ => '!= %s',
Comparison::GT => '> %s',
Comparison::GTE => '>= %s',
Comparison::LT => '< %s',
Comparison::LTE => '<= %s',
Comparison::IN => 'IN (%s)',
Comparison::NIN => 'NOT IN (%s)',
Comparison::CONTAINS => 'LIKE %s',
);
/**
* Metadata object that describes the mapping of the mapped entity class.
*
* @var \Doctrine\ORM\Mapping\ClassMetadata
*/
protected $class;
/**
* The underlying DBAL Connection of the used EntityManager.
*
* @var \Doctrine\DBAL\Connection $conn
*/
protected $conn;
/**
* The database platform.
*
* @var \Doctrine\DBAL\Platforms\AbstractPlatform
*/
protected $platform;
/**
* The EntityManager instance.
*
* @var EntityManagerInterface
*/
protected $em;
/**
* Queued inserts.
*
* @var array
*/
protected $queuedInserts = array();
/**
* The map of column names to DBAL mapping types of all prepared columns used
* when INSERTing or UPDATEing an entity.
*
* @var array
*
* @see prepareInsertData($entity)
* @see prepareUpdateData($entity)
*/
protected $columnTypes = array();
/**
* The map of quoted column names.
*
* @var array
*
* @see prepareInsertData($entity)
* @see prepareUpdateData($entity)
*/
protected $quotedColumns = array();
/**
* The INSERT SQL statement used for entities handled by this persister.
* This SQL is only generated once per request, if at all.
*
* @var string
*/
private $insertSql;
/**
* The quote strategy.
*
* @var \Doctrine\ORM\Mapping\QuoteStrategy
*/
protected $quoteStrategy;
/**
* The IdentifierFlattener used for manipulating identifiers
*
* @var \Doctrine\ORM\Utility\IdentifierFlattener
*/
private $identifierFlattener;
/**
* @var CachedPersisterContext
*/
protected $currentPersisterContext;
/**
* @var CachedPersisterContext
*/
private $limitsHandlingContext;
/**
* @var CachedPersisterContext
*/
private $noLimitsContext;
/**
* Initializes a new BasicEntityPersister that uses the given EntityManager
* and persists instances of the class described by the given ClassMetadata descriptor.
*
* @param EntityManagerInterface $em
* @param ClassMetadata $class
*/
public function __construct(EntityManagerInterface $em, ClassMetadata $class)
{
$this->em = $em;
$this->class = $class;
$this->conn = $em->getConnection();
$this->platform = $this->conn->getDatabasePlatform();
$this->quoteStrategy = $em->getConfiguration()->getQuoteStrategy();
$this->identifierFlattener = new IdentifierFlattener($em->getUnitOfWork(), $em->getMetadataFactory());
$this->noLimitsContext = $this->currentPersisterContext = new CachedPersisterContext(
$class,
new Query\ResultSetMapping(),
false
);
$this->limitsHandlingContext = new CachedPersisterContext(
$class,
new Query\ResultSetMapping(),
true
);
}
/**
* {@inheritdoc}
*/
public function getClassMetadata()
{
return $this->class;
}
/**
* {@inheritdoc}
*/
public function getResultSetMapping()
{
return $this->currentPersisterContext->rsm;
}
/**
* {@inheritdoc}
*/
public function addInsert($entity)
{
$this->queuedInserts[spl_object_hash($entity)] = $entity;
}
/**
* {@inheritdoc}
*/
public function getInserts()
{
return $this->queuedInserts;
}
/**
* {@inheritdoc}
*/
public function executeInserts()
{
if ( ! $this->queuedInserts) {
return array();
}
$postInsertIds = array();
$idGenerator = $this->class->idGenerator;
$isPostInsertId = $idGenerator->isPostInsertGenerator();
$stmt = $this->conn->prepare($this->getInsertSQL());
$tableName = $this->class->getTableName();
foreach ($this->queuedInserts as $entity) {
$insertData = $this->prepareInsertData($entity);
if (isset($insertData[$tableName])) {
$paramIndex = 1;
foreach ($insertData[$tableName] as $column => $value) {
$stmt->bindValue($paramIndex++, $value, $this->columnTypes[$column]);
}
}
$stmt->execute();
if ($isPostInsertId) {
$generatedId = $idGenerator->generate($this->em, $entity);
$id = array(
$this->class->identifier[0] => $generatedId
);
$postInsertIds[] = array(
'generatedId' => $generatedId,
'entity' => $entity,
);
} else {
$id = $this->class->getIdentifierValues($entity);
}
if ($this->class->isVersioned) {
$this->assignDefaultVersionValue($entity, $id);
}
}
$stmt->closeCursor();
$this->queuedInserts = array();
return $postInsertIds;
}
/**
* Retrieves the default version value which was created
* by the preceding INSERT statement and assigns it back in to the
* entities version field.
*
* @param object $entity
* @param array $id
*
* @return void
*/
protected function assignDefaultVersionValue($entity, array $id)
{
$value = $this->fetchVersionValue($this->class, $id);
$this->class->setFieldValue($entity, $this->class->versionField, $value);
}
/**
* Fetches the current version value of a versioned entity.
*
* @param \Doctrine\ORM\Mapping\ClassMetadata $versionedClass
* @param array $id
*
* @return mixed
*/
protected function fetchVersionValue($versionedClass, array $id)
{
$versionField = $versionedClass->versionField;
$tableName = $this->quoteStrategy->getTableName($versionedClass, $this->platform);
$identifier = $this->quoteStrategy->getIdentifierColumnNames($versionedClass, $this->platform);
$columnName = $this->quoteStrategy->getColumnName($versionField, $versionedClass, $this->platform);
// FIXME: Order with composite keys might not be correct
$sql = 'SELECT ' . $columnName
. ' FROM ' . $tableName
. ' WHERE ' . implode(' = ? AND ', $identifier) . ' = ?';
$flatId = $this->identifierFlattener->flattenIdentifier($versionedClass, $id);
$value = $this->conn->fetchColumn($sql, array_values($flatId));
return Type::getType($versionedClass->fieldMappings[$versionField]['type'])->convertToPHPValue($value, $this->platform);
}
/**
* {@inheritdoc}
*/
public function update($entity)
{
$tableName = $this->class->getTableName();
$updateData = $this->prepareUpdateData($entity);
if ( ! isset($updateData[$tableName]) || ! ($data = $updateData[$tableName])) {
return;
}
$isVersioned = $this->class->isVersioned;
$quotedTableName = $this->quoteStrategy->getTableName($this->class, $this->platform);
$this->updateTable($entity, $quotedTableName, $data, $isVersioned);
if ($isVersioned) {
$id = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
$this->assignDefaultVersionValue($entity, $id);
}
}
/**
* Performs an UPDATE statement for an entity on a specific table.
* The UPDATE can optionally be versioned, which requires the entity to have a version field.
*
* @param object $entity The entity object being updated.
* @param string $quotedTableName The quoted name of the table to apply the UPDATE on.
* @param array $updateData The map of columns to update (column => value).
* @param boolean $versioned Whether the UPDATE should be versioned.
*
* @return void
*
* @throws \Doctrine\ORM\ORMException
* @throws \Doctrine\ORM\OptimisticLockException
*/
protected final function updateTable($entity, $quotedTableName, array $updateData, $versioned = false)
{
$set = array();
$types = array();
$params = array();
foreach ($updateData as $columnName => $value) {
$placeholder = '?';
$column = $columnName;
switch (true) {
case isset($this->class->fieldNames[$columnName]):
$fieldName = $this->class->fieldNames[$columnName];
$column = $this->quoteStrategy->getColumnName($fieldName, $this->class, $this->platform);
if (isset($this->class->fieldMappings[$fieldName]['requireSQLConversion'])) {
$type = Type::getType($this->columnTypes[$columnName]);
$placeholder = $type->convertToDatabaseValueSQL('?', $this->platform);
}
break;
case isset($this->quotedColumns[$columnName]):
$column = $this->quotedColumns[$columnName];
break;
}
$params[] = $value;
$set[] = $column . ' = ' . $placeholder;
$types[] = $this->columnTypes[$columnName];
}
$where = array();
$identifier = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
foreach ($this->class->identifier as $idField) {
if ( ! isset($this->class->associationMappings[$idField])) {
$params[] = $identifier[$idField];
$types[] = $this->class->fieldMappings[$idField]['type'];
$where[] = $this->quoteStrategy->getColumnName($idField, $this->class, $this->platform);
continue;
}
$params[] = $identifier[$idField];
$where[] = $this->class->associationMappings[$idField]['joinColumns'][0]['name'];
$targetMapping = $this->em->getClassMetadata($this->class->associationMappings[$idField]['targetEntity']);
switch (true) {
case (isset($targetMapping->fieldMappings[$targetMapping->identifier[0]])):
$types[] = $targetMapping->fieldMappings[$targetMapping->identifier[0]]['type'];
break;
case (isset($targetMapping->associationMappings[$targetMapping->identifier[0]])):
$types[] = $targetMapping->associationMappings[$targetMapping->identifier[0]]['type'];
break;
default:
throw ORMException::unrecognizedField($targetMapping->identifier[0]);
}
}
if ($versioned) {
$versionField = $this->class->versionField;
$versionFieldType = $this->class->fieldMappings[$versionField]['type'];
$versionColumn = $this->quoteStrategy->getColumnName($versionField, $this->class, $this->platform);
$where[] = $versionColumn;
$types[] = $this->class->fieldMappings[$versionField]['type'];
$params[] = $this->class->reflFields[$versionField]->getValue($entity);
switch ($versionFieldType) {
case Type::SMALLINT:
case Type::INTEGER:
case Type::BIGINT:
$set[] = $versionColumn . ' = ' . $versionColumn . ' + 1';
break;
case Type::DATETIME:
$set[] = $versionColumn . ' = CURRENT_TIMESTAMP';
break;
}
}
$sql = 'UPDATE ' . $quotedTableName
. ' SET ' . implode(', ', $set)
. ' WHERE ' . implode(' = ? AND ', $where) . ' = ?';
$result = $this->conn->executeUpdate($sql, $params, $types);
if ($versioned && ! $result) {
throw OptimisticLockException::lockFailed($entity);
}
}
/**
* @todo Add check for platform if it supports foreign keys/cascading.
*
* @param array $identifier
*
* @return void
*/
protected function deleteJoinTableRecords($identifier)
{
foreach ($this->class->associationMappings as $mapping) {
if ($mapping['type'] !== ClassMetadata::MANY_TO_MANY) {
continue;
}
// @Todo this only covers scenarios with no inheritance or of the same level. Is there something
// like self-referential relationship between different levels of an inheritance hierarchy? I hope not!
$selfReferential = ($mapping['targetEntity'] == $mapping['sourceEntity']);
$class = $this->class;
$association = $mapping;
$otherColumns = array();
$otherKeys = array();
$keys = array();
if ( ! $mapping['isOwningSide']) {
$class = $this->em->getClassMetadata($mapping['targetEntity']);
$association = $class->associationMappings[$mapping['mappedBy']];
}
$joinColumns = $mapping['isOwningSide']
? $association['joinTable']['joinColumns']
: $association['joinTable']['inverseJoinColumns'];
if ($selfReferential) {
$otherColumns = (! $mapping['isOwningSide'])
? $association['joinTable']['joinColumns']
: $association['joinTable']['inverseJoinColumns'];
}
foreach ($joinColumns as $joinColumn) {
$keys[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform);
}
foreach ($otherColumns as $joinColumn) {
$otherKeys[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform);
}
if (isset($mapping['isOnDeleteCascade'])) {
continue;
}
$joinTableName = $this->quoteStrategy->getJoinTableName($association, $this->class, $this->platform);
$this->conn->delete($joinTableName, array_combine($keys, $identifier));
if ($selfReferential) {
$this->conn->delete($joinTableName, array_combine($otherKeys, $identifier));
}
}
}
/**
* {@inheritdoc}
*/
public function delete($entity)
{
$class = $this->class;
$identifier = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
$tableName = $this->quoteStrategy->getTableName($class, $this->platform);
$idColumns = $this->quoteStrategy->getIdentifierColumnNames($class, $this->platform);
$id = array_combine($idColumns, $identifier);
$types = array_map(function ($identifier) use ($class) {
if (isset($class->fieldMappings[$identifier])) {
return $class->fieldMappings[$identifier]['type'];
}
$targetMapping = $this->em->getClassMetadata($class->associationMappings[$identifier]['targetEntity']);
if (isset($targetMapping->fieldMappings[$targetMapping->identifier[0]])) {
return $targetMapping->fieldMappings[$targetMapping->identifier[0]]['type'];
}
if (isset($targetMapping->associationMappings[$targetMapping->identifier[0]])) {
return $targetMapping->associationMappings[$targetMapping->identifier[0]]['type'];
}
throw ORMException::unrecognizedField($targetMapping->identifier[0]);
}, $class->identifier);
$this->deleteJoinTableRecords($identifier);
return (bool) $this->conn->delete($tableName, $id, $types);
}
/**
* Prepares the changeset of an entity for database insertion (UPDATE).
*
* The changeset is obtained from the currently running UnitOfWork.
*
* During this preparation the array that is passed as the second parameter is filled with
* => pairs, grouped by table name.
*
* Example:
*
* array(
* 'foo_table' => array('column1' => 'value1', 'column2' => 'value2', ...),
* 'bar_table' => array('columnX' => 'valueX', 'columnY' => 'valueY', ...),
* ...
* )
*
*
* @param object $entity The entity for which to prepare the data.
*
* @return array The prepared data.
*/
protected function prepareUpdateData($entity)
{
$versionField = null;
$result = array();
$uow = $this->em->getUnitOfWork();
if (($versioned = $this->class->isVersioned) != false) {
$versionField = $this->class->versionField;
}
foreach ($uow->getEntityChangeSet($entity) as $field => $change) {
if (isset($versionField) && $versionField == $field) {
continue;
}
if (isset($this->class->embeddedClasses[$field])) {
continue;
}
$newVal = $change[1];
if ( ! isset($this->class->associationMappings[$field])) {
$columnName = $this->class->columnNames[$field];
$this->columnTypes[$columnName] = $this->class->fieldMappings[$field]['type'];
$result[$this->getOwningTable($field)][$columnName] = $newVal;
continue;
}
$assoc = $this->class->associationMappings[$field];
// Only owning side of x-1 associations can have a FK column.
if ( ! $assoc['isOwningSide'] || ! ($assoc['type'] & ClassMetadata::TO_ONE)) {
continue;
}
if ($newVal !== null) {
$oid = spl_object_hash($newVal);
if (isset($this->queuedInserts[$oid]) || $uow->isScheduledForInsert($newVal)) {
// The associated entity $newVal is not yet persisted, so we must
// set $newVal = null, in order to insert a null value and schedule an
// extra update on the UnitOfWork.
$uow->scheduleExtraUpdate($entity, array($field => array(null, $newVal)));
$newVal = null;
}
}
$newValId = null;
if ($newVal !== null) {
$newValId = $uow->getEntityIdentifier($newVal);
}
$targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
$owningTable = $this->getOwningTable($field);
foreach ($assoc['joinColumns'] as $joinColumn) {
$sourceColumn = $joinColumn['name'];
$targetColumn = $joinColumn['referencedColumnName'];
$quotedColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform);
$this->quotedColumns[$sourceColumn] = $quotedColumn;
$this->columnTypes[$sourceColumn] = PersisterHelper::getTypeOfColumn($targetColumn, $targetClass, $this->em);
$result[$owningTable][$sourceColumn] = $newValId
? $newValId[$targetClass->getFieldForColumn($targetColumn)]
: null;
}
}
return $result;
}
/**
* Prepares the data changeset of a managed entity for database insertion (initial INSERT).
* The changeset of the entity is obtained from the currently running UnitOfWork.
*
* The default insert data preparation is the same as for updates.
*
* @param object $entity The entity for which to prepare the data.
*
* @return array The prepared data for the tables to update.
*
* @see prepareUpdateData
*/
protected function prepareInsertData($entity)
{
return $this->prepareUpdateData($entity);
}
/**
* {@inheritdoc}
*/
public function getOwningTable($fieldName)
{
return $this->class->getTableName();
}
/**
* {@inheritdoc}
*/
public function load(array $criteria, $entity = null, $assoc = null, array $hints = array(), $lockMode = null, $limit = null, array $orderBy = null)
{
$this->switchPersisterContext(null, $limit);
$sql = $this->getSelectSQL($criteria, $assoc, $lockMode, $limit, null, $orderBy);
list($params, $types) = $this->expandParameters($criteria);
$stmt = $this->conn->executeQuery($sql, $params, $types);
if ($entity !== null) {
$hints[Query::HINT_REFRESH] = true;
$hints[Query::HINT_REFRESH_ENTITY] = $entity;
}
$hydrator = $this->em->newHydrator($this->currentPersisterContext->selectJoinSql ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT);
$entities = $hydrator->hydrateAll($stmt, $this->currentPersisterContext->rsm, $hints);
return $entities ? $entities[0] : null;
}
/**
* {@inheritdoc}
*/
public function loadById(array $identifier, $entity = null)
{
return $this->load($identifier, $entity);
}
/**
* {@inheritdoc}
*/
public function loadOneToOneEntity(array $assoc, $sourceEntity, array $identifier = array())
{
if (($foundEntity = $this->em->getUnitOfWork()->tryGetById($identifier, $assoc['targetEntity'])) != false) {
return $foundEntity;
}
$targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
if ($assoc['isOwningSide']) {
$isInverseSingleValued = $assoc['inversedBy'] && ! $targetClass->isCollectionValuedAssociation($assoc['inversedBy']);
// Mark inverse side as fetched in the hints, otherwise the UoW would
// try to load it in a separate query (remember: to-one inverse sides can not be lazy).
$hints = array();
if ($isInverseSingleValued) {
$hints['fetched']["r"][$assoc['inversedBy']] = true;
}
/* cascade read-only status
if ($this->em->getUnitOfWork()->isReadOnly($sourceEntity)) {
$hints[Query::HINT_READ_ONLY] = true;
}
*/
$targetEntity = $this->load($identifier, null, $assoc, $hints);
// Complete bidirectional association, if necessary
if ($targetEntity !== null && $isInverseSingleValued) {
$targetClass->reflFields[$assoc['inversedBy']]->setValue($targetEntity, $sourceEntity);
}
return $targetEntity;
}
$sourceClass = $this->em->getClassMetadata($assoc['sourceEntity']);
$owningAssoc = $targetClass->getAssociationMapping($assoc['mappedBy']);
// TRICKY: since the association is specular source and target are flipped
foreach ($owningAssoc['targetToSourceKeyColumns'] as $sourceKeyColumn => $targetKeyColumn) {
if ( ! isset($sourceClass->fieldNames[$sourceKeyColumn])) {
throw MappingException::joinColumnMustPointToMappedField(
$sourceClass->name, $sourceKeyColumn
);
}
// unset the old value and set the new sql aliased value here. By definition
// unset($identifier[$targetKeyColumn] works here with how UnitOfWork::createEntity() calls this method.
$identifier[$this->getSQLTableAlias($targetClass->name) . "." . $targetKeyColumn] =
$sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
unset($identifier[$targetKeyColumn]);
}
$targetEntity = $this->load($identifier, null, $assoc);
if ($targetEntity !== null) {
$targetClass->setFieldValue($targetEntity, $assoc['mappedBy'], $sourceEntity);
}
return $targetEntity;
}
/**
* {@inheritdoc}
*/
public function refresh(array $id, $entity, $lockMode = null)
{
$sql = $this->getSelectSQL($id, null, $lockMode);
list($params, $types) = $this->expandParameters($id);
$stmt = $this->conn->executeQuery($sql, $params, $types);
$hydrator = $this->em->newHydrator(Query::HYDRATE_OBJECT);
$hydrator->hydrateAll($stmt, $this->currentPersisterContext->rsm, array(Query::HINT_REFRESH => true));
}
/**
* {@inheritDoc}
*/
public function count($criteria = array())
{
$sql = $this->getCountSQL($criteria);
list($params, $types) = ($criteria instanceof Criteria)
? $this->expandCriteriaParameters($criteria)
: $this->expandParameters($criteria);
return (int) $this->conn->executeQuery($sql, $params, $types)->fetchColumn();
}
/**
* {@inheritdoc}
*/
public function loadCriteria(Criteria $criteria)
{
$orderBy = $criteria->getOrderings();
$limit = $criteria->getMaxResults();
$offset = $criteria->getFirstResult();
$query = $this->getSelectSQL($criteria, null, null, $limit, $offset, $orderBy);
list($params, $types) = $this->expandCriteriaParameters($criteria);
$stmt = $this->conn->executeQuery($query, $params, $types);
$hydrator = $this->em->newHydrator(($this->currentPersisterContext->selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT);
return $hydrator->hydrateAll($stmt, $this->currentPersisterContext->rsm, array(UnitOfWork::HINT_DEFEREAGERLOAD => true));
}
/**
* {@inheritdoc}
*/
public function expandCriteriaParameters(Criteria $criteria)
{
$expression = $criteria->getWhereExpression();
$sqlParams = array();
$sqlTypes = array();
if ($expression === null) {
return array($sqlParams, $sqlTypes);
}
$valueVisitor = new SqlValueVisitor();
$valueVisitor->dispatch($expression);
list($params, $types) = $valueVisitor->getParamsAndTypes();
foreach ($params as $param) {
$sqlParams = array_merge($sqlParams, $this->getValues($param));
}
foreach ($types as $type) {
list ($field, $value) = $type;
$sqlTypes = array_merge($sqlTypes, $this->getTypes($field, $value, $this->class));
}
return array($sqlParams, $sqlTypes);
}
/**
* {@inheritdoc}
*/
public function loadAll(array $criteria = array(), array $orderBy = null, $limit = null, $offset = null)
{
$this->switchPersisterContext($offset, $limit);
$sql = $this->getSelectSQL($criteria, null, null, $limit, $offset, $orderBy);
list($params, $types) = $this->expandParameters($criteria);
$stmt = $this->conn->executeQuery($sql, $params, $types);
$hydrator = $this->em->newHydrator(($this->currentPersisterContext->selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT);
return $hydrator->hydrateAll($stmt, $this->currentPersisterContext->rsm, array(UnitOfWork::HINT_DEFEREAGERLOAD => true));
}
/**
* {@inheritdoc}
*/
public function getManyToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null)
{
$this->switchPersisterContext($offset, $limit);
$stmt = $this->getManyToManyStatement($assoc, $sourceEntity, $offset, $limit);
return $this->loadArrayFromStatement($assoc, $stmt);
}
/**
* Loads an array of entities from a given DBAL statement.
*
* @param array $assoc
* @param \Doctrine\DBAL\Statement $stmt
*
* @return array
*/
private function loadArrayFromStatement($assoc, $stmt)
{
$rsm = $this->currentPersisterContext->rsm;
$hints = array(UnitOfWork::HINT_DEFEREAGERLOAD => true);
if (isset($assoc['indexBy'])) {
$rsm = clone ($this->currentPersisterContext->rsm); // this is necessary because the "default rsm" should be changed.
$rsm->addIndexBy('r', $assoc['indexBy']);
}
return $this->em->newHydrator(Query::HYDRATE_OBJECT)->hydrateAll($stmt, $rsm, $hints);
}
/**
* Hydrates a collection from a given DBAL statement.
*
* @param array $assoc
* @param \Doctrine\DBAL\Statement $stmt
* @param PersistentCollection $coll
*
* @return array
*/
private function loadCollectionFromStatement($assoc, $stmt, $coll)
{
$rsm = $this->currentPersisterContext->rsm;
$hints = array(
UnitOfWork::HINT_DEFEREAGERLOAD => true,
'collection' => $coll
);
if (isset($assoc['indexBy'])) {
$rsm = clone ($this->currentPersisterContext->rsm); // this is necessary because the "default rsm" should be changed.
$rsm->addIndexBy('r', $assoc['indexBy']);
}
return $this->em->newHydrator(Query::HYDRATE_OBJECT)->hydrateAll($stmt, $rsm, $hints);
}
/**
* {@inheritdoc}
*/
public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
{
$stmt = $this->getManyToManyStatement($assoc, $sourceEntity);
return $this->loadCollectionFromStatement($assoc, $stmt, $coll);
}
/**
* @param array $assoc
* @param object $sourceEntity
* @param int|null $offset
* @param int|null $limit
*
* @return \Doctrine\DBAL\Driver\Statement
*
* @throws \Doctrine\ORM\Mapping\MappingException
*/
private function getManyToManyStatement(array $assoc, $sourceEntity, $offset = null, $limit = null)
{
$this->switchPersisterContext($offset, $limit);
$sourceClass = $this->em->getClassMetadata($assoc['sourceEntity']);
$class = $sourceClass;
$association = $assoc;
$criteria = array();
$parameters = array();
if ( ! $assoc['isOwningSide']) {
$class = $this->em->getClassMetadata($assoc['targetEntity']);
$association = $class->associationMappings[$assoc['mappedBy']];
}
$joinColumns = $assoc['isOwningSide']
? $association['joinTable']['joinColumns']
: $association['joinTable']['inverseJoinColumns'];
$quotedJoinTable = $this->quoteStrategy->getJoinTableName($association, $class, $this->platform);
foreach ($joinColumns as $joinColumn) {
$sourceKeyColumn = $joinColumn['referencedColumnName'];
$quotedKeyColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform);
switch (true) {
case $sourceClass->containsForeignIdentifier:
$field = $sourceClass->getFieldForColumn($sourceKeyColumn);
$value = $sourceClass->reflFields[$field]->getValue($sourceEntity);
if (isset($sourceClass->associationMappings[$field])) {
$value = $this->em->getUnitOfWork()->getEntityIdentifier($value);
$value = $value[$this->em->getClassMetadata($sourceClass->associationMappings[$field]['targetEntity'])->identifier[0]];
}
break;
case isset($sourceClass->fieldNames[$sourceKeyColumn]):
$field = $sourceClass->fieldNames[$sourceKeyColumn];
$value = $sourceClass->reflFields[$field]->getValue($sourceEntity);
break;
default:
throw MappingException::joinColumnMustPointToMappedField(
$sourceClass->name, $sourceKeyColumn
);
}
$criteria[$quotedJoinTable . '.' . $quotedKeyColumn] = $value;
$parameters[] = array(
'value' => $value,
'field' => $field,
'class' => $sourceClass,
);
}
$sql = $this->getSelectSQL($criteria, $assoc, null, $limit, $offset);
list($params, $types) = $this->expandToManyParameters($parameters);
return $this->conn->executeQuery($sql, $params, $types);
}
/**
* {@inheritdoc}
*/
public function getSelectSQL($criteria, $assoc = null, $lockMode = null, $limit = null, $offset = null, array $orderBy = null)
{
$this->switchPersisterContext($offset, $limit);
$lockSql = '';
$joinSql = '';
$orderBySql = '';
if ($assoc != null && $assoc['type'] == ClassMetadata::MANY_TO_MANY) {
$joinSql = $this->getSelectManyToManyJoinSQL($assoc);
}
if (isset($assoc['orderBy'])) {
$orderBy = $assoc['orderBy'];
}
if ($orderBy) {
$orderBySql = $this->getOrderBySQL($orderBy, $this->getSQLTableAlias($this->class->name));
}
$conditionSql = ($criteria instanceof Criteria)
? $this->getSelectConditionCriteriaSQL($criteria)
: $this->getSelectConditionSQL($criteria, $assoc);
switch ($lockMode) {
case LockMode::PESSIMISTIC_READ:
$lockSql = ' ' . $this->platform->getReadLockSql();
break;
case LockMode::PESSIMISTIC_WRITE:
$lockSql = ' ' . $this->platform->getWriteLockSql();
break;
}
$columnList = $this->getSelectColumnsSQL();
$tableAlias = $this->getSQLTableAlias($this->class->name);
$filterSql = $this->generateFilterConditionSQL($this->class, $tableAlias);
$tableName = $this->quoteStrategy->getTableName($this->class, $this->platform);
if ('' !== $filterSql) {
$conditionSql = $conditionSql
? $conditionSql . ' AND ' . $filterSql
: $filterSql;
}
$select = 'SELECT ' . $columnList;
$from = ' FROM ' . $tableName . ' '. $tableAlias;
$join = $this->currentPersisterContext->selectJoinSql . $joinSql;
$where = ($conditionSql ? ' WHERE ' . $conditionSql : '');
$lock = $this->platform->appendLockHint($from, $lockMode);
$query = $select
. $lock
. $join
. $where
. $orderBySql;
return $this->platform->modifyLimitQuery($query, $limit, $offset) . $lockSql;
}
/**
* {@inheritDoc}
*/
public function getCountSQL($criteria = array())
{
$tableName = $this->quoteStrategy->getTableName($this->class, $this->platform);
$tableAlias = $this->getSQLTableAlias($this->class->name);
$conditionSql = ($criteria instanceof Criteria)
? $this->getSelectConditionCriteriaSQL($criteria)
: $this->getSelectConditionSQL($criteria);
$filterSql = $this->generateFilterConditionSQL($this->class, $tableAlias);
if ('' !== $filterSql) {
$conditionSql = $conditionSql
? $conditionSql . ' AND ' . $filterSql
: $filterSql;
}
$sql = 'SELECT COUNT(*) '
. 'FROM ' . $tableName . ' ' . $tableAlias
. (empty($conditionSql) ? '' : ' WHERE ' . $conditionSql);
return $sql;
}
/**
* Gets the ORDER BY SQL snippet for ordered collections.
*
* @param array $orderBy
* @param string $baseTableAlias
*
* @return string
*
* @throws \Doctrine\ORM\ORMException
*/
protected final function getOrderBySQL(array $orderBy, $baseTableAlias)
{
$orderByList = array();
foreach ($orderBy as $fieldName => $orientation) {
$orientation = strtoupper(trim($orientation));
if ($orientation != 'ASC' && $orientation != 'DESC') {
throw ORMException::invalidOrientation($this->class->name, $fieldName);
}
if (isset($this->class->fieldMappings[$fieldName])) {
$tableAlias = isset($this->class->fieldMappings[$fieldName]['inherited'])
? $this->getSQLTableAlias($this->class->fieldMappings[$fieldName]['inherited'])
: $baseTableAlias;
$columnName = $this->quoteStrategy->getColumnName($fieldName, $this->class, $this->platform);
$orderByList[] = $tableAlias . '.' . $columnName . ' ' . $orientation;
continue;
}
if (isset($this->class->associationMappings[$fieldName])) {
if ( ! $this->class->associationMappings[$fieldName]['isOwningSide']) {
throw ORMException::invalidFindByInverseAssociation($this->class->name, $fieldName);
}
$tableAlias = isset($this->class->associationMappings[$fieldName]['inherited'])
? $this->getSQLTableAlias($this->class->associationMappings[$fieldName]['inherited'])
: $baseTableAlias;
foreach ($this->class->associationMappings[$fieldName]['joinColumns'] as $joinColumn) {
$columnName = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform);
$orderByList[] = $tableAlias . '.' . $columnName . ' ' . $orientation;
}
continue;
}
throw ORMException::unrecognizedField($fieldName);
}
return ' ORDER BY ' . implode(', ', $orderByList);
}
/**
* Gets the SQL fragment with the list of columns to select when querying for
* an entity in this persister.
*
* Subclasses should override this method to alter or change the select column
* list SQL fragment. Note that in the implementation of BasicEntityPersister
* the resulting SQL fragment is generated only once and cached in {@link selectColumnListSql}.
* Subclasses may or may not do the same.
*
* @return string The SQL fragment.
*/
protected function getSelectColumnsSQL()
{
if ($this->currentPersisterContext->selectColumnListSql !== null) {
return $this->currentPersisterContext->selectColumnListSql;
}
$columnList = array();
$this->currentPersisterContext->rsm->addEntityResult($this->class->name, 'r'); // r for root
// Add regular columns to select list
foreach ($this->class->fieldNames as $field) {
$columnList[] = $this->getSelectColumnSQL($field, $this->class);
}
$this->currentPersisterContext->selectJoinSql = '';
$eagerAliasCounter = 0;
foreach ($this->class->associationMappings as $assocField => $assoc) {
$assocColumnSQL = $this->getSelectColumnAssociationSQL($assocField, $assoc, $this->class);
if ($assocColumnSQL) {
$columnList[] = $assocColumnSQL;
}
$isAssocToOneInverseSide = $assoc['type'] & ClassMetadata::TO_ONE && ! $assoc['isOwningSide'];
$isAssocFromOneEager = $assoc['type'] !== ClassMetadata::MANY_TO_MANY && $assoc['fetch'] === ClassMetadata::FETCH_EAGER;
if ( ! ($isAssocFromOneEager || $isAssocToOneInverseSide)) {
continue;
}
if ((($assoc['type'] & ClassMetadata::TO_MANY) > 0) && $this->currentPersisterContext->handlesLimits) {
continue;
}
$eagerEntity = $this->em->getClassMetadata($assoc['targetEntity']);
if ($eagerEntity->inheritanceType != ClassMetadata::INHERITANCE_TYPE_NONE) {
continue; // now this is why you shouldn't use inheritance
}
$assocAlias = 'e' . ($eagerAliasCounter++);
$this->currentPersisterContext->rsm->addJoinedEntityResult($assoc['targetEntity'], $assocAlias, 'r', $assocField);
foreach ($eagerEntity->fieldNames as $field) {
$columnList[] = $this->getSelectColumnSQL($field, $eagerEntity, $assocAlias);
}
foreach ($eagerEntity->associationMappings as $eagerAssocField => $eagerAssoc) {
$eagerAssocColumnSQL = $this->getSelectColumnAssociationSQL(
$eagerAssocField, $eagerAssoc, $eagerEntity, $assocAlias
);
if ($eagerAssocColumnSQL) {
$columnList[] = $eagerAssocColumnSQL;
}
}
$association = $assoc;
$joinCondition = array();
if (isset($assoc['indexBy'])) {
$this->currentPersisterContext->rsm->addIndexBy($assocAlias, $assoc['indexBy']);
}
if ( ! $assoc['isOwningSide']) {
$eagerEntity = $this->em->getClassMetadata($assoc['targetEntity']);
$association = $eagerEntity->getAssociationMapping($assoc['mappedBy']);
}
$joinTableAlias = $this->getSQLTableAlias($eagerEntity->name, $assocAlias);
$joinTableName = $this->quoteStrategy->getTableName($eagerEntity, $this->platform);
if ($assoc['isOwningSide']) {
$tableAlias = $this->getSQLTableAlias($association['targetEntity'], $assocAlias);
$this->currentPersisterContext->selectJoinSql .= ' ' . $this->getJoinSQLForJoinColumns($association['joinColumns']);
foreach ($association['joinColumns'] as $joinColumn) {
$sourceCol = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform);
$targetCol = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $this->class, $this->platform);
$joinCondition[] = $this->getSQLTableAlias($association['sourceEntity'])
. '.' . $sourceCol . ' = ' . $tableAlias . '.' . $targetCol;
}
// Add filter SQL
if ($filterSql = $this->generateFilterConditionSQL($eagerEntity, $tableAlias)) {
$joinCondition[] = $filterSql;
}
} else {
$this->currentPersisterContext->selectJoinSql .= ' LEFT JOIN';
foreach ($association['joinColumns'] as $joinColumn) {
$sourceCol = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform);
$targetCol = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $this->class, $this->platform);
$joinCondition[] = $this->getSQLTableAlias($association['sourceEntity'], $assocAlias) . '.' . $sourceCol . ' = '
. $this->getSQLTableAlias($association['targetEntity']) . '.' . $targetCol;
}
}
$this->currentPersisterContext->selectJoinSql .= ' ' . $joinTableName . ' ' . $joinTableAlias . ' ON ';
$this->currentPersisterContext->selectJoinSql .= implode(' AND ', $joinCondition);
}
$this->currentPersisterContext->selectColumnListSql = implode(', ', $columnList);
return $this->currentPersisterContext->selectColumnListSql;
}
/**
* Gets the SQL join fragment used when selecting entities from an association.
*
* @param string $field
* @param array $assoc
* @param ClassMetadata $class
* @param string $alias
*
* @return string
*/
protected function getSelectColumnAssociationSQL($field, $assoc, ClassMetadata $class, $alias = 'r')
{
if ( ! ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) ) {
return '';
}
$columnList = array();
$targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
foreach ($assoc['joinColumns'] as $joinColumn) {
$type = null;
$isIdentifier = isset($assoc['id']) && $assoc['id'] === true;
$quotedColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform);
$resultColumnName = $this->getSQLColumnAlias($joinColumn['name']);
$columnList[] = $this->getSQLTableAlias($class->name, ($alias == 'r' ? '' : $alias) )
. '.' . $quotedColumn . ' AS ' . $resultColumnName;
$type = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $targetClass, $this->em);
$this->currentPersisterContext->rsm->addMetaResult($alias, $resultColumnName, $quotedColumn, $isIdentifier, $type);
}
return implode(', ', $columnList);
}
/**
* Gets the SQL join fragment used when selecting entities from a
* many-to-many association.
*
* @param array $manyToMany
*
* @return string
*/
protected function getSelectManyToManyJoinSQL(array $manyToMany)
{
$conditions = array();
$association = $manyToMany;
$sourceTableAlias = $this->getSQLTableAlias($this->class->name);
if ( ! $manyToMany['isOwningSide']) {
$targetEntity = $this->em->getClassMetadata($manyToMany['targetEntity']);
$association = $targetEntity->associationMappings[$manyToMany['mappedBy']];
}
$joinTableName = $this->quoteStrategy->getJoinTableName($association, $this->class, $this->platform);
$joinColumns = ($manyToMany['isOwningSide'])
? $association['joinTable']['inverseJoinColumns']
: $association['joinTable']['joinColumns'];
foreach ($joinColumns as $joinColumn) {
$quotedSourceColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform);
$quotedTargetColumn = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $this->class, $this->platform);
$conditions[] = $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableName . '.' . $quotedSourceColumn;
}
return ' INNER JOIN ' . $joinTableName . ' ON ' . implode(' AND ', $conditions);
}
/**
* {@inheritdoc}
*/
public function getInsertSQL()
{
if ($this->insertSql !== null) {
return $this->insertSql;
}
$columns = $this->getInsertColumnList();
$tableName = $this->quoteStrategy->getTableName($this->class, $this->platform);
if (empty($columns)) {
$identityColumn = $this->quoteStrategy->getColumnName($this->class->identifier[0], $this->class, $this->platform);
$this->insertSql = $this->platform->getEmptyIdentityInsertSQL($tableName, $identityColumn);
return $this->insertSql;
}
$values = array();
$columns = array_unique($columns);
foreach ($columns as $column) {
$placeholder = '?';
if (isset($this->class->fieldNames[$column])
&& isset($this->columnTypes[$this->class->fieldNames[$column]])
&& isset($this->class->fieldMappings[$this->class->fieldNames[$column]]['requireSQLConversion'])) {
$type = Type::getType($this->columnTypes[$this->class->fieldNames[$column]]);
$placeholder = $type->convertToDatabaseValueSQL('?', $this->platform);
}
$values[] = $placeholder;
}
$columns = implode(', ', $columns);
$values = implode(', ', $values);
$this->insertSql = sprintf('INSERT INTO %s (%s) VALUES (%s)', $tableName, $columns, $values);
return $this->insertSql;
}
/**
* Gets the list of columns to put in the INSERT SQL statement.
*
* Subclasses should override this method to alter or change the list of
* columns placed in the INSERT statements used by the persister.
*
* @return array The list of columns.
*/
protected function getInsertColumnList()
{
$columns = array();
foreach ($this->class->reflFields as $name => $field) {
if ($this->class->isVersioned && $this->class->versionField == $name) {
continue;
}
if (isset($this->class->embeddedClasses[$name])) {
continue;
}
if (isset($this->class->associationMappings[$name])) {
$assoc = $this->class->associationMappings[$name];
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
foreach ($assoc['joinColumns'] as $joinColumn) {
$columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform);
}
}
continue;
}
if ($this->class->generatorType != ClassMetadata::GENERATOR_TYPE_IDENTITY || $this->class->identifier[0] != $name) {
$columns[] = $this->quoteStrategy->getColumnName($name, $this->class, $this->platform);
$this->columnTypes[$name] = $this->class->fieldMappings[$name]['type'];
}
}
return $columns;
}
/**
* Gets the SQL snippet of a qualified column name for the given field name.
*
* @param string $field The field name.
* @param ClassMetadata $class The class that declares this field. The table this class is
* mapped to must own the column for the given field.
* @param string $alias
*
* @return string
*/
protected function getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r')
{
$root = $alias == 'r' ? '' : $alias ;
$tableAlias = $this->getSQLTableAlias($class->name, $root);
$columnName = $this->quoteStrategy->getColumnName($field, $class, $this->platform);
$sql = $tableAlias . '.' . $columnName;
$columnAlias = $this->getSQLColumnAlias($class->columnNames[$field]);
$this->currentPersisterContext->rsm->addFieldResult($alias, $columnAlias, $field);
if (isset($class->fieldMappings[$field]['requireSQLConversion'])) {
$type = Type::getType($class->getTypeOfField($field));
$sql = $type->convertToPHPValueSQL($sql, $this->platform);
}
return $sql . ' AS ' . $columnAlias;
}
/**
* Gets the SQL table alias for the given class name.
*
* @param string $className
* @param string $assocName
*
* @return string The SQL table alias.
*
* @todo Reconsider. Binding table aliases to class names is not such a good idea.
*/
protected function getSQLTableAlias($className, $assocName = '')
{
if ($assocName) {
$className .= '#' . $assocName;
}
if (isset($this->currentPersisterContext->sqlTableAliases[$className])) {
return $this->currentPersisterContext->sqlTableAliases[$className];
}
$tableAlias = 't' . $this->currentPersisterContext->sqlAliasCounter++;
$this->currentPersisterContext->sqlTableAliases[$className] = $tableAlias;
return $tableAlias;
}
/**
* {@inheritdoc}
*/
public function lock(array $criteria, $lockMode)
{
$lockSql = '';
$conditionSql = $this->getSelectConditionSQL($criteria);
switch ($lockMode) {
case LockMode::PESSIMISTIC_READ:
$lockSql = $this->platform->getReadLockSql();
break;
case LockMode::PESSIMISTIC_WRITE:
$lockSql = $this->platform->getWriteLockSql();
break;
}
$lock = $this->getLockTablesSql($lockMode);
$where = ($conditionSql ? ' WHERE ' . $conditionSql : '') . ' ';
$sql = 'SELECT 1 '
. $lock
. $where
. $lockSql;
list($params, $types) = $this->expandParameters($criteria);
$this->conn->executeQuery($sql, $params, $types);
}
/**
* Gets the FROM and optionally JOIN conditions to lock the entity managed by this persister.
*
* @param integer $lockMode One of the Doctrine\DBAL\LockMode::* constants.
*
* @return string
*/
protected function getLockTablesSql($lockMode)
{
return $this->platform->appendLockHint(
'FROM '
. $this->quoteStrategy->getTableName($this->class, $this->platform) . ' '
. $this->getSQLTableAlias($this->class->name),
$lockMode
);
}
/**
* Gets the Select Where Condition from a Criteria object.
*
* @param \Doctrine\Common\Collections\Criteria $criteria
*
* @return string
*/
protected function getSelectConditionCriteriaSQL(Criteria $criteria)
{
$expression = $criteria->getWhereExpression();
if ($expression === null) {
return '';
}
$visitor = new SqlExpressionVisitor($this, $this->class);
return $visitor->dispatch($expression);
}
/**
* {@inheritdoc}
*/
public function getSelectConditionStatementSQL($field, $value, $assoc = null, $comparison = null)
{
$selectedColumns = array();
$columns = $this->getSelectConditionStatementColumnSQL($field, $assoc);
if (count($columns) > 1 && $comparison === Comparison::IN) {
/*
* @todo try to support multi-column IN expressions.
* Example: (col1, col2) IN (('val1A', 'val2A'), ('val1B', 'val2B'))
*/
throw ORMException::cantUseInOperatorOnCompositeKeys();
}
foreach ($columns as $column) {
$placeholder = '?';
if (isset($this->class->fieldMappings[$field]['requireSQLConversion'])) {
$placeholder = Type::getType($this->class->getTypeOfField($field))->convertToDatabaseValueSQL($placeholder, $this->platform);
}
if (null !== $comparison) {
// special case null value handling
if (($comparison === Comparison::EQ || $comparison === Comparison::IS) && null ===$value) {
$selectedColumns[] = $column . ' IS NULL';
continue;
}
if ($comparison === Comparison::NEQ && null === $value) {
$selectedColumns[] = $column . ' IS NOT NULL';
continue;
}
$selectedColumns[] = $column . ' ' . sprintf(self::$comparisonMap[$comparison], $placeholder);
continue;
}
if (is_array($value)) {
$in = sprintf('%s IN (%s)', $column, $placeholder);
if (false !== array_search(null, $value, true)) {
$selectedColumns[] = sprintf('(%s OR %s IS NULL)', $in, $column);
continue;
}
$selectedColumns[] = $in;
continue;
}
if (null === $value) {
$selectedColumns[] = sprintf('%s IS NULL', $column);
continue;
}
$selectedColumns[] = sprintf('%s = %s', $column, $placeholder);
}
return implode(' AND ', $selectedColumns);
}
/**
* Builds the left-hand-side of a where condition statement.
*
* @param string $field
* @param array|null $assoc
*
* @return string[]
*
* @throws \Doctrine\ORM\ORMException
*/
private function getSelectConditionStatementColumnSQL($field, $assoc = null)
{
if (isset($this->class->columnNames[$field])) {
$className = (isset($this->class->fieldMappings[$field]['inherited']))
? $this->class->fieldMappings[$field]['inherited']
: $this->class->name;
return array($this->getSQLTableAlias($className) . '.' . $this->quoteStrategy->getColumnName($field, $this->class, $this->platform));
}
if (isset($this->class->associationMappings[$field])) {
$association = $this->class->associationMappings[$field];
// Many-To-Many requires join table check for joinColumn
$columns = array();
$class = $this->class;
if ($association['type'] === ClassMetadata::MANY_TO_MANY) {
if ( ! $association['isOwningSide']) {
$association = $assoc;
}
$joinTableName = $this->quoteStrategy->getJoinTableName($association, $class, $this->platform);
$joinColumns = $assoc['isOwningSide']
? $association['joinTable']['joinColumns']
: $association['joinTable']['inverseJoinColumns'];
foreach ($joinColumns as $joinColumn) {
$columns[] = $joinTableName . '.' . $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform);
}
} else {
if ( ! $association['isOwningSide']) {
throw ORMException::invalidFindByInverseAssociation($this->class->name, $field);
}
$className = (isset($association['inherited']))
? $association['inherited']
: $this->class->name;
foreach ($association['joinColumns'] as $joinColumn) {
$columns[] = $this->getSQLTableAlias($className) . '.' . $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform);
}
}
return $columns;
}
if ($assoc !== null && strpos($field, " ") === false && strpos($field, "(") === false) {
// very careless developers could potentially open up this normally hidden api for userland attacks,
// therefore checking for spaces and function calls which are not allowed.
// found a join column condition, not really a "field"
return array($field);
}
throw ORMException::unrecognizedField($field);
}
/**
* Gets the conditional SQL fragment used in the WHERE clause when selecting
* entities in this persister.
*
* Subclasses are supposed to override this method if they intend to change
* or alter the criteria by which entities are selected.
*
* @param array $criteria
* @param array|null $assoc
*
* @return string
*/
protected function getSelectConditionSQL(array $criteria, $assoc = null)
{
$conditions = array();
foreach ($criteria as $field => $value) {
$conditions[] = $this->getSelectConditionStatementSQL($field, $value, $assoc);
}
return implode(' AND ', $conditions);
}
/**
* {@inheritdoc}
*/
public function getOneToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null)
{
$this->switchPersisterContext($offset, $limit);
$stmt = $this->getOneToManyStatement($assoc, $sourceEntity, $offset, $limit);
return $this->loadArrayFromStatement($assoc, $stmt);
}
/**
* {@inheritdoc}
*/
public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
{
$stmt = $this->getOneToManyStatement($assoc, $sourceEntity);
return $this->loadCollectionFromStatement($assoc, $stmt, $coll);
}
/**
* Builds criteria and execute SQL statement to fetch the one to many entities from.
*
* @param array $assoc
* @param object $sourceEntity
* @param int|null $offset
* @param int|null $limit
*
* @return \Doctrine\DBAL\Statement
*/
private function getOneToManyStatement(array $assoc, $sourceEntity, $offset = null, $limit = null)
{
$this->switchPersisterContext($offset, $limit);
$criteria = array();
$parameters = array();
$owningAssoc = $this->class->associationMappings[$assoc['mappedBy']];
$sourceClass = $this->em->getClassMetadata($assoc['sourceEntity']);
$tableAlias = $this->getSQLTableAlias(isset($owningAssoc['inherited']) ? $owningAssoc['inherited'] : $this->class->name);
foreach ($owningAssoc['targetToSourceKeyColumns'] as $sourceKeyColumn => $targetKeyColumn) {
if ($sourceClass->containsForeignIdentifier) {
$field = $sourceClass->getFieldForColumn($sourceKeyColumn);
$value = $sourceClass->reflFields[$field]->getValue($sourceEntity);
if (isset($sourceClass->associationMappings[$field])) {
$value = $this->em->getUnitOfWork()->getEntityIdentifier($value);
$value = $value[$this->em->getClassMetadata($sourceClass->associationMappings[$field]['targetEntity'])->identifier[0]];
}
$criteria[$tableAlias . "." . $targetKeyColumn] = $value;
$parameters[] = array(
'value' => $value,
'field' => $field,
'class' => $sourceClass,
);
continue;
}
$field = $sourceClass->fieldNames[$sourceKeyColumn];
$value = $sourceClass->reflFields[$field]->getValue($sourceEntity);
$criteria[$tableAlias . "." . $targetKeyColumn] = $value;
$parameters[] = array(
'value' => $value,
'field' => $field,
'class' => $sourceClass,
);
}
$sql = $this->getSelectSQL($criteria, $assoc, null, $limit, $offset);
list($params, $types) = $this->expandToManyParameters($parameters);
return $this->conn->executeQuery($sql, $params, $types);
}
/**
* {@inheritdoc}
*/
public function expandParameters($criteria)
{
$params = array();
$types = array();
foreach ($criteria as $field => $value) {
if ($value === null) {
continue; // skip null values.
}
$types = array_merge($types, $this->getTypes($field, $value, $this->class));
$params = array_merge($params, $this->getValues($value));
}
return array($params, $types);
}
/**
* Expands the parameters from the given criteria and use the correct binding types if found,
* specialized for OneToMany or ManyToMany associations.
*
* @param mixed[][] $criteria an array of arrays containing following:
* - field to which each criterion will be bound
* - value to be bound
* - class to which the field belongs to
*
*
* @return array
*/
private function expandToManyParameters($criteria)
{
$params = array();
$types = array();
foreach ($criteria as $criterion) {
if ($criterion['value'] === null) {
continue; // skip null values.
}
$types = array_merge($types, $this->getTypes($criterion['field'], $criterion['value'], $criterion['class']));
$params = array_merge($params, $this->getValues($criterion['value']));
}
return array($params, $types);
}
/**
* Infers field types to be used by parameter type casting.
*
* @param string $field
* @param mixed $value
*
* @return array
*
* @throws \Doctrine\ORM\Query\QueryException
*/
private function getTypes($field, $value, ClassMetadata $class)
{
$types = array();
switch (true) {
case (isset($class->fieldMappings[$field])):
$types = array_merge($types, PersisterHelper::getTypeOfField($field, $class, $this->em));
break;
case (isset($class->associationMappings[$field])):
$assoc = $class->associationMappings[$field];
$class = $this->em->getClassMetadata($assoc['targetEntity']);
if (! $assoc['isOwningSide']) {
$assoc = $class->associationMappings[$assoc['mappedBy']];
$class = $this->em->getClassMetadata($assoc['targetEntity']);
}
$columns = $assoc['type'] === ClassMetadata::MANY_TO_MANY
? $assoc['relationToTargetKeyColumns']
: $assoc['sourceToTargetKeyColumns'];
foreach ($columns as $column){
$types[] = PersisterHelper::getTypeOfColumn($column, $class, $this->em);
}
break;
default:
$types[] = null;
break;
}
if (is_array($value)) {
return array_map(
function ($type) {
return Type::getType($type)->getBindingType() + Connection::ARRAY_PARAM_OFFSET;
},
$types
);
}
return $types;
}
/**
* Retrieves the parameters that identifies a value.
*
* @param mixed $value
*
* @return array
*/
private function getValues($value)
{
if (is_array($value)) {
$newValue = array();
foreach ($value as $itemValue) {
$newValue = array_merge($newValue, $this->getValues($itemValue));
}
return array($newValue);
}
if (is_object($value) && $this->em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($value))) {
$class = $this->em->getClassMetadata(get_class($value));
if ($class->isIdentifierComposite) {
$newValue = array();
foreach ($class->getIdentifierValues($value) as $innerValue) {
$newValue = array_merge($newValue, $this->getValues($innerValue));
}
return $newValue;
}
}
return array($this->getIndividualValue($value));
}
/**
* Retrieves an individual parameter value.
*
* @param mixed $value
*
* @return mixed
*/
private function getIndividualValue($value)
{
if ( ! is_object($value) || ! $this->em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($value))) {
return $value;
}
return $this->em->getUnitOfWork()->getSingleIdentifierValue($value);
}
/**
* {@inheritdoc}
*/
public function exists($entity, Criteria $extraConditions = null)
{
$criteria = $this->class->getIdentifierValues($entity);
if ( ! $criteria) {
return false;
}
$alias = $this->getSQLTableAlias($this->class->name);
$sql = 'SELECT 1 '
. $this->getLockTablesSql(null)
. ' WHERE ' . $this->getSelectConditionSQL($criteria);
list($params, $types) = $this->expandParameters($criteria);
if (null !== $extraConditions) {
$sql .= ' AND ' . $this->getSelectConditionCriteriaSQL($extraConditions);
list($criteriaParams, $criteriaTypes) = $this->expandCriteriaParameters($extraConditions);
$params = array_merge($params, $criteriaParams);
$types = array_merge($types, $criteriaTypes);
}
if ($filterSql = $this->generateFilterConditionSQL($this->class, $alias)) {
$sql .= ' AND ' . $filterSql;
}
return (bool) $this->conn->fetchColumn($sql, $params, 0, $types);
}
/**
* Generates the appropriate join SQL for the given join column.
*
* @param array $joinColumns The join columns definition of an association.
*
* @return string LEFT JOIN if one of the columns is nullable, INNER JOIN otherwise.
*/
protected function getJoinSQLForJoinColumns($joinColumns)
{
// if one of the join columns is nullable, return left join
foreach ($joinColumns as $joinColumn) {
if ( ! isset($joinColumn['nullable']) || $joinColumn['nullable']) {
return 'LEFT JOIN';
}
}
return 'INNER JOIN';
}
/**
* {@inheritdoc}
*/
public function getSQLColumnAlias($columnName)
{
return $this->quoteStrategy->getColumnAlias($columnName, $this->currentPersisterContext->sqlAliasCounter++, $this->platform);
}
/**
* Generates the filter SQL for a given entity and table alias.
*
* @param ClassMetadata $targetEntity Metadata of the target entity.
* @param string $targetTableAlias The table alias of the joined/selected table.
*
* @return string The SQL query part to add to a query.
*/
protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias)
{
$filterClauses = array();
foreach ($this->em->getFilters()->getEnabledFilters() as $filter) {
if ('' !== $filterExpr = $filter->addFilterConstraint($targetEntity, $targetTableAlias)) {
$filterClauses[] = '(' . $filterExpr . ')';
}
}
$sql = implode(' AND ', $filterClauses);
return $sql ? "(" . $sql . ")" : ""; // Wrap again to avoid "X or Y and FilterConditionSQL"
}
/**
* Switches persister context according to current query offset/limits
*
* This is due to the fact that to-many associations cannot be fetch-joined when a limit is involved
*
* @param null|int $offset
* @param null|int $limit
*/
protected function switchPersisterContext($offset, $limit)
{
if (null === $offset && null === $limit) {
$this->currentPersisterContext = $this->noLimitsContext;
return;
}
$this->currentPersisterContext = $this->limitsHandlingContext;
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Persisters/Entity/CachedPersisterContext.php 0000664 0000000 0000000 00000006272 13215356457 0027235 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Persisters\Entity;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\ORM\Query\ResultSetMapping;
/**
* A swappable persister context to use as a container for the current
* generated query/resultSetMapping/type binding information.
*
* This class is a utility class to be used only by the persister API
*
* This object is highly mutable due to performance reasons. Same reasoning
* behind its properties being public.
*
* @author Marco Pivetta
*/
class CachedPersisterContext
{
/**
* Metadata object that describes the mapping of the mapped entity class.
*
* @var \Doctrine\ORM\Mapping\ClassMetadata
*/
public $class;
/**
* ResultSetMapping that is used for all queries. Is generated lazily once per request.
*
* @var \Doctrine\ORM\Query\ResultSetMapping
*/
public $rsm;
/**
* The SELECT column list SQL fragment used for querying entities by this persister.
* This SQL fragment is only generated once per request, if at all.
*
* @var string|null
*/
public $selectColumnListSql;
/**
* The JOIN SQL fragment used to eagerly load all many-to-one and one-to-one
* associations configured as FETCH_EAGER, as well as all inverse one-to-one associations.
*
* @var string
*/
public $selectJoinSql;
/**
* Counter for creating unique SQL table and column aliases.
*
* @var integer
*/
public $sqlAliasCounter = 0;
/**
* Map from class names (FQCN) to the corresponding generated SQL table aliases.
*
* @var array
*/
public $sqlTableAliases = array();
/**
* Whether this persistent context is considering limit operations applied to the selection queries
*
* @var bool
*/
public $handlesLimits;
/**
* @param ClassMetadata $class
* @param ResultSetMapping $rsm
* @param bool $handlesLimits
*/
public function __construct(
ClassMetadata $class,
ResultSetMapping $rsm,
$handlesLimits
) {
$this->class = $class;
$this->rsm = $rsm;
$this->handlesLimits = (bool) $handlesLimits;
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Persisters/Entity/EntityPersister.php 0000664 0000000 0000000 00000027313 13215356457 0025774 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Persisters\Entity;
use Doctrine\ORM\PersistentCollection;
use Doctrine\Common\Collections\Criteria;
/**
* Entity persister interface
* Define the behavior that should be implemented by all entity persisters.
*
* @author Fabio B. Silva
* @since 2.5
*/
interface EntityPersister
{
/**
* @return \Doctrine\ORM\Mapping\ClassMetadata
*/
public function getClassMetadata();
/**
* Gets the ResultSetMapping used for hydration.
*
* @return \Doctrine\ORM\Query\ResultSetMapping
*/
public function getResultSetMapping();
/**
* Get all queued inserts.
*
* @return array
*/
public function getInserts();
/**
* @TODO - It should not be here.
* But its necessary since JoinedSubclassPersister#executeInserts invoke the root persister.
*
* Gets the INSERT SQL used by the persister to persist a new entity.
*
* @return string
*/
public function getInsertSQL();
/**
* Gets the SELECT SQL to select one or more entities by a set of field criteria.
*
* @param array|\Doctrine\Common\Collections\Criteria $criteria
* @param array|null $assoc
* @param int|null $lockMode
* @param int|null $limit
* @param int|null $offset
* @param array|null $orderBy
*
* @return string
*/
public function getSelectSQL($criteria, $assoc = null, $lockMode = null, $limit = null, $offset = null, array $orderBy = null);
/**
* Get the COUNT SQL to count entities (optionally based on a criteria)
*
* @param array|\Doctrine\Common\Collections\Criteria $criteria
* @return string
*/
public function getCountSQL($criteria = array());
/**
* Expands the parameters from the given criteria and use the correct binding types if found.
*
* @param $criteria
*
* @return array
*/
public function expandParameters($criteria);
/**
* Expands Criteria Parameters by walking the expressions and grabbing all parameters and types from it.
*
* @param \Doctrine\Common\Collections\Criteria $criteria
*
* @return array
*/
public function expandCriteriaParameters(Criteria $criteria);
/**
* Gets the SQL WHERE condition for matching a field with a given value.
*
* @param string $field
* @param mixed $value
* @param array|null $assoc
* @param string|null $comparison
*
* @return string
*/
public function getSelectConditionStatementSQL($field, $value, $assoc = null, $comparison = null);
/**
* Adds an entity to the queued insertions.
* The entity remains queued until {@link executeInserts} is invoked.
*
* @param object $entity The entity to queue for insertion.
*
* @return void
*/
public function addInsert($entity);
/**
* Executes all queued entity insertions and returns any generated post-insert
* identifiers that were created as a result of the insertions.
*
* If no inserts are queued, invoking this method is a NOOP.
*
* @return array An array of any generated post-insert IDs. This will be an empty array
* if the entity class does not use the IDENTITY generation strategy.
*/
public function executeInserts();
/**
* Updates a managed entity. The entity is updated according to its current changeset
* in the running UnitOfWork. If there is no changeset, nothing is updated.
*
* @param object $entity The entity to update.
*
* @return void
*/
public function update($entity);
/**
* Deletes a managed entity.
*
* The entity to delete must be managed and have a persistent identifier.
* The deletion happens instantaneously.
*
* Subclasses may override this method to customize the semantics of entity deletion.
*
* @param object $entity The entity to delete.
*
* @return bool TRUE if the entity got deleted in the database, FALSE otherwise.
*/
public function delete($entity);
/**
* Count entities (optionally filtered by a criteria)
*
* @param array|\Doctrine\Common\Collections\Criteria $criteria
*
* @return int
*/
public function count($criteria = array());
/**
* Gets the name of the table that owns the column the given field is mapped to.
*
* The default implementation in BasicEntityPersister always returns the name
* of the table the entity type of this persister is mapped to, since an entity
* is always persisted to a single table with a BasicEntityPersister.
*
* @param string $fieldName The field name.
*
* @return string The table name.
*/
public function getOwningTable($fieldName);
/**
* Loads an entity by a list of field criteria.
*
* @param array $criteria The criteria by which to load the entity.
* @param object|null $entity The entity to load the data into. If not specified, a new entity is created.
* @param array|null $assoc The association that connects the entity to load to another entity, if any.
* @param array $hints Hints for entity creation.
* @param int|null $lockMode One of the \Doctrine\DBAL\LockMode::* constants
* or NULL if no specific lock mode should be used
* for loading the entity.
* @param int|null $limit Limit number of results.
* @param array|null $orderBy Criteria to order by.
*
* @return object|null The loaded and managed entity instance or NULL if the entity can not be found.
*
* @todo Check identity map? loadById method? Try to guess whether $criteria is the id?
*/
public function load(array $criteria, $entity = null, $assoc = null, array $hints = array(), $lockMode = null, $limit = null, array $orderBy = null);
/**
* Loads an entity by identifier.
*
* @param array $identifier The entity identifier.
* @param object|null $entity The entity to load the data into. If not specified, a new entity is created.
*
* @return object The loaded and managed entity instance or NULL if the entity can not be found.
*
* @todo Check parameters
*/
public function loadById(array $identifier, $entity = null);
/**
* Loads an entity of this persister's mapped class as part of a single-valued
* association from another entity.
*
* @param array $assoc The association to load.
* @param object $sourceEntity The entity that owns the association (not necessarily the "owning side").
* @param array $identifier The identifier of the entity to load. Must be provided if
* the association to load represents the owning side, otherwise
* the identifier is derived from the $sourceEntity.
*
* @return object The loaded and managed entity instance or NULL if the entity can not be found.
*
* @throws \Doctrine\ORM\Mapping\MappingException
*/
public function loadOneToOneEntity(array $assoc, $sourceEntity, array $identifier = array());
/**
* Refreshes a managed entity.
*
* @param array $id The identifier of the entity as an associative array from
* column or field names to values.
* @param object $entity The entity to refresh.
* @param int|null $lockMode One of the \Doctrine\DBAL\LockMode::* constants
* or NULL if no specific lock mode should be used
* for refreshing the managed entity.
*
* @return void
*/
public function refresh(array $id, $entity, $lockMode = null);
/**
* Loads Entities matching the given Criteria object.
*
* @param \Doctrine\Common\Collections\Criteria $criteria
*
* @return array
*/
public function loadCriteria(Criteria $criteria);
/**
* Loads a list of entities by a list of field criteria.
*
* @param array $criteria
* @param array|null $orderBy
* @param int|null $limit
* @param int|null $offset
*
* @return array
*/
public function loadAll(array $criteria = array(), array $orderBy = null, $limit = null, $offset = null);
/**
* Gets (sliced or full) elements of the given collection.
*
* @param array $assoc
* @param object $sourceEntity
* @param int|null $offset
* @param int|null $limit
*
* @return array
*/
public function getManyToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null);
/**
* Loads a collection of entities of a many-to-many association.
*
* @param array $assoc The association mapping of the association being loaded.
* @param object $sourceEntity The entity that owns the collection.
* @param PersistentCollection $collection The collection to fill.
*
* @return array
*/
public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $collection);
/**
* Loads a collection of entities in a one-to-many association.
*
* @param array $assoc
* @param object $sourceEntity
* @param PersistentCollection $collection The collection to load/fill.
*
* @return array
*/
public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $collection);
/**
* Locks all rows of this entity matching the given criteria with the specified pessimistic lock mode.
*
* @param array $criteria
* @param int $lockMode One of the Doctrine\DBAL\LockMode::* constants.
*
* @return void
*/
public function lock(array $criteria, $lockMode);
/**
* Returns an array with (sliced or full list) of elements in the specified collection.
*
* @param array $assoc
* @param object $sourceEntity
* @param int|null $offset
* @param int|null $limit
*
* @return array
*/
public function getOneToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null);
/**
* Checks whether the given managed entity exists in the database.
*
* @param object $entity
* @param Criteria|null $extraConditions
*
* @return boolean TRUE if the entity exists in the database, FALSE otherwise.
*/
public function exists($entity, Criteria $extraConditions = null);
}
doctrine2-2.5.14/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php 0000664 0000000 0000000 00000055463 13215356457 0027437 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Persisters\Entity;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\DBAL\LockMode;
use Doctrine\DBAL\Types\Type;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Utility\PersisterHelper;
/**
* The joined subclass persister maps a single entity instance to several tables in the
* database as it is defined by the Class Table Inheritance strategy.
*
* @author Roman Borschel
* @author Benjamin Eberlei
* @author Alexander
* @since 2.0
* @see http://martinfowler.com/eaaCatalog/classTableInheritance.html
*/
class JoinedSubclassPersister extends AbstractEntityInheritancePersister
{
/**
* Map that maps column names to the table names that own them.
* This is mainly a temporary cache, used during a single request.
*
* @var array
*/
private $owningTableMap = array();
/**
* Map of table to quoted table names.
*
* @var array
*/
private $quotedTableMap = array();
/**
* {@inheritdoc}
*/
protected function getDiscriminatorColumnTableName()
{
$class = ($this->class->name !== $this->class->rootEntityName)
? $this->em->getClassMetadata($this->class->rootEntityName)
: $this->class;
return $class->getTableName();
}
/**
* This function finds the ClassMetadata instance in an inheritance hierarchy
* that is responsible for enabling versioning.
*
* @return \Doctrine\ORM\Mapping\ClassMetadata
*/
private function getVersionedClassMetadata()
{
if (isset($this->class->fieldMappings[$this->class->versionField]['inherited'])) {
$definingClassName = $this->class->fieldMappings[$this->class->versionField]['inherited'];
return $this->em->getClassMetadata($definingClassName);
}
return $this->class;
}
/**
* Gets the name of the table that owns the column the given field is mapped to.
*
* @param string $fieldName
*
* @return string
*
* @override
*/
public function getOwningTable($fieldName)
{
if (isset($this->owningTableMap[$fieldName])) {
return $this->owningTableMap[$fieldName];
}
switch (true) {
case isset($this->class->associationMappings[$fieldName]['inherited']):
$cm = $this->em->getClassMetadata($this->class->associationMappings[$fieldName]['inherited']);
break;
case isset($this->class->fieldMappings[$fieldName]['inherited']):
$cm = $this->em->getClassMetadata($this->class->fieldMappings[$fieldName]['inherited']);
break;
default:
$cm = $this->class;
break;
}
$tableName = $cm->getTableName();
$quotedTableName = $this->quoteStrategy->getTableName($cm, $this->platform);
$this->owningTableMap[$fieldName] = $tableName;
$this->quotedTableMap[$tableName] = $quotedTableName;
return $tableName;
}
/**
* {@inheritdoc}
*/
public function executeInserts()
{
if ( ! $this->queuedInserts) {
return array();
}
$postInsertIds = array();
$idGenerator = $this->class->idGenerator;
$isPostInsertId = $idGenerator->isPostInsertGenerator();
$rootClass = ($this->class->name !== $this->class->rootEntityName)
? $this->em->getClassMetadata($this->class->rootEntityName)
: $this->class;
// Prepare statement for the root table
$rootPersister = $this->em->getUnitOfWork()->getEntityPersister($rootClass->name);
$rootTableName = $rootClass->getTableName();
$rootTableStmt = $this->conn->prepare($rootPersister->getInsertSQL());
// Prepare statements for sub tables.
$subTableStmts = array();
if ($rootClass !== $this->class) {
$subTableStmts[$this->class->getTableName()] = $this->conn->prepare($this->getInsertSQL());
}
foreach ($this->class->parentClasses as $parentClassName) {
$parentClass = $this->em->getClassMetadata($parentClassName);
$parentTableName = $parentClass->getTableName();
if ($parentClass !== $rootClass) {
$parentPersister = $this->em->getUnitOfWork()->getEntityPersister($parentClassName);
$subTableStmts[$parentTableName] = $this->conn->prepare($parentPersister->getInsertSQL());
}
}
// Execute all inserts. For each entity:
// 1) Insert on root table
// 2) Insert on sub tables
foreach ($this->queuedInserts as $entity) {
$insertData = $this->prepareInsertData($entity);
// Execute insert on root table
$paramIndex = 1;
foreach ($insertData[$rootTableName] as $columnName => $value) {
$rootTableStmt->bindValue($paramIndex++, $value, $this->columnTypes[$columnName]);
}
$rootTableStmt->execute();
if ($isPostInsertId) {
$generatedId = $idGenerator->generate($this->em, $entity);
$id = array(
$this->class->identifier[0] => $generatedId
);
$postInsertIds[] = array(
'generatedId' => $generatedId,
'entity' => $entity,
);
} else {
$id = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
}
if ($this->class->isVersioned) {
$this->assignDefaultVersionValue($entity, $id);
}
// Execute inserts on subtables.
// The order doesn't matter because all child tables link to the root table via FK.
foreach ($subTableStmts as $tableName => $stmt) {
/** @var \Doctrine\DBAL\Statement $stmt */
$paramIndex = 1;
$data = isset($insertData[$tableName])
? $insertData[$tableName]
: array();
foreach ((array) $id as $idName => $idVal) {
$type = isset($this->columnTypes[$idName]) ? $this->columnTypes[$idName] : Type::STRING;
$stmt->bindValue($paramIndex++, $idVal, $type);
}
foreach ($data as $columnName => $value) {
if (!is_array($id) || !isset($id[$columnName])) {
$stmt->bindValue($paramIndex++, $value, $this->columnTypes[$columnName]);
}
}
$stmt->execute();
}
}
$rootTableStmt->closeCursor();
foreach ($subTableStmts as $stmt) {
$stmt->closeCursor();
}
$this->queuedInserts = array();
return $postInsertIds;
}
/**
* {@inheritdoc}
*/
public function update($entity)
{
$updateData = $this->prepareUpdateData($entity);
if ( ! $updateData) {
return;
}
if (($isVersioned = $this->class->isVersioned) === false) {
return;
}
$versionedClass = $this->getVersionedClassMetadata();
$versionedTable = $versionedClass->getTableName();
foreach ($updateData as $tableName => $data) {
$tableName = $this->quotedTableMap[$tableName];
$versioned = $isVersioned && $versionedTable === $tableName;
$this->updateTable($entity, $tableName, $data, $versioned);
}
// Make sure the table with the version column is updated even if no columns on that
// table were affected.
if ($isVersioned) {
if ( ! isset($updateData[$versionedTable])) {
$tableName = $this->quoteStrategy->getTableName($versionedClass, $this->platform);
$this->updateTable($entity, $tableName, array(), true);
}
$identifiers = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
$this->assignDefaultVersionValue($entity, $identifiers);
}
}
/**
* {@inheritdoc}
*/
public function delete($entity)
{
$identifier = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
$id = array_combine($this->class->getIdentifierColumnNames(), $identifier);
$this->deleteJoinTableRecords($identifier);
// If the database platform supports FKs, just
// delete the row from the root table. Cascades do the rest.
if ($this->platform->supportsForeignKeyConstraints()) {
$rootClass = $this->em->getClassMetadata($this->class->rootEntityName);
$rootTable = $this->quoteStrategy->getTableName($rootClass, $this->platform);
return (bool) $this->conn->delete($rootTable, $id);
}
// Delete from all tables individually, starting from this class' table up to the root table.
$rootTable = $this->quoteStrategy->getTableName($this->class, $this->platform);
$affectedRows = $this->conn->delete($rootTable, $id);
foreach ($this->class->parentClasses as $parentClass) {
$parentMetadata = $this->em->getClassMetadata($parentClass);
$parentTable = $this->quoteStrategy->getTableName($parentMetadata, $this->platform);
$this->conn->delete($parentTable, $id);
}
return (bool) $affectedRows;
}
/**
* {@inheritdoc}
*/
public function getSelectSQL($criteria, $assoc = null, $lockMode = null, $limit = null, $offset = null, array $orderBy = null)
{
$this->switchPersisterContext($offset, $limit);
$baseTableAlias = $this->getSQLTableAlias($this->class->name);
$joinSql = $this->getJoinSql($baseTableAlias);
if ($assoc != null && $assoc['type'] == ClassMetadata::MANY_TO_MANY) {
$joinSql .= $this->getSelectManyToManyJoinSQL($assoc);
}
$conditionSql = ($criteria instanceof Criteria)
? $this->getSelectConditionCriteriaSQL($criteria)
: $this->getSelectConditionSQL($criteria, $assoc);
// If the current class in the root entity, add the filters
if ($filterSql = $this->generateFilterConditionSQL($this->em->getClassMetadata($this->class->rootEntityName), $this->getSQLTableAlias($this->class->rootEntityName))) {
$conditionSql .= $conditionSql
? ' AND ' . $filterSql
: $filterSql;
}
$orderBySql = '';
if ($assoc !== null && isset($assoc['orderBy'])) {
$orderBy = $assoc['orderBy'];
}
if ($orderBy) {
$orderBySql = $this->getOrderBySQL($orderBy, $baseTableAlias);
}
$lockSql = '';
switch ($lockMode) {
case LockMode::PESSIMISTIC_READ:
$lockSql = ' ' . $this->platform->getReadLockSql();
break;
case LockMode::PESSIMISTIC_WRITE:
$lockSql = ' ' . $this->platform->getWriteLockSql();
break;
}
$tableName = $this->quoteStrategy->getTableName($this->class, $this->platform);
$from = ' FROM ' . $tableName . ' ' . $baseTableAlias;
$where = $conditionSql != '' ? ' WHERE ' . $conditionSql : '';
$lock = $this->platform->appendLockHint($from, $lockMode);
$columnList = $this->getSelectColumnsSQL();
$query = 'SELECT ' . $columnList
. $lock
. $joinSql
. $where
. $orderBySql;
return $this->platform->modifyLimitQuery($query, $limit, $offset) . $lockSql;
}
/**
* {@inheritDoc}
*/
public function getCountSQL($criteria = array())
{
$tableName = $this->quoteStrategy->getTableName($this->class, $this->platform);
$baseTableAlias = $this->getSQLTableAlias($this->class->name);
$joinSql = $this->getJoinSql($baseTableAlias);
$conditionSql = ($criteria instanceof Criteria)
? $this->getSelectConditionCriteriaSQL($criteria)
: $this->getSelectConditionSQL($criteria);
$filterSql = $this->generateFilterConditionSQL($this->em->getClassMetadata($this->class->rootEntityName), $this->getSQLTableAlias($this->class->rootEntityName));
if ('' !== $filterSql) {
$conditionSql = $conditionSql
? $conditionSql . ' AND ' . $filterSql
: $filterSql;
}
$sql = 'SELECT COUNT(*) '
. 'FROM ' . $tableName . ' ' . $baseTableAlias
. $joinSql
. (empty($conditionSql) ? '' : ' WHERE ' . $conditionSql);
return $sql;
}
/**
* {@inheritdoc}
*/
protected function getLockTablesSql($lockMode)
{
$joinSql = '';
$identifierColumns = $this->class->getIdentifierColumnNames();
$baseTableAlias = $this->getSQLTableAlias($this->class->name);
// INNER JOIN parent tables
foreach ($this->class->parentClasses as $parentClassName) {
$conditions = array();
$tableAlias = $this->getSQLTableAlias($parentClassName);
$parentClass = $this->em->getClassMetadata($parentClassName);
$joinSql .= ' INNER JOIN ' . $this->quoteStrategy->getTableName($parentClass, $this->platform) . ' ' . $tableAlias . ' ON ';
foreach ($identifierColumns as $idColumn) {
$conditions[] = $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
}
$joinSql .= implode(' AND ', $conditions);
}
return parent::getLockTablesSql($lockMode) . $joinSql;
}
/**
* Ensure this method is never called. This persister overrides getSelectEntitiesSQL directly.
*
* @return string
*/
protected function getSelectColumnsSQL()
{
// Create the column list fragment only once
if ($this->currentPersisterContext->selectColumnListSql !== null) {
return $this->currentPersisterContext->selectColumnListSql;
}
$columnList = array();
$discrColumn = $this->class->discriminatorColumn['name'];
$baseTableAlias = $this->getSQLTableAlias($this->class->name);
$resultColumnName = $this->platform->getSQLResultCasing($discrColumn);
$this->currentPersisterContext->rsm->addEntityResult($this->class->name, 'r');
$this->currentPersisterContext->rsm->setDiscriminatorColumn('r', $resultColumnName);
$this->currentPersisterContext->rsm->addMetaResult('r', $resultColumnName, $discrColumn);
// Add regular columns
foreach ($this->class->fieldMappings as $fieldName => $mapping) {
$class = isset($mapping['inherited'])
? $this->em->getClassMetadata($mapping['inherited'])
: $this->class;
$columnList[] = $this->getSelectColumnSQL($fieldName, $class);
}
// Add foreign key columns
foreach ($this->class->associationMappings as $mapping) {
if ( ! $mapping['isOwningSide'] || ! ($mapping['type'] & ClassMetadata::TO_ONE)) {
continue;
}
$tableAlias = isset($mapping['inherited'])
? $this->getSQLTableAlias($mapping['inherited'])
: $baseTableAlias;
foreach ($mapping['targetToSourceKeyColumns'] as $srcColumn) {
$className = isset($mapping['inherited'])
? $mapping['inherited']
: $this->class->name;
$targetClass = $this->em->getClassMetadata($mapping['targetEntity']);
$columnList[] = $this->getSelectJoinColumnSQL(
$tableAlias,
$srcColumn,
$className,
PersisterHelper::getTypeOfColumn(
$mapping['sourceToTargetKeyColumns'][$srcColumn],
$targetClass,
$this->em
)
);
}
}
// Add discriminator column (DO NOT ALIAS, see AbstractEntityInheritancePersister#processSQLResult).
$tableAlias = ($this->class->rootEntityName == $this->class->name)
? $baseTableAlias
: $this->getSQLTableAlias($this->class->rootEntityName);
$columnList[] = $tableAlias . '.' . $discrColumn;
// sub tables
foreach ($this->class->subClasses as $subClassName) {
$subClass = $this->em->getClassMetadata($subClassName);
$tableAlias = $this->getSQLTableAlias($subClassName);
// Add subclass columns
foreach ($subClass->fieldMappings as $fieldName => $mapping) {
if (isset($mapping['inherited'])) {
continue;
}
$columnList[] = $this->getSelectColumnSQL($fieldName, $subClass);
}
// Add join columns (foreign keys)
foreach ($subClass->associationMappings as $mapping) {
if ( ! $mapping['isOwningSide']
|| ! ($mapping['type'] & ClassMetadata::TO_ONE)
|| isset($mapping['inherited'])) {
continue;
}
foreach ($mapping['targetToSourceKeyColumns'] as $srcColumn) {
$className = isset($mapping['inherited'])
? $mapping['inherited']
: $subClass->name;
$targetClass = $this->em->getClassMetadata($mapping['targetEntity']);
$columnList[] = $this->getSelectJoinColumnSQL(
$tableAlias,
$srcColumn,
$className,
PersisterHelper::getTypeOfColumn(
$mapping['sourceToTargetKeyColumns'][$srcColumn],
$targetClass,
$this->em
)
);
}
}
}
$this->currentPersisterContext->selectColumnListSql = implode(', ', $columnList);
return $this->currentPersisterContext->selectColumnListSql;
}
/**
* {@inheritdoc}
*/
protected function getInsertColumnList()
{
// Identifier columns must always come first in the column list of subclasses.
$columns = $this->class->parentClasses
? $this->class->getIdentifierColumnNames()
: array();
foreach ($this->class->reflFields as $name => $field) {
if (isset($this->class->fieldMappings[$name]['inherited'])
&& ! isset($this->class->fieldMappings[$name]['id'])
|| isset($this->class->associationMappings[$name]['inherited'])
|| ($this->class->isVersioned && $this->class->versionField == $name)
|| isset($this->class->embeddedClasses[$name])) {
continue;
}
if (isset($this->class->associationMappings[$name])) {
$assoc = $this->class->associationMappings[$name];
if ($assoc['type'] & ClassMetadata::TO_ONE && $assoc['isOwningSide']) {
foreach ($assoc['targetToSourceKeyColumns'] as $sourceCol) {
$columns[] = $sourceCol;
}
}
} else if ($this->class->name != $this->class->rootEntityName ||
! $this->class->isIdGeneratorIdentity() || $this->class->identifier[0] != $name) {
$columns[] = $this->quoteStrategy->getColumnName($name, $this->class, $this->platform);
$this->columnTypes[$name] = $this->class->fieldMappings[$name]['type'];
}
}
// Add discriminator column if it is the topmost class.
if ($this->class->name == $this->class->rootEntityName) {
$columns[] = $this->class->discriminatorColumn['name'];
}
return $columns;
}
/**
* {@inheritdoc}
*/
protected function assignDefaultVersionValue($entity, array $id)
{
$value = $this->fetchVersionValue($this->getVersionedClassMetadata(), $id);
$this->class->setFieldValue($entity, $this->class->versionField, $value);
}
/**
* @param string $baseTableAlias
* @return string
*/
private function getJoinSql($baseTableAlias)
{
$joinSql = '';
$identifierColumn = $this->class->getIdentifierColumnNames();
// INNER JOIN parent tables
foreach ($this->class->parentClasses as $parentClassName) {
$conditions = array();
$parentClass = $this->em->getClassMetadata($parentClassName);
$tableAlias = $this->getSQLTableAlias($parentClassName);
$joinSql .= ' INNER JOIN ' . $this->quoteStrategy->getTableName($parentClass, $this->platform) . ' ' . $tableAlias . ' ON ';
foreach ($identifierColumn as $idColumn) {
$conditions[] = $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
}
$joinSql .= implode(' AND ', $conditions);
}
// OUTER JOIN sub tables
foreach ($this->class->subClasses as $subClassName) {
$conditions = array();
$subClass = $this->em->getClassMetadata($subClassName);
$tableAlias = $this->getSQLTableAlias($subClassName);
$joinSql .= ' LEFT JOIN ' . $this->quoteStrategy->getTableName($subClass, $this->platform) . ' ' . $tableAlias . ' ON ';
foreach ($identifierColumn as $idColumn) {
$conditions[] = $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
}
$joinSql .= implode(' AND ', $conditions);
}
return $joinSql;
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Persisters/Entity/SingleTablePersister.php 0000664 0000000 0000000 00000015245 13215356457 0026712 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Persisters\Entity;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Utility\PersisterHelper;
/**
* Persister for entities that participate in a hierarchy mapped with the
* SINGLE_TABLE strategy.
*
* @author Roman Borschel
* @author Benjamin Eberlei
* @author Alexander
* @since 2.0
* @link http://martinfowler.com/eaaCatalog/singleTableInheritance.html
*/
class SingleTablePersister extends AbstractEntityInheritancePersister
{
/**
* {@inheritdoc}
*/
protected function getDiscriminatorColumnTableName()
{
return $this->class->getTableName();
}
/**
* {@inheritdoc}
*/
protected function getSelectColumnsSQL()
{
if ($this->currentPersisterContext->selectColumnListSql !== null) {
return $this->currentPersisterContext->selectColumnListSql;
}
$columnList[] = parent::getSelectColumnsSQL();
$rootClass = $this->em->getClassMetadata($this->class->rootEntityName);
$tableAlias = $this->getSQLTableAlias($rootClass->name);
// Append discriminator column
$discrColumn = $this->class->discriminatorColumn['name'];
$columnList[] = $tableAlias . '.' . $discrColumn;
$resultColumnName = $this->platform->getSQLResultCasing($discrColumn);
$this->currentPersisterContext->rsm->setDiscriminatorColumn('r', $resultColumnName);
$this->currentPersisterContext->rsm->addMetaResult('r', $resultColumnName, $discrColumn);
// Append subclass columns
foreach ($this->class->subClasses as $subClassName) {
$subClass = $this->em->getClassMetadata($subClassName);
// Regular columns
foreach ($subClass->fieldMappings as $fieldName => $mapping) {
if (isset($mapping['inherited'])) {
continue;
}
$columnList[] = $this->getSelectColumnSQL($fieldName, $subClass);
}
// Foreign key columns
foreach ($subClass->associationMappings as $assoc) {
if ( ! $assoc['isOwningSide']
|| ! ($assoc['type'] & ClassMetadata::TO_ONE)
|| isset($assoc['inherited'])) {
continue;
}
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
$className = isset($assoc['inherited']) ? $assoc['inherited'] : $this->class->name;
$targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
$columnList[] = $this->getSelectJoinColumnSQL(
$tableAlias,
$srcColumn,
$className,
PersisterHelper::getTypeOfColumn(
$assoc['sourceToTargetKeyColumns'][$srcColumn],
$targetClass,
$this->em
)
);
}
}
}
$this->currentPersisterContext->selectColumnListSql = implode(', ', $columnList);
return $this->currentPersisterContext->selectColumnListSql;
}
/**
* {@inheritdoc}
*/
protected function getInsertColumnList()
{
$columns = parent::getInsertColumnList();
// Add discriminator column to the INSERT SQL
$columns[] = $this->class->discriminatorColumn['name'];
return $columns;
}
/**
* {@inheritdoc}
*/
protected function getSQLTableAlias($className, $assocName = '')
{
return parent::getSQLTableAlias($this->class->rootEntityName, $assocName);
}
/**
* {@inheritdoc}
*/
protected function getSelectConditionSQL(array $criteria, $assoc = null)
{
$conditionSql = parent::getSelectConditionSQL($criteria, $assoc);
if ($conditionSql) {
$conditionSql .= ' AND ';
}
return $conditionSql . $this->getSelectConditionDiscriminatorValueSQL();
}
/**
* {@inheritdoc}
*/
protected function getSelectConditionCriteriaSQL(Criteria $criteria)
{
$conditionSql = parent::getSelectConditionCriteriaSQL($criteria);
if ($conditionSql) {
$conditionSql .= ' AND ';
}
return $conditionSql . $this->getSelectConditionDiscriminatorValueSQL();
}
/**
* @return string
*/
protected function getSelectConditionDiscriminatorValueSQL()
{
$values = array();
if ($this->class->discriminatorValue !== null) { // discriminators can be 0
$values[] = $this->conn->quote($this->class->discriminatorValue);
}
$discrValues = array_flip($this->class->discriminatorMap);
foreach ($this->class->subClasses as $subclassName) {
$values[] = $this->conn->quote($discrValues[$subclassName]);
}
$values = implode(', ', $values);
$discColumn = $this->class->discriminatorColumn['name'];
$tableAlias = $this->getSQLTableAlias($this->class->name);
return $tableAlias . '.' . $discColumn . ' IN (' . $values . ')';
}
/**
* {@inheritdoc}
*/
protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias)
{
// Ensure that the filters are applied to the root entity of the inheritance tree
$targetEntity = $this->em->getClassMetadata($targetEntity->rootEntityName);
// we don't care about the $targetTableAlias, in a STI there is only one table.
return parent::generateFilterConditionSQL($targetEntity, $targetTableAlias);
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Persisters/PersisterException.php 0000664 0000000 0000000 00000001060 13215356457 0025171 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Persisters;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\Common\Collections\Expr\ExpressionVisitor;
use Doctrine\Common\Collections\Expr\Comparison;
use Doctrine\Common\Collections\Expr\Value;
use Doctrine\Common\Collections\Expr\CompositeExpression;
use Doctrine\ORM\Persisters\Entity\BasicEntityPersister;
/**
* Visit Expressions and generate SQL WHERE conditions from them.
*
* @author Benjamin Eberlei
* @since 2.3
*/
class SqlExpressionVisitor extends ExpressionVisitor
{
/**
* @var \Doctrine\ORM\Persisters\Entity\BasicEntityPersister
*/
private $persister;
/**
* @var \Doctrine\ORM\Mapping\ClassMetadata
*/
private $classMetadata;
/**
* @param \Doctrine\ORM\Persisters\Entity\BasicEntityPersister $persister
* @param \Doctrine\ORM\Mapping\ClassMetadata $classMetadata
*/
public function __construct(BasicEntityPersister $persister, ClassMetadata $classMetadata)
{
$this->persister = $persister;
$this->classMetadata = $classMetadata;
}
/**
* Converts a comparison expression into the target query language output.
*
* @param \Doctrine\Common\Collections\Expr\Comparison $comparison
*
* @return mixed
*/
public function walkComparison(Comparison $comparison)
{
$field = $comparison->getField();
$value = $comparison->getValue()->getValue(); // shortcut for walkValue()
if (isset($this->classMetadata->associationMappings[$field]) &&
$value !== null &&
! is_object($value) &&
! in_array($comparison->getOperator(), array(Comparison::IN, Comparison::NIN))) {
throw PersisterException::matchingAssocationFieldRequiresObject($this->classMetadata->name, $field);
}
return $this->persister->getSelectConditionStatementSQL($field, $value, null, $comparison->getOperator());
}
/**
* Converts a composite expression into the target query language output.
*
* @param \Doctrine\Common\Collections\Expr\CompositeExpression $expr
*
* @return mixed
*
* @throws \RuntimeException
*/
public function walkCompositeExpression(CompositeExpression $expr)
{
$expressionList = array();
foreach ($expr->getExpressionList() as $child) {
$expressionList[] = $this->dispatch($child);
}
switch($expr->getType()) {
case CompositeExpression::TYPE_AND:
return '(' . implode(' AND ', $expressionList) . ')';
case CompositeExpression::TYPE_OR:
return '(' . implode(' OR ', $expressionList) . ')';
default:
throw new \RuntimeException("Unknown composite " . $expr->getType());
}
}
/**
* Converts a value expression into the target query language part.
*
* @param \Doctrine\Common\Collections\Expr\Value $value
*
* @return mixed
*/
public function walkValue(Value $value)
{
return '?';
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Persisters/SqlValueVisitor.php 0000664 0000000 0000000 00000007170 13215356457 0024456 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Persisters;
use Doctrine\Common\Collections\Expr\ExpressionVisitor;
use Doctrine\Common\Collections\Expr\Comparison;
use Doctrine\Common\Collections\Expr\Value;
use Doctrine\Common\Collections\Expr\CompositeExpression;
/**
* Extract the values from a criteria/expression
*
* @author Benjamin Eberlei
*/
class SqlValueVisitor extends ExpressionVisitor
{
/**
* @var array
*/
private $values = array();
/**
* @var array
*/
private $types = array();
/**
* Converts a comparison expression into the target query language output.
*
* @param \Doctrine\Common\Collections\Expr\Comparison $comparison
*
* @return mixed
*/
public function walkComparison(Comparison $comparison)
{
$value = $this->getValueFromComparison($comparison);
$field = $comparison->getField();
$operator = $comparison->getOperator();
if (($operator === Comparison::EQ || $operator === Comparison::IS) && $value === null) {
return;
} else if ($operator === Comparison::NEQ && $value === null) {
return;
}
$this->values[] = $value;
$this->types[] = array($field, $value, $operator);
}
/**
* Converts a composite expression into the target query language output.
*
* @param \Doctrine\Common\Collections\Expr\CompositeExpression $expr
*
* @return mixed
*/
public function walkCompositeExpression(CompositeExpression $expr)
{
foreach ($expr->getExpressionList() as $child) {
$this->dispatch($child);
}
}
/**
* Converts a value expression into the target query language part.
*
* @param \Doctrine\Common\Collections\Expr\Value $value
*
* @return mixed
*/
public function walkValue(Value $value)
{
return;
}
/**
* Returns the Parameters and Types necessary for matching the last visited expression.
*
* @return array
*/
public function getParamsAndTypes()
{
return array($this->values, $this->types);
}
/**
* Returns the value from a Comparison. In case of a CONTAINS comparison,
* the value is wrapped in %-signs, because it will be used in a LIKE clause.
*
* @param \Doctrine\Common\Collections\Expr\Comparison $comparison
* @return mixed
*/
protected function getValueFromComparison(Comparison $comparison)
{
$value = $comparison->getValue()->getValue();
return $comparison->getOperator() == Comparison::CONTAINS
? "%{$value}%"
: $value;
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/PessimisticLockException.php 0000664 0000000 0000000 00000002757 13215356457 0024171 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM;
/**
* Pessimistic Lock Exception
*
* @license http://www.opensource.org/licenses/mit-license.php MIT
* @link www.doctrine-project.com
* @since 1.0
* @author Benjamin Eberlei
* @author Roman Borschel
*/
class PessimisticLockException extends ORMException
{
/**
* @return PessimisticLockException
*/
public static function lockFailed()
{
return new self("The pessimistic lock failed.");
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Proxy/ 0000775 0000000 0000000 00000000000 13215356457 0017602 5 ustar 00root root 0000000 0000000 doctrine2-2.5.14/lib/Doctrine/ORM/Proxy/Autoloader.php 0000664 0000000 0000000 00000002246 13215356457 0022416 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Proxy;
use Doctrine\Common\Proxy\Autoloader as BaseAutoloader;
/**
* @deprecated use \Doctrine\Common\Proxy\Autoloader instead
*/
class Autoloader extends BaseAutoloader
{
}
doctrine2-2.5.14/lib/Doctrine/ORM/Proxy/Proxy.php 0000664 0000000 0000000 00000002275 13215356457 0021442 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Proxy;
use Doctrine\Common\Proxy\Proxy as BaseProxy;
/**
* Interface for proxy classes.
*
* @author Roman Borschel
* @since 2.0
*/
interface Proxy extends BaseProxy
{
}
doctrine2-2.5.14/lib/Doctrine/ORM/Proxy/ProxyFactory.php 0000664 0000000 0000000 00000022111 13215356457 0022761 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Proxy;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\Common\Proxy\AbstractProxyFactory;
use Doctrine\Common\Proxy\Proxy as BaseProxy;
use Doctrine\Common\Proxy\ProxyDefinition;
use Doctrine\Common\Proxy\ProxyGenerator;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Persisters\Entity\EntityPersister;
use Doctrine\ORM\EntityNotFoundException;
use Doctrine\ORM\Utility\IdentifierFlattener;
/**
* This factory is used to create proxy objects for entities at runtime.
*
* @author Roman Borschel
* @author Giorgio Sironi
* @author Marco Pivetta
* @since 2.0
*/
class ProxyFactory extends AbstractProxyFactory
{
/**
* @var EntityManagerInterface The EntityManager this factory is bound to.
*/
private $em;
/**
* @var \Doctrine\ORM\UnitOfWork The UnitOfWork this factory uses to retrieve persisters
*/
private $uow;
/**
* @var string
*/
private $proxyNs;
/**
* The IdentifierFlattener used for manipulating identifiers
*
* @var \Doctrine\ORM\Utility\IdentifierFlattener
*/
private $identifierFlattener;
/**
* Initializes a new instance of the ProxyFactory class that is
* connected to the given EntityManager.
*
* @param EntityManagerInterface $em The EntityManager the new factory works for.
* @param string $proxyDir The directory to use for the proxy classes. It must exist.
* @param string $proxyNs The namespace to use for the proxy classes.
* @param boolean|int $autoGenerate The strategy for automatically generating proxy classes. Possible
* values are constants of Doctrine\Common\Proxy\AbstractProxyFactory.
*/
public function __construct(EntityManagerInterface $em, $proxyDir, $proxyNs, $autoGenerate = AbstractProxyFactory::AUTOGENERATE_NEVER)
{
$proxyGenerator = new ProxyGenerator($proxyDir, $proxyNs);
$proxyGenerator->setPlaceholder('baseProxyInterface', 'Doctrine\ORM\Proxy\Proxy');
parent::__construct($proxyGenerator, $em->getMetadataFactory(), $autoGenerate);
$this->em = $em;
$this->uow = $em->getUnitOfWork();
$this->proxyNs = $proxyNs;
$this->identifierFlattener = new IdentifierFlattener($this->uow, $em->getMetadataFactory());
}
/**
* {@inheritDoc}
*/
protected function skipClass(ClassMetadata $metadata)
{
/* @var $metadata \Doctrine\ORM\Mapping\ClassMetadataInfo */
return $metadata->isMappedSuperclass
|| $metadata->isEmbeddedClass
|| $metadata->getReflectionClass()->isAbstract();
}
/**
* {@inheritDoc}
*/
protected function createProxyDefinition($className)
{
$classMetadata = $this->em->getClassMetadata($className);
$entityPersister = $this->uow->getEntityPersister($className);
return new ProxyDefinition(
ClassUtils::generateProxyClassName($className, $this->proxyNs),
$classMetadata->getIdentifierFieldNames(),
$classMetadata->getReflectionProperties(),
$this->createInitializer($classMetadata, $entityPersister),
$this->createCloner($classMetadata, $entityPersister)
);
}
/**
* Creates a closure capable of initializing a proxy
*
* @param \Doctrine\Common\Persistence\Mapping\ClassMetadata $classMetadata
* @param \Doctrine\ORM\Persisters\Entity\EntityPersister $entityPersister
*
* @return \Closure
*
* @throws \Doctrine\ORM\EntityNotFoundException
*/
private function createInitializer(ClassMetadata $classMetadata, EntityPersister $entityPersister)
{
if ($classMetadata->getReflectionClass()->hasMethod('__wakeup')) {
return function (BaseProxy $proxy) use ($entityPersister, $classMetadata) {
$initializer = $proxy->__getInitializer();
$cloner = $proxy->__getCloner();
$proxy->__setInitializer(null);
$proxy->__setCloner(null);
if ($proxy->__isInitialized()) {
return;
}
$properties = $proxy->__getLazyProperties();
foreach ($properties as $propertyName => $property) {
if ( ! isset($proxy->$propertyName)) {
$proxy->$propertyName = $properties[$propertyName];
}
}
$proxy->__setInitialized(true);
$proxy->__wakeup();
$identifier = $classMetadata->getIdentifierValues($proxy);
if (null === $entityPersister->loadById($identifier, $proxy)) {
$proxy->__setInitializer($initializer);
$proxy->__setCloner($cloner);
$proxy->__setInitialized(false);
throw EntityNotFoundException::fromClassNameAndIdentifier(
$classMetadata->getName(),
$this->identifierFlattener->flattenIdentifier($classMetadata, $identifier)
);
}
};
}
return function (BaseProxy $proxy) use ($entityPersister, $classMetadata) {
$initializer = $proxy->__getInitializer();
$cloner = $proxy->__getCloner();
$proxy->__setInitializer(null);
$proxy->__setCloner(null);
if ($proxy->__isInitialized()) {
return;
}
$properties = $proxy->__getLazyProperties();
foreach ($properties as $propertyName => $property) {
if (!isset($proxy->$propertyName)) {
$proxy->$propertyName = $properties[$propertyName];
}
}
$proxy->__setInitialized(true);
$identifier = $classMetadata->getIdentifierValues($proxy);
if (null === $entityPersister->loadById($identifier, $proxy)) {
$proxy->__setInitializer($initializer);
$proxy->__setCloner($cloner);
$proxy->__setInitialized(false);
throw EntityNotFoundException::fromClassNameAndIdentifier(
$classMetadata->getName(),
$this->identifierFlattener->flattenIdentifier($classMetadata, $identifier)
);
}
};
}
/**
* Creates a closure capable of finalizing state a cloned proxy
*
* @param \Doctrine\Common\Persistence\Mapping\ClassMetadata $classMetadata
* @param \Doctrine\ORM\Persisters\Entity\EntityPersister $entityPersister
*
* @return \Closure
*
* @throws \Doctrine\ORM\EntityNotFoundException
*/
private function createCloner(ClassMetadata $classMetadata, EntityPersister $entityPersister)
{
return function (BaseProxy $proxy) use ($entityPersister, $classMetadata) {
if ($proxy->__isInitialized()) {
return;
}
$proxy->__setInitialized(true);
$proxy->__setInitializer(null);
$class = $entityPersister->getClassMetadata();
$identifier = $classMetadata->getIdentifierValues($proxy);
$original = $entityPersister->loadById($identifier);
if (null === $original) {
throw EntityNotFoundException::fromClassNameAndIdentifier(
$classMetadata->getName(),
$this->identifierFlattener->flattenIdentifier($classMetadata, $identifier)
);
}
foreach ($class->getReflectionProperties() as $property) {
if ( ! $class->hasField($property->name) && ! $class->hasAssociation($property->name)) {
continue;
}
$property->setAccessible(true);
$property->setValue($proxy, $property->getValue($original));
}
};
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Query.php 0000664 0000000 0000000 00000046702 13215356457 0020310 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM;
use Doctrine\DBAL\LockMode;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\ParserResult;
use Doctrine\ORM\Query\QueryException;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query\ParameterTypeInferer;
use Doctrine\Common\Collections\ArrayCollection;
/**
* A Query object represents a DQL query.
*
* @since 1.0
* @author Guilherme Blanco
* @author Konsta Vesterinen
* @author Roman Borschel
*/
final class Query extends AbstractQuery
{
/**
* A query object is in CLEAN state when it has NO unparsed/unprocessed DQL parts.
*/
const STATE_CLEAN = 1;
/**
* A query object is in state DIRTY when it has DQL parts that have not yet been
* parsed/processed. This is automatically defined as DIRTY when addDqlQueryPart
* is called.
*/
const STATE_DIRTY = 2;
/* Query HINTS */
/**
* The refresh hint turns any query into a refresh query with the result that
* any local changes in entities are overridden with the fetched values.
*
* @var string
*/
const HINT_REFRESH = 'doctrine.refresh';
/**
* @var string
*/
const HINT_CACHE_ENABLED = 'doctrine.cache.enabled';
/**
* @var string
*/
const HINT_CACHE_EVICT = 'doctrine.cache.evict';
/**
* Internal hint: is set to the proxy entity that is currently triggered for loading
*
* @var string
*/
const HINT_REFRESH_ENTITY = 'doctrine.refresh.entity';
/**
* The forcePartialLoad query hint forces a particular query to return
* partial objects.
*
* @var string
* @todo Rename: HINT_OPTIMIZE
*/
const HINT_FORCE_PARTIAL_LOAD = 'doctrine.forcePartialLoad';
/**
* The includeMetaColumns query hint causes meta columns like foreign keys and
* discriminator columns to be selected and returned as part of the query result.
*
* This hint does only apply to non-object queries.
*
* @var string
*/
const HINT_INCLUDE_META_COLUMNS = 'doctrine.includeMetaColumns';
/**
* An array of class names that implement \Doctrine\ORM\Query\TreeWalker and
* are iterated and executed after the DQL has been parsed into an AST.
*
* @var string
*/
const HINT_CUSTOM_TREE_WALKERS = 'doctrine.customTreeWalkers';
/**
* A string with a class name that implements \Doctrine\ORM\Query\TreeWalker
* and is used for generating the target SQL from any DQL AST tree.
*
* @var string
*/
const HINT_CUSTOM_OUTPUT_WALKER = 'doctrine.customOutputWalker';
//const HINT_READ_ONLY = 'doctrine.readOnly';
/**
* @var string
*/
const HINT_INTERNAL_ITERATION = 'doctrine.internal.iteration';
/**
* @var string
*/
const HINT_LOCK_MODE = 'doctrine.lockMode';
/**
* The current state of this query.
*
* @var integer
*/
private $_state = self::STATE_CLEAN;
/**
* A snapshot of the parameter types the query was parsed with.
*
* @var array
*/
private $_parsedTypes = array();
/**
* Cached DQL query.
*
* @var string
*/
private $_dql = null;
/**
* The parser result that holds DQL => SQL information.
*
* @var \Doctrine\ORM\Query\ParserResult
*/
private $_parserResult;
/**
* The first result to return (the "offset").
*
* @var integer
*/
private $_firstResult = null;
/**
* The maximum number of results to return (the "limit").
*
* @var integer
*/
private $_maxResults = null;
/**
* The cache driver used for caching queries.
*
* @var \Doctrine\Common\Cache\Cache|null
*/
private $_queryCache;
/**
* Whether or not expire the query cache.
*
* @var boolean
*/
private $_expireQueryCache = false;
/**
* The query cache lifetime.
*
* @var int
*/
private $_queryCacheTTL;
/**
* Whether to use a query cache, if available. Defaults to TRUE.
*
* @var boolean
*/
private $_useQueryCache = true;
/**
* Gets the SQL query/queries that correspond to this DQL query.
*
* @return mixed The built sql query or an array of all sql queries.
*
* @override
*/
public function getSQL()
{
return $this->_parse()->getSQLExecutor()->getSQLStatements();
}
/**
* Returns the corresponding AST for this DQL query.
*
* @return \Doctrine\ORM\Query\AST\SelectStatement |
* \Doctrine\ORM\Query\AST\UpdateStatement |
* \Doctrine\ORM\Query\AST\DeleteStatement
*/
public function getAST()
{
$parser = new Parser($this);
return $parser->getAST();
}
/**
* {@inheritdoc}
*/
protected function getResultSetMapping()
{
// parse query or load from cache
if ($this->_resultSetMapping === null) {
$this->_resultSetMapping = $this->_parse()->getResultSetMapping();
}
return $this->_resultSetMapping;
}
/**
* Parses the DQL query, if necessary, and stores the parser result.
*
* Note: Populates $this->_parserResult as a side-effect.
*
* @return \Doctrine\ORM\Query\ParserResult
*/
private function _parse()
{
$types = array();
foreach ($this->parameters as $parameter) {
/** @var Query\Parameter $parameter */
$types[$parameter->getName()] = $parameter->getType();
}
// Return previous parser result if the query and the filter collection are both clean
if ($this->_state === self::STATE_CLEAN && $this->_parsedTypes === $types && $this->_em->isFiltersStateClean()) {
return $this->_parserResult;
}
$this->_state = self::STATE_CLEAN;
$this->_parsedTypes = $types;
// Check query cache.
if ( ! ($this->_useQueryCache && ($queryCache = $this->getQueryCacheDriver()))) {
$parser = new Parser($this);
$this->_parserResult = $parser->parse();
return $this->_parserResult;
}
$hash = $this->_getQueryCacheId();
$cached = $this->_expireQueryCache ? false : $queryCache->fetch($hash);
if ($cached instanceof ParserResult) {
// Cache hit.
$this->_parserResult = $cached;
return $this->_parserResult;
}
// Cache miss.
$parser = new Parser($this);
$this->_parserResult = $parser->parse();
$queryCache->save($hash, $this->_parserResult, $this->_queryCacheTTL);
return $this->_parserResult;
}
/**
* {@inheritdoc}
*/
protected function _doExecute()
{
$executor = $this->_parse()->getSqlExecutor();
if ($this->_queryCacheProfile) {
$executor->setQueryCacheProfile($this->_queryCacheProfile);
}
if ($this->_resultSetMapping === null) {
$this->_resultSetMapping = $this->_parserResult->getResultSetMapping();
}
// Prepare parameters
$paramMappings = $this->_parserResult->getParameterMappings();
$paramCount = count($this->parameters);
$mappingCount = count($paramMappings);
if ($paramCount > $mappingCount) {
throw QueryException::tooManyParameters($mappingCount, $paramCount);
} elseif ($paramCount < $mappingCount) {
throw QueryException::tooFewParameters($mappingCount, $paramCount);
}
// evict all cache for the entity region
if ($this->hasCache && isset($this->_hints[self::HINT_CACHE_EVICT]) && $this->_hints[self::HINT_CACHE_EVICT]) {
$this->evictEntityCacheRegion();
}
list($sqlParams, $types) = $this->processParameterMappings($paramMappings);
return $executor->execute($this->_em->getConnection(), $sqlParams, $types);
}
/**
* Evict entity cache region
*/
private function evictEntityCacheRegion()
{
$AST = $this->getAST();
if ($AST instanceof \Doctrine\ORM\Query\AST\SelectStatement) {
throw new QueryException('The hint "HINT_CACHE_EVICT" is not valid for select statements.');
}
$className = ($AST instanceof \Doctrine\ORM\Query\AST\DeleteStatement)
? $AST->deleteClause->abstractSchemaName
: $AST->updateClause->abstractSchemaName;
$this->_em->getCache()->evictEntityRegion($className);
}
/**
* Processes query parameter mappings.
*
* @param array $paramMappings
*
* @return array
*
* @throws Query\QueryException
*/
private function processParameterMappings($paramMappings)
{
$sqlParams = array();
$types = array();
foreach ($this->parameters as $parameter) {
$key = $parameter->getName();
$value = $parameter->getValue();
$rsm = $this->getResultSetMapping();
if ( ! isset($paramMappings[$key])) {
throw QueryException::unknownParameter($key);
}
if (isset($rsm->metadataParameterMapping[$key]) && $value instanceof ClassMetadata) {
$value = $value->getMetadataValue($rsm->metadataParameterMapping[$key]);
}
$value = $this->processParameterValue($value);
$type = ($parameter->getValue() === $value)
? $parameter->getType()
: ParameterTypeInferer::inferType($value);
foreach ($paramMappings[$key] as $position) {
$types[$position] = $type;
}
$sqlPositions = $paramMappings[$key];
// optimized multi value sql positions away for now,
// they are not allowed in DQL anyways.
$value = array($value);
$countValue = count($value);
for ($i = 0, $l = count($sqlPositions); $i < $l; $i++) {
$sqlParams[$sqlPositions[$i]] = $value[($i % $countValue)];
}
}
if (count($sqlParams) != count($types)) {
throw QueryException::parameterTypeMismatch();
}
if ($sqlParams) {
ksort($sqlParams);
$sqlParams = array_values($sqlParams);
ksort($types);
$types = array_values($types);
}
return array($sqlParams, $types);
}
/**
* Defines a cache driver to be used for caching queries.
*
* @param \Doctrine\Common\Cache\Cache|null $queryCache Cache driver.
*
* @return Query This query instance.
*/
public function setQueryCacheDriver($queryCache)
{
$this->_queryCache = $queryCache;
return $this;
}
/**
* Defines whether the query should make use of a query cache, if available.
*
* @param boolean $bool
*
* @return Query This query instance.
*/
public function useQueryCache($bool)
{
$this->_useQueryCache = $bool;
return $this;
}
/**
* Returns the cache driver used for query caching.
*
* @return \Doctrine\Common\Cache\Cache|null The cache driver used for query caching or NULL, if
* this Query does not use query caching.
*/
public function getQueryCacheDriver()
{
if ($this->_queryCache) {
return $this->_queryCache;
}
return $this->_em->getConfiguration()->getQueryCacheImpl();
}
/**
* Defines how long the query cache will be active before expire.
*
* @param integer $timeToLive How long the cache entry is valid.
*
* @return Query This query instance.
*/
public function setQueryCacheLifetime($timeToLive)
{
if ($timeToLive !== null) {
$timeToLive = (int) $timeToLive;
}
$this->_queryCacheTTL = $timeToLive;
return $this;
}
/**
* Retrieves the lifetime of resultset cache.
*
* @return int
*/
public function getQueryCacheLifetime()
{
return $this->_queryCacheTTL;
}
/**
* Defines if the query cache is active or not.
*
* @param boolean $expire Whether or not to force query cache expiration.
*
* @return Query This query instance.
*/
public function expireQueryCache($expire = true)
{
$this->_expireQueryCache = $expire;
return $this;
}
/**
* Retrieves if the query cache is active or not.
*
* @return bool
*/
public function getExpireQueryCache()
{
return $this->_expireQueryCache;
}
/**
* @override
*/
public function free()
{
parent::free();
$this->_dql = null;
$this->_state = self::STATE_CLEAN;
}
/**
* Sets a DQL query string.
*
* @param string $dqlQuery DQL Query.
*
* @return \Doctrine\ORM\AbstractQuery
*/
public function setDQL($dqlQuery)
{
if ($dqlQuery !== null) {
$this->_dql = $dqlQuery;
$this->_state = self::STATE_DIRTY;
}
return $this;
}
/**
* Returns the DQL query that is represented by this query object.
*
* @return string DQL query.
*/
public function getDQL()
{
return $this->_dql;
}
/**
* Returns the state of this query object
* By default the type is Doctrine_ORM_Query_Abstract::STATE_CLEAN but if it appears any unprocessed DQL
* part, it is switched to Doctrine_ORM_Query_Abstract::STATE_DIRTY.
*
* @see AbstractQuery::STATE_CLEAN
* @see AbstractQuery::STATE_DIRTY
*
* @return integer The query state.
*/
public function getState()
{
return $this->_state;
}
/**
* Method to check if an arbitrary piece of DQL exists
*
* @param string $dql Arbitrary piece of DQL to check for.
*
* @return boolean
*/
public function contains($dql)
{
return stripos($this->getDQL(), $dql) === false ? false : true;
}
/**
* Sets the position of the first result to retrieve (the "offset").
*
* @param integer $firstResult The first result to return.
*
* @return Query This query object.
*/
public function setFirstResult($firstResult)
{
$this->_firstResult = $firstResult;
$this->_state = self::STATE_DIRTY;
return $this;
}
/**
* Gets the position of the first result the query object was set to retrieve (the "offset").
* Returns NULL if {@link setFirstResult} was not applied to this query.
*
* @return integer The position of the first result.
*/
public function getFirstResult()
{
return $this->_firstResult;
}
/**
* Sets the maximum number of results to retrieve (the "limit").
*
* @param integer $maxResults
*
* @return Query This query object.
*/
public function setMaxResults($maxResults)
{
$this->_maxResults = $maxResults;
$this->_state = self::STATE_DIRTY;
return $this;
}
/**
* Gets the maximum number of results the query object was set to retrieve (the "limit").
* Returns NULL if {@link setMaxResults} was not applied to this query.
*
* @return integer Maximum number of results.
*/
public function getMaxResults()
{
return $this->_maxResults;
}
/**
* Executes the query and returns an IterableResult that can be used to incrementally
* iterated over the result.
*
* @param ArrayCollection|array|null $parameters The query parameters.
* @param integer $hydrationMode The hydration mode to use.
*
* @return \Doctrine\ORM\Internal\Hydration\IterableResult
*/
public function iterate($parameters = null, $hydrationMode = self::HYDRATE_OBJECT)
{
$this->setHint(self::HINT_INTERNAL_ITERATION, true);
return parent::iterate($parameters, $hydrationMode);
}
/**
* {@inheritdoc}
*/
public function setHint($name, $value)
{
$this->_state = self::STATE_DIRTY;
return parent::setHint($name, $value);
}
/**
* {@inheritdoc}
*/
public function setHydrationMode($hydrationMode)
{
$this->_state = self::STATE_DIRTY;
return parent::setHydrationMode($hydrationMode);
}
/**
* Set the lock mode for this Query.
*
* @see \Doctrine\DBAL\LockMode
*
* @param int $lockMode
*
* @return Query
*
* @throws TransactionRequiredException
*/
public function setLockMode($lockMode)
{
if (in_array($lockMode, array(LockMode::NONE, LockMode::PESSIMISTIC_READ, LockMode::PESSIMISTIC_WRITE), true)) {
if ( ! $this->_em->getConnection()->isTransactionActive()) {
throw TransactionRequiredException::transactionRequired();
}
}
$this->setHint(self::HINT_LOCK_MODE, $lockMode);
return $this;
}
/**
* Get the current lock mode for this query.
*
* @return int|null The current lock mode of this query or NULL if no specific lock mode is set.
*/
public function getLockMode()
{
$lockMode = $this->getHint(self::HINT_LOCK_MODE);
if (false === $lockMode) {
return null;
}
return $lockMode;
}
/**
* Generate a cache id for the query cache - reusing the Result-Cache-Id generator.
*
* @return string
*/
protected function _getQueryCacheId()
{
ksort($this->_hints);
$platform = $this->getEntityManager()
->getConnection()
->getDatabasePlatform()
->getName();
return md5(
$this->getDql() . serialize($this->_hints) .
'&platform=' . $platform .
($this->_em->hasFilters() ? $this->_em->getFilters()->getHash() : '') .
'&firstResult=' . $this->_firstResult . '&maxResult=' . $this->_maxResults .
'&hydrationMode=' . $this->_hydrationMode . '&types=' . serialize($this->_parsedTypes) . 'DOCTRINE_QUERY_CACHE_SALT'
);
}
/**
* {@inheritdoc}
*/
protected function getHash()
{
return sha1(parent::getHash(). '-'. $this->_firstResult . '-' . $this->_maxResults);
}
/**
* Cleanup Query resource when clone is called.
*
* @return void
*/
public function __clone()
{
parent::__clone();
$this->_state = self::STATE_DIRTY;
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Query/ 0000775 0000000 0000000 00000000000 13215356457 0017566 5 ustar 00root root 0000000 0000000 doctrine2-2.5.14/lib/Doctrine/ORM/Query/AST/ 0000775 0000000 0000000 00000000000 13215356457 0020215 5 ustar 00root root 0000000 0000000 doctrine2-2.5.14/lib/Doctrine/ORM/Query/AST/ASTException.php 0000664 0000000 0000000 00000002566 13215356457 0023245 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Query\AST;
use Doctrine\ORM\Query\QueryException;
/**
* Base exception class for AST exceptions.
*/
class ASTException extends QueryException
{
/**
* @param Node $node
*
* @return ASTException
*/
public static function noDispatchForNode($node)
{
return new self("Double-dispatch for node " . get_class($node) . " is not supported.");
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Query/AST/AggregateExpression.php 0000664 0000000 0000000 00000004251 13215356457 0024676 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Query\AST;
/**
* Description of AggregateExpression.
*
* @link www.doctrine-project.org
* @since 2.0
* @author Guilherme Blanco
* @author Jonathan Wage
* @author Roman Borschel
*/
class AggregateExpression extends Node
{
/**
* @var string
*/
public $functionName;
/**
* @var PathExpression|SimpleArithmeticExpression
*/
public $pathExpression;
/**
* Some aggregate expressions support distinct, eg COUNT.
*
* @var bool
*/
public $isDistinct = false;
/**
* @param string $functionName
* @param PathExpression|SimpleArithmeticExpression $pathExpression
* @param bool $isDistinct
*/
public function __construct($functionName, $pathExpression, $isDistinct)
{
$this->functionName = $functionName;
$this->pathExpression = $pathExpression;
$this->isDistinct = $isDistinct;
}
/**
* {@inheritdoc}
*/
public function dispatch($walker)
{
return $walker->walkAggregateExpression($this);
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Query/AST/ArithmeticExpression.php 0000664 0000000 0000000 00000003644 13215356457 0025106 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Query\AST;
/**
* ArithmeticExpression ::= SimpleArithmeticExpression | "(" Subselect ")"
*
* @link www.doctrine-project.org
* @since 2.0
* @author Guilherme Blanco
* @author Jonathan Wage
* @author Roman Borschel
*/
class ArithmeticExpression extends Node
{
/**
* @var SimpleArithmeticExpression|null
*/
public $simpleArithmeticExpression;
/**
* @var Subselect|null
*/
public $subselect;
/**
* @return bool
*/
public function isSimpleArithmeticExpression()
{
return (bool) $this->simpleArithmeticExpression;
}
/**
* @return bool
*/
public function isSubselect()
{
return (bool) $this->subselect;
}
/**
* {@inheritdoc}
*/
public function dispatch($walker)
{
return $walker->walkArithmeticExpression($this);
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Query/AST/ArithmeticFactor.php 0000664 0000000 0000000 00000004236 13215356457 0024163 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Query\AST;
/**
* ArithmeticFactor ::= [("+" | "-")] ArithmeticPrimary
*
* @link www.doctrine-project.org
* @since 2.0
* @author Guilherme Blanco
* @author Jonathan Wage
* @author Roman Borschel
*/
class ArithmeticFactor extends Node
{
/**
* @var mixed
*/
public $arithmeticPrimary;
/**
* NULL represents no sign, TRUE means positive and FALSE means negative sign.
*
* @var null|boolean
*/
public $sign;
/**
* @param mixed $arithmeticPrimary
* @param null|bool $sign
*/
public function __construct($arithmeticPrimary, $sign = null)
{
$this->arithmeticPrimary = $arithmeticPrimary;
$this->sign = $sign;
}
/**
* @return bool
*/
public function isPositiveSigned()
{
return $this->sign === true;
}
/**
* @return bool
*/
public function isNegativeSigned()
{
return $this->sign === false;
}
/**
* {@inheritdoc}
*/
public function dispatch($sqlWalker)
{
return $sqlWalker->walkArithmeticFactor($this);
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Query/AST/ArithmeticTerm.php 0000664 0000000 0000000 00000003321 13215356457 0023646 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Query\AST;
/**
* ArithmeticTerm ::= ArithmeticFactor {("*" | "/") ArithmeticFactor}*
*
* @link www.doctrine-project.org
* @since 2.0
* @author Guilherme Blanco
* @author Jonathan Wage
* @author Roman Borschel
*/
class ArithmeticTerm extends Node
{
/**
* @var array
*/
public $arithmeticFactors;
/**
* @param array $arithmeticFactors
*/
public function __construct(array $arithmeticFactors)
{
$this->arithmeticFactors = $arithmeticFactors;
}
/**
* {@inheritdoc}
*/
public function dispatch($sqlWalker)
{
return $sqlWalker->walkArithmeticTerm($this);
}
}
doctrine2-2.5.14/lib/Doctrine/ORM/Query/AST/BetweenExpression.php 0000664 0000000 0000000 00000004116 13215356457 0024401 0 ustar 00root root 0000000 0000000 .
*/
namespace Doctrine\ORM\Query\AST;
/**
* Description of BetweenExpression.
*
* @link www.doctrine-project.org
* @since 2.0
* @author Guilherme Blanco
* @author Jonathan Wage
* @author Roman Borschel