From 22f035354e5c0f14e8d291834c145cb56d2c62e2 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Sun, 13 Sep 2020 13:54:56 +0200 Subject: [PATCH 01/37] [GH-8265] Prototype for Attribute Metadata Driver --- .../ORM/Mapping/AttributeOverride.php | 3 + lib/Doctrine/ORM/Mapping/Cache.php | 3 + .../ORM/Mapping/ChangeTrackingPolicy.php | 3 + lib/Doctrine/ORM/Mapping/Column.php | 3 + .../ORM/Mapping/CustomIdGenerator.php | 3 + .../ORM/Mapping/DiscriminatorColumn.php | 3 + lib/Doctrine/ORM/Mapping/DiscriminatorMap.php | 3 + .../ORM/Mapping/Driver/AttributeReader.php | 87 +++ .../ORM/Mapping/Driver/AttributesDriver.php | 503 ++++++++++++++++++ lib/Doctrine/ORM/Mapping/Embeddable.php | 3 + lib/Doctrine/ORM/Mapping/Embedded.php | 3 + lib/Doctrine/ORM/Mapping/Entity.php | 3 + lib/Doctrine/ORM/Mapping/GeneratedValue.php | 3 + .../ORM/Mapping/HasLifecycleCallbacks.php | 3 + lib/Doctrine/ORM/Mapping/Id.php | 3 + lib/Doctrine/ORM/Mapping/Index.php | 3 + lib/Doctrine/ORM/Mapping/InheritanceType.php | 3 + .../ORM/Mapping/InverseJoinColumn.php | 63 +++ lib/Doctrine/ORM/Mapping/JoinColumn.php | 1 + lib/Doctrine/ORM/Mapping/JoinTable.php | 3 + lib/Doctrine/ORM/Mapping/ManyToMany.php | 3 + lib/Doctrine/ORM/Mapping/ManyToOne.php | 3 + lib/Doctrine/ORM/Mapping/MappedSuperclass.php | 3 + lib/Doctrine/ORM/Mapping/OneToMany.php | 3 + lib/Doctrine/ORM/Mapping/OneToOne.php | 3 + lib/Doctrine/ORM/Mapping/OrderBy.php | 3 + lib/Doctrine/ORM/Mapping/PostLoad.php | 3 + lib/Doctrine/ORM/Mapping/PostPersist.php | 3 + lib/Doctrine/ORM/Mapping/PostRemove.php | 3 + lib/Doctrine/ORM/Mapping/PostUpdate.php | 3 + lib/Doctrine/ORM/Mapping/PreFlush.php | 3 + lib/Doctrine/ORM/Mapping/PrePersist.php | 3 + lib/Doctrine/ORM/Mapping/PreRemove.php | 3 + lib/Doctrine/ORM/Mapping/PreUpdate.php | 3 + .../ORM/Mapping/SequenceGenerator.php | 3 + lib/Doctrine/ORM/Mapping/Table.php | 3 + lib/Doctrine/ORM/Mapping/UniqueConstraint.php | 3 + lib/Doctrine/ORM/Mapping/Version.php | 3 + .../ORM/Mapping/AbstractMappingDriverTest.php | 23 + .../Tests/ORM/Mapping/AttributeDriverTest.php | 15 + 40 files changed, 794 insertions(+) create mode 100644 lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php create mode 100644 lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php create mode 100644 lib/Doctrine/ORM/Mapping/InverseJoinColumn.php create mode 100644 tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php diff --git a/lib/Doctrine/ORM/Mapping/AttributeOverride.php b/lib/Doctrine/ORM/Mapping/AttributeOverride.php index f86d3a1521d..33db15d3f4c 100644 --- a/lib/Doctrine/ORM/Mapping/AttributeOverride.php +++ b/lib/Doctrine/ORM/Mapping/AttributeOverride.php @@ -19,6 +19,8 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * This annotation is used to override the mapping of a entity property. * @@ -28,6 +30,7 @@ * @Annotation * @Target("ANNOTATION") */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] final class AttributeOverride implements Annotation { /** diff --git a/lib/Doctrine/ORM/Mapping/Cache.php b/lib/Doctrine/ORM/Mapping/Cache.php index 3226b603160..b3e992e32f8 100644 --- a/lib/Doctrine/ORM/Mapping/Cache.php +++ b/lib/Doctrine/ORM/Mapping/Cache.php @@ -19,6 +19,8 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * Caching to an entity or a collection. * @@ -28,6 +30,7 @@ * @Annotation * @Target({"CLASS","PROPERTY"}) */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_PROPERTY)] final class Cache implements Annotation { /** diff --git a/lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php b/lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php index 3657b764f1e..8121c1fc958 100644 --- a/lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php +++ b/lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("CLASS") */ +#[Attribute(Attribute::TARGET_CLASS)] final class ChangeTrackingPolicy implements Annotation { /** diff --git a/lib/Doctrine/ORM/Mapping/Column.php b/lib/Doctrine/ORM/Mapping/Column.php index 711590be672..0c1a4c1a075 100644 --- a/lib/Doctrine/ORM/Mapping/Column.php +++ b/lib/Doctrine/ORM/Mapping/Column.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target({"PROPERTY","ANNOTATION"}) */ +#[Attribute(Attribute::TARGET_PROPERTY)] final class Column implements Annotation { /** diff --git a/lib/Doctrine/ORM/Mapping/CustomIdGenerator.php b/lib/Doctrine/ORM/Mapping/CustomIdGenerator.php index 41e200e12a7..a48ba1acb1b 100644 --- a/lib/Doctrine/ORM/Mapping/CustomIdGenerator.php +++ b/lib/Doctrine/ORM/Mapping/CustomIdGenerator.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("PROPERTY") */ +#[Attribute(Attribute::TARGET_PROPERTY)] final class CustomIdGenerator implements Annotation { /** diff --git a/lib/Doctrine/ORM/Mapping/DiscriminatorColumn.php b/lib/Doctrine/ORM/Mapping/DiscriminatorColumn.php index 97ca7e9b577..332f6d7ad5a 100644 --- a/lib/Doctrine/ORM/Mapping/DiscriminatorColumn.php +++ b/lib/Doctrine/ORM/Mapping/DiscriminatorColumn.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("CLASS") */ +#[Attribute(Attribute::TARGET_CLASS)] final class DiscriminatorColumn implements Annotation { /** diff --git a/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php b/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php index 09d619465cd..720b7dbe596 100644 --- a/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php +++ b/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("CLASS") */ +#[Attribute(Attribute::TARGET_CLASS)] final class DiscriminatorMap implements Annotation { /** diff --git a/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php b/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php new file mode 100644 index 00000000000..a4ad4806980 --- /dev/null +++ b/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php @@ -0,0 +1,87 @@ + */ + private $isRepeatableAttribute = []; + + function getClassAnnotations(\ReflectionClass $class) + { + return $this->convertToAttributeInstances($class->getAttributes()); + } + + function getClassAnnotation(\ReflectionClass $class, $annotationName) + { + return $this->getClassAnnotations($class)[$annotationName] ?? ($this->isRepeatable($annotationName) ? [] : null); + } + + function getMethodAnnotations(\ReflectionMethod $method) + { + return $this->convertToAttributeInstances($method->getAttributes()); + } + + function getMethodAnnotation(\ReflectionMethod $method, $annotationName) + { + return $this->getMethodAnnotations($method)[$annotationName] ?? ($this->isRepeatable($annotationName) ? [] : null); + } + + function getPropertyAnnotations(\ReflectionProperty $property) + { + return $this->convertToAttributeInstances($property->getAttributes()); + } + + function getPropertyAnnotation(\ReflectionProperty $property, $annotationName) + { + return $this->getPropertyAnnotations($property)[$annotationName] ?? ($this->isRepeatable($annotationName) ? [] : null); + } + + private function convertToAttributeInstances(array $attributes) + { + $instances = []; + + foreach ($attributes as $attribute) { + // Make sure we only get Doctrine Annotations + if (is_subclass_of($attribute->getName(), Annotation::class)) { + $instance = new $attribute->getName(); + $arguments = $attribute->getArguments(); + + // unnamed argument is automatically "value" in Doctrine Annotations + if (count($arguments) >= 1 && isset($arguments[0])) { + $arguments['value'] = $arguments[0]; + unset($arguments[0]); + } + + // This works using the old Annotation, but will probably break Attribute IDE autocomplete support + foreach ($arguments as $name => $value) { + $instance->$name = $value; + } + + if ($this->isRepeatable($attribute->getName())) { + $instances[$attribute->getName()][] = $instance; + } else { + $instances[$attribute->getName()] = $instance; + } + } + } + + return $instances; + } + + private function isRepeatable(string $attributeClassName) : bool + { + if (isset($this->isRepeatableAttribute[$attributeClassName])) { + return $this->isRepeatableAttribute[$attributeClassName]; + } + + $reflectionClass = new \ReflectionClass($attributeClassName); + $attribute = $reflectionClass->getAttributes()[0]; + + return $this->isRepeatableAttribute[$attributeClassName] = $attribute->flags && Attribute::IS_REPEATABLE; + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php b/lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php new file mode 100644 index 00000000000..aebab108918 --- /dev/null +++ b/lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php @@ -0,0 +1,503 @@ + 1, + Mapping\MappedSuperclass::class => 2, + ]; + + public function __construct(array $paths) + { + parent::__construct(new AttributeReader(), $paths); + } + + public function loadMetadataForClass($className, ClassMetadata $metadata) + { + /* @var $metadata \Doctrine\ORM\Mapping\ClassMetadataInfo */ + $reflectionClass = $metadata->getReflectionClass(); + + $classAttributes = $this->reader->getClassAnnotations($reflectionClass); + + // Evaluate Entity annotation + if (isset($classAttributes[Mapping\Entity::class])) { + $entityAttribute = $classAttributes[Mapping\Entity::class]; + if ($entityAttribute->repositoryClass !== null) { + $metadata->setCustomRepositoryClass($entityAttribute->repositoryClass); + } + + if ($entityAttribute->readOnly) { + $metadata->markReadOnly(); + } + } else if (isset($classAttributes[Mapping\MappedSuperclass::class])) { + $mappedSuperclassAttribute = $classAttributes[Mapping\MappedSuperclass::class]; + + $metadata->setCustomRepositoryClass($mappedSuperclassAttribute->repositoryClass); + $metadata->isMappedSuperclass = true; + } else if (isset($classAttributes[Mapping\Embeddable::class])) { + $metadata->isEmbeddedClass = true; + } else { + throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className); + } + + // Evaluate Table annotation + if (isset($classAttributes[Mapping\Table::class])) { + $tableAnnot = $classAttributes[Mapping\Table::class]; + $primaryTable = [ + 'name' => $tableAnnot->name, + 'schema' => $tableAnnot->schema + ]; + + if (isset($classAttributes[Mapping\Index::class])) { + foreach ($classAttributes[Mapping\Index::class] as $indexAnnot) { + $index = ['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 (isset($classAttributes[Mapping\UniqueConstraint::class])) { + foreach ($classAttributes[Mapping\UniqueConstraint::class] as $uniqueConstraintAnnot) { + $uniqueConstraint = ['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($classAttributes[Mapping\Cache::class])) { + $cacheAttribute = $classAttributes[Mapping\Cache::class]; + $cacheMap = [ + 'region' => $cacheAttribute->region, + 'usage' => constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $cacheAttribute->usage), + ]; + + $metadata->enableCache($cacheMap); + } + + // Evaluate InheritanceType annotation + if (isset($classAttributes[Mapping\InheritanceType::class])) { + $inheritanceTypeAttribute = $classAttributes[Mapping\InheritanceType::class]; + + $metadata->setInheritanceType( + constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceTypeAttribute->value) + ); + + if ($metadata->inheritanceType != Mapping\ClassMetadata::INHERITANCE_TYPE_NONE) { + // Evaluate DiscriminatorColumn annotation + if (isset($classAttributes[Mapping\DiscriminatorColumn::class])) { + $discrColumnAttribute = $classAttributes[Mapping\DiscriminatorColumn::class]; + + $metadata->setDiscriminatorColumn( + [ + 'name' => $discrColumnAttribute->name, + 'type' => $discrColumnAttribute->type ?: 'string', + 'length' => $discrColumnAttribute->length ?: 255, + 'columnDefinition' => $discrColumnAttribute->columnDefinition, + ] + ); + } else { + $metadata->setDiscriminatorColumn(['name' => 'dtype', 'type' => 'string', 'length' => 255]); + } + + // Evaluate DiscriminatorMap annotation + if (isset($classAttributes[Mapping\DiscriminatorMap::class])) { + $discrMapAttribute = $classAttributes[Mapping\DiscriminatorMap::class]; + $metadata->setDiscriminatorMap($discrMapAttribute->value); + } + } + } + + // Evaluate DoctrineChangeTrackingPolicy annotation + if (isset($classAttributes[Mapping\ChangeTrackingPolicy::class])) { + $changeTrackingAttribute = $classAttributes[Mapping\ChangeTrackingPolicy::class]; + $metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_' . $changeTrackingAttribute->value)); + } + + // Evaluate annotations on properties/fields + /* @var $property \ReflectionProperty */ + foreach ($reflectionClass->getProperties() as $property) { + if ($metadata->isMappedSuperclass && ! $property->isPrivate() + || + $metadata->isInheritedField($property->name) + || + $metadata->isInheritedAssociation($property->name) + || + $metadata->isInheritedEmbeddedClass($property->name)) { + continue; + } + + $mapping = []; + $mapping['fieldName'] = $property->getName(); + + // Evaluate @Cache annotation + if (($cacheAttribute = $this->reader->getPropertyAnnotation($property, Mapping\Cache::class)) !== null) { + $mapping['cache'] = $metadata->getAssociationCacheDefaults( + $mapping['fieldName'], + [ + 'usage' => constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $cacheAttribute->usage), + 'region' => $cacheAttribute->region, + ] + ); + } + // Check for JoinColumn/JoinColumns annotations + $joinColumns = []; + + if ($joinColumnAttribute = $this->reader->getPropertyAnnotation($property, Mapping\JoinColumn::class)) { + $joinColumns[] = $this->joinColumnToArray($joinColumnAttribute); + } + + // Field can only be annotated with one of: + // @Column, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany + if ($columnAttribute = $this->reader->getPropertyAnnotation($property, Mapping\Column::class)) { + if ($columnAttribute->type == null) { + throw MappingException::propertyTypeIsRequired($className, $property->getName()); + } + + $mapping = $this->columnToArray($property->getName(), $columnAttribute); + + if ($this->reader->getPropertyAnnotation($property, Mapping\Id::class)) { + $mapping['id'] = true; + } + + if ($generatedValueAttribute = $this->reader->getPropertyAnnotation($property, Mapping\GeneratedValue::class)) { + $metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' . $generatedValueAttribute->strategy)); + } + + if ($this->reader->getPropertyAnnotation($property, Mapping\Version::class)) { + $metadata->setVersionMapping($mapping); + } + + $metadata->mapField($mapping); + + // Check for SequenceGenerator/TableGenerator definition + if ($seqGeneratorAttribute = $this->reader->getPropertyAnnotation($property, Mapping\SequenceGenerator::class)) { + $metadata->setSequenceGeneratorDefinition( + [ + 'sequenceName' => $seqGeneratorAttribute->sequenceName, + 'allocationSize' => $seqGeneratorAttribute->allocationSize, + 'initialValue' => $seqGeneratorAttribute->initialValue + ] + ); + } else if ($this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\TableGenerator')) { + throw MappingException::tableIdGeneratorNotImplemented($className); + } else if ($customGeneratorAttribute = $this->reader->getPropertyAnnotation($property, Mapping\CustomIdGenerator::class)) { + $metadata->setCustomGeneratorDefinition( + [ + 'class' => $customGeneratorAttribute->class + ] + ); + } + } else if ($oneToOneAttribute = $this->reader->getPropertyAnnotation($property, Mapping\OneToOne::class)) { + if ($this->reader->getPropertyAnnotation($property, Mapping\Id::class)) { + $mapping['id'] = true; + } + + $mapping['targetEntity'] = $oneToOneAttribute->targetEntity; + $mapping['joinColumns'] = $joinColumns; + $mapping['mappedBy'] = $oneToOneAttribute->mappedBy; + $mapping['inversedBy'] = $oneToOneAttribute->inversedBy; + $mapping['cascade'] = $oneToOneAttribute->cascade; + $mapping['orphanRemoval'] = $oneToOneAttribute->orphanRemoval; + $mapping['fetch'] = $this->getFetchMode($className, $oneToOneAttribute->fetch); + $metadata->mapOneToOne($mapping); + } else if ($oneToManyAttribute = $this->reader->getPropertyAnnotation($property, Mapping\OneToMany::class)) { + $mapping['mappedBy'] = $oneToManyAttribute->mappedBy; + $mapping['targetEntity'] = $oneToManyAttribute->targetEntity; + $mapping['cascade'] = $oneToManyAttribute->cascade; + $mapping['indexBy'] = $oneToManyAttribute->indexBy; + $mapping['orphanRemoval'] = $oneToManyAttribute->orphanRemoval; + $mapping['fetch'] = $this->getFetchMode($className, $oneToManyAttribute->fetch); + + if ($orderByAttribute = $this->reader->getPropertyAnnotation($property, Mapping\OrderBy::class)) { + $mapping['orderBy'] = $orderByAttribute->value; + } + + $metadata->mapOneToMany($mapping); + } else if ($manyToOneAttribute = $this->reader->getPropertyAnnotation($property, Mapping\ManyToOne::class)) { + if ($idAttribute = $this->reader->getPropertyAnnotation($property, Mapping\Id::class)) { + $mapping['id'] = true; + } + + $mapping['joinColumns'] = $joinColumns; + $mapping['cascade'] = $manyToOneAttribute->cascade; + $mapping['inversedBy'] = $manyToOneAttribute->inversedBy; + $mapping['targetEntity'] = $manyToOneAttribute->targetEntity; + $mapping['fetch'] = $this->getFetchMode($className, $manyToOneAttribute->fetch); + $metadata->mapManyToOne($mapping); + } else if ($manyToManyAttribute = $this->reader->getPropertyAnnotation($property, Mapping\ManyToMany::class)) { + $joinTable = []; + + if ($joinTableAttribute = $this->reader->getPropertyAnnotation($property, Mapping\JoinTable::class)) { + $joinTable = [ + 'name' => $joinTableAttribute->name, + 'schema' => $joinTableAttribute->schema + ]; + + foreach ($this->reader->getPropertyAnnotation($property, Mapping\JoinColumn::class) as $joinColumn) { + $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumn); + } + + foreach ($this->reader->getPropertyAnnotation($property, Mapping\InverseJoinColumn::class) as $joinColumn) { + $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumn); + } + } + + $mapping['joinTable'] = $joinTable; + $mapping['targetEntity'] = $manyToManyAttribute->targetEntity; + $mapping['mappedBy'] = $manyToManyAttribute->mappedBy; + $mapping['inversedBy'] = $manyToManyAttribute->inversedBy; + $mapping['cascade'] = $manyToManyAttribute->cascade; + $mapping['indexBy'] = $manyToManyAttribute->indexBy; + $mapping['orphanRemoval'] = $manyToManyAttribute->orphanRemoval; + $mapping['fetch'] = $this->getFetchMode($className, $manyToManyAttribute->fetch); + + if ($orderByAttribute = $this->reader->getPropertyAnnotation($property, Mapping\OrderBy::class)) { + $mapping['orderBy'] = $orderByAttribute->value; + } + + $metadata->mapManyToMany($mapping); + } else if ($embeddedAttribute = $this->reader->getPropertyAnnotation($property, Mapping\Embedded::class)) { + $mapping['class'] = $embeddedAttribute->class; + $mapping['columnPrefix'] = $embeddedAttribute->columnPrefix; + + $metadata->mapEmbedded($mapping); + } + } + + // Evaluate AttributeOverrides annotation + if (isset($classAttributes[Mapping\AttributeOverride::class])) { + + foreach ($classAttributes[Mapping\AttributeOverride::class] as $attributeOverrideAttribute) { + $attributeOverride = $this->columnToArray($attributeOverrideAttribute->name, $attributeOverrideAttribute->column); + + $metadata->setAttributeOverride($attributeOverrideAttribute->name, $attributeOverride); + } + } + + // Evaluate EntityListeners annotation + if (isset($classAttributes[Mapping\EntityListeners::class])) { + $entityListenersAttribute = $classAttributes[Mapping\EntityListeners::class]; + + foreach ($entityListenersAttribute->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($classAttributes[Mapping\HasLifecycleCallbacks::class])) { + /* @var $method \ReflectionMethod */ + foreach ($reflectionClass->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 callable[] + */ + private function getMethodCallbacks(\ReflectionMethod $method) + { + $callbacks = []; + $attributes = $this->reader->getMethodAnnotations($method); + + foreach ($attributes as $attribute) { + if ($attribute instanceof Mapping\PrePersist) { + $callbacks[] = [$method->name, Events::prePersist]; + } + + if ($attribute instanceof Mapping\PostPersist) { + $callbacks[] = [$method->name, Events::postPersist]; + } + + if ($attribute instanceof Mapping\PreUpdate) { + $callbacks[] = [$method->name, Events::preUpdate]; + } + + if ($attribute instanceof Mapping\PostUpdate) { + $callbacks[] = [$method->name, Events::postUpdate]; + } + + if ($attribute instanceof Mapping\PreRemove) { + $callbacks[] = [$method->name, Events::preRemove]; + } + + if ($attribute instanceof Mapping\PostRemove) { + $callbacks[] = [$method->name, Events::postRemove]; + } + + if ($attribute instanceof Mapping\PostLoad) { + $callbacks[] = [$method->name, Events::postLoad]; + } + + if ($attribute instanceof Mapping\PreFlush) { + $callbacks[] = [$method->name, Events::preFlush]; + } + } + + return $callbacks; + } + + /** + * Parse the given JoinColumn as array + * + * @param Mapping\JoinColumn $joinColumn + * + * @return mixed[] + * + * @psalm-return array{ + * name: string, + * unique: bool, + * nullable: bool, + * onDelete: mixed, + * columnDefinition: string, + * referencedColumnName: string + * } + */ + private function joinColumnToArray(Mapping\JoinColumn $joinColumn) + { + return [ + '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 Mapping\Column $column + * + * @return mixed[] + * + * @psalm-return array{ + * fieldName: string, + * type: mixed, + * scale: int, + * length: int, + * unique: bool, + * nullable: bool, + * precision: int, + * options?: mixed[], + * columnName?: string, + * columnDefinition?: string + * } + */ + private function columnToArray($fieldName, Mapping\Column $column) + { + $mapping = [ + '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; + } +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Mapping/Embeddable.php b/lib/Doctrine/ORM/Mapping/Embeddable.php index f14bfac82a6..54a5f474206 100644 --- a/lib/Doctrine/ORM/Mapping/Embeddable.php +++ b/lib/Doctrine/ORM/Mapping/Embeddable.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("CLASS") */ +#[Attribute(Attribute::TARGET_CLASS)] final class Embeddable implements Annotation { } diff --git a/lib/Doctrine/ORM/Mapping/Embedded.php b/lib/Doctrine/ORM/Mapping/Embedded.php index 37339108bc9..5da283efacc 100644 --- a/lib/Doctrine/ORM/Mapping/Embedded.php +++ b/lib/Doctrine/ORM/Mapping/Embedded.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("PROPERTY") */ +#[Attribute(Attribute::TARGET_PROPERTY)] final class Embedded implements Annotation { /** diff --git a/lib/Doctrine/ORM/Mapping/Entity.php b/lib/Doctrine/ORM/Mapping/Entity.php index edf6ad5a4be..248a90be30e 100644 --- a/lib/Doctrine/ORM/Mapping/Entity.php +++ b/lib/Doctrine/ORM/Mapping/Entity.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("CLASS") */ +#[Attribute(Attribute::TARGET_CLASS)] final class Entity implements Annotation { /** diff --git a/lib/Doctrine/ORM/Mapping/GeneratedValue.php b/lib/Doctrine/ORM/Mapping/GeneratedValue.php index 27c03d4bee7..1a2f572eeb8 100644 --- a/lib/Doctrine/ORM/Mapping/GeneratedValue.php +++ b/lib/Doctrine/ORM/Mapping/GeneratedValue.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("PROPERTY") */ +#[Attribute(Attribute::TARGET_PROPERTY)] final class GeneratedValue implements Annotation { /** diff --git a/lib/Doctrine/ORM/Mapping/HasLifecycleCallbacks.php b/lib/Doctrine/ORM/Mapping/HasLifecycleCallbacks.php index 313ece31f8c..9bfbdf1cc59 100644 --- a/lib/Doctrine/ORM/Mapping/HasLifecycleCallbacks.php +++ b/lib/Doctrine/ORM/Mapping/HasLifecycleCallbacks.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("CLASS") */ +#[Attribute(Attribute::TARGET_CLASS)] final class HasLifecycleCallbacks implements Annotation { } diff --git a/lib/Doctrine/ORM/Mapping/Id.php b/lib/Doctrine/ORM/Mapping/Id.php index 6c9bcef0d71..06ff443dd40 100644 --- a/lib/Doctrine/ORM/Mapping/Id.php +++ b/lib/Doctrine/ORM/Mapping/Id.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("PROPERTY") */ +#[Attribute(Attribute::TARGET_PROPERTY)] final class Id implements Annotation { } diff --git a/lib/Doctrine/ORM/Mapping/Index.php b/lib/Doctrine/ORM/Mapping/Index.php index 45953a80478..24eb752a8b7 100644 --- a/lib/Doctrine/ORM/Mapping/Index.php +++ b/lib/Doctrine/ORM/Mapping/Index.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("ANNOTATION") */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] final class Index implements Annotation { /** diff --git a/lib/Doctrine/ORM/Mapping/InheritanceType.php b/lib/Doctrine/ORM/Mapping/InheritanceType.php index de803369a30..5f42fb095d2 100644 --- a/lib/Doctrine/ORM/Mapping/InheritanceType.php +++ b/lib/Doctrine/ORM/Mapping/InheritanceType.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("CLASS") */ +#[Attribute(Attribute::TARGET_CLASS)] final class InheritanceType implements Annotation { /** diff --git a/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php b/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php new file mode 100644 index 00000000000..14b5518b9c3 --- /dev/null +++ b/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php @@ -0,0 +1,63 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +use Attribute; + +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] +final class InverseJoinColumn 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; +} diff --git a/lib/Doctrine/ORM/Mapping/JoinColumn.php b/lib/Doctrine/ORM/Mapping/JoinColumn.php index febce917481..751946861d4 100644 --- a/lib/Doctrine/ORM/Mapping/JoinColumn.php +++ b/lib/Doctrine/ORM/Mapping/JoinColumn.php @@ -23,6 +23,7 @@ * @Annotation * @Target({"PROPERTY","ANNOTATION"}) */ +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] final class JoinColumn implements Annotation { /** diff --git a/lib/Doctrine/ORM/Mapping/JoinTable.php b/lib/Doctrine/ORM/Mapping/JoinTable.php index 879316a2874..90664ca888a 100644 --- a/lib/Doctrine/ORM/Mapping/JoinTable.php +++ b/lib/Doctrine/ORM/Mapping/JoinTable.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target({"PROPERTY","ANNOTATION"}) */ +#[Attribute(Attribute::TARGET_PROPERTY)] final class JoinTable implements Annotation { /** diff --git a/lib/Doctrine/ORM/Mapping/ManyToMany.php b/lib/Doctrine/ORM/Mapping/ManyToMany.php index ca2f53c9eea..e7bd6ac69fe 100644 --- a/lib/Doctrine/ORM/Mapping/ManyToMany.php +++ b/lib/Doctrine/ORM/Mapping/ManyToMany.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("PROPERTY") */ +#[Attribute(Attribute::TARGET_PROPERTY)] final class ManyToMany implements Annotation { /** diff --git a/lib/Doctrine/ORM/Mapping/ManyToOne.php b/lib/Doctrine/ORM/Mapping/ManyToOne.php index d3414e6a956..8147d932de4 100644 --- a/lib/Doctrine/ORM/Mapping/ManyToOne.php +++ b/lib/Doctrine/ORM/Mapping/ManyToOne.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("PROPERTY") */ +#[Attribute(Attribute::TARGET_PROPERTY)] final class ManyToOne implements Annotation { /** diff --git a/lib/Doctrine/ORM/Mapping/MappedSuperclass.php b/lib/Doctrine/ORM/Mapping/MappedSuperclass.php index 74588107d89..73b6766f417 100644 --- a/lib/Doctrine/ORM/Mapping/MappedSuperclass.php +++ b/lib/Doctrine/ORM/Mapping/MappedSuperclass.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("CLASS") */ +#[Attribute(Attribute::TARGET_CLASS)] final class MappedSuperclass implements Annotation { /** diff --git a/lib/Doctrine/ORM/Mapping/OneToMany.php b/lib/Doctrine/ORM/Mapping/OneToMany.php index 4b2465718e1..c7519158d8f 100644 --- a/lib/Doctrine/ORM/Mapping/OneToMany.php +++ b/lib/Doctrine/ORM/Mapping/OneToMany.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("PROPERTY") */ +#[Attribute(Attribute::TARGET_PROPERTY)] final class OneToMany implements Annotation { /** diff --git a/lib/Doctrine/ORM/Mapping/OneToOne.php b/lib/Doctrine/ORM/Mapping/OneToOne.php index b2ab81f88d9..de6a601547c 100644 --- a/lib/Doctrine/ORM/Mapping/OneToOne.php +++ b/lib/Doctrine/ORM/Mapping/OneToOne.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("PROPERTY") */ +#[Attribute(Attribute::TARGET_PROPERTY)] final class OneToOne implements Annotation { /** diff --git a/lib/Doctrine/ORM/Mapping/OrderBy.php b/lib/Doctrine/ORM/Mapping/OrderBy.php index ad1b7a8f714..cf6cdfe223a 100644 --- a/lib/Doctrine/ORM/Mapping/OrderBy.php +++ b/lib/Doctrine/ORM/Mapping/OrderBy.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("PROPERTY") */ +#[Attribute(Attribute::TARGET_PROPERTY)] final class OrderBy implements Annotation { /** diff --git a/lib/Doctrine/ORM/Mapping/PostLoad.php b/lib/Doctrine/ORM/Mapping/PostLoad.php index 2f8e9932e35..bb91da54ac3 100644 --- a/lib/Doctrine/ORM/Mapping/PostLoad.php +++ b/lib/Doctrine/ORM/Mapping/PostLoad.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("METHOD") */ +#[Attribute(Attribute::TARGET_METHOD)] final class PostLoad implements Annotation { } diff --git a/lib/Doctrine/ORM/Mapping/PostPersist.php b/lib/Doctrine/ORM/Mapping/PostPersist.php index 2aea7194911..1785f1aee1e 100644 --- a/lib/Doctrine/ORM/Mapping/PostPersist.php +++ b/lib/Doctrine/ORM/Mapping/PostPersist.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("METHOD") */ +#[Attribute(Attribute::TARGET_METHOD)] final class PostPersist implements Annotation { } diff --git a/lib/Doctrine/ORM/Mapping/PostRemove.php b/lib/Doctrine/ORM/Mapping/PostRemove.php index 321c4bd547b..71c9dac6218 100644 --- a/lib/Doctrine/ORM/Mapping/PostRemove.php +++ b/lib/Doctrine/ORM/Mapping/PostRemove.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("METHOD") */ +#[Attribute(Attribute::TARGET_METHOD)] final class PostRemove implements Annotation { } diff --git a/lib/Doctrine/ORM/Mapping/PostUpdate.php b/lib/Doctrine/ORM/Mapping/PostUpdate.php index a55f7072a69..3ee2dcaecd8 100644 --- a/lib/Doctrine/ORM/Mapping/PostUpdate.php +++ b/lib/Doctrine/ORM/Mapping/PostUpdate.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("METHOD") */ +#[Attribute(Attribute::TARGET_METHOD)] final class PostUpdate implements Annotation { } diff --git a/lib/Doctrine/ORM/Mapping/PreFlush.php b/lib/Doctrine/ORM/Mapping/PreFlush.php index 6697d372c37..341d2ef88b3 100644 --- a/lib/Doctrine/ORM/Mapping/PreFlush.php +++ b/lib/Doctrine/ORM/Mapping/PreFlush.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("METHOD") */ +#[Attribute(Attribute::TARGET_METHOD)] final class PreFlush implements Annotation { } diff --git a/lib/Doctrine/ORM/Mapping/PrePersist.php b/lib/Doctrine/ORM/Mapping/PrePersist.php index fea05be6d3d..a0b2969bf2e 100644 --- a/lib/Doctrine/ORM/Mapping/PrePersist.php +++ b/lib/Doctrine/ORM/Mapping/PrePersist.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("METHOD") */ +#[Attribute(Attribute::TARGET_METHOD)] final class PrePersist implements Annotation { } diff --git a/lib/Doctrine/ORM/Mapping/PreRemove.php b/lib/Doctrine/ORM/Mapping/PreRemove.php index 29822edacc9..402153f7bb1 100644 --- a/lib/Doctrine/ORM/Mapping/PreRemove.php +++ b/lib/Doctrine/ORM/Mapping/PreRemove.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("METHOD") */ +#[Attribute(Attribute::TARGET_METHOD)] final class PreRemove implements Annotation { } diff --git a/lib/Doctrine/ORM/Mapping/PreUpdate.php b/lib/Doctrine/ORM/Mapping/PreUpdate.php index 290df72e04a..4b04a65acc1 100644 --- a/lib/Doctrine/ORM/Mapping/PreUpdate.php +++ b/lib/Doctrine/ORM/Mapping/PreUpdate.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("METHOD") */ +#[Attribute(Attribute::TARGET_METHOD)] final class PreUpdate implements Annotation { } diff --git a/lib/Doctrine/ORM/Mapping/SequenceGenerator.php b/lib/Doctrine/ORM/Mapping/SequenceGenerator.php index ba1c45b6425..f53c84bd9ab 100644 --- a/lib/Doctrine/ORM/Mapping/SequenceGenerator.php +++ b/lib/Doctrine/ORM/Mapping/SequenceGenerator.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("PROPERTY") */ +#[Attribute(Attribute::TARGET_PROPERTY)] final class SequenceGenerator implements Annotation { /** diff --git a/lib/Doctrine/ORM/Mapping/Table.php b/lib/Doctrine/ORM/Mapping/Table.php index 6ed703750be..cceff201082 100644 --- a/lib/Doctrine/ORM/Mapping/Table.php +++ b/lib/Doctrine/ORM/Mapping/Table.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("CLASS") */ +#[Attribute(Attribute::TARGET_CLASS)] final class Table implements Annotation { /** diff --git a/lib/Doctrine/ORM/Mapping/UniqueConstraint.php b/lib/Doctrine/ORM/Mapping/UniqueConstraint.php index f117d1873e8..ce087a8c266 100644 --- a/lib/Doctrine/ORM/Mapping/UniqueConstraint.php +++ b/lib/Doctrine/ORM/Mapping/UniqueConstraint.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("ANNOTATION") */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] final class UniqueConstraint implements Annotation { /** diff --git a/lib/Doctrine/ORM/Mapping/Version.php b/lib/Doctrine/ORM/Mapping/Version.php index a2377027950..ac01fea5384 100644 --- a/lib/Doctrine/ORM/Mapping/Version.php +++ b/lib/Doctrine/ORM/Mapping/Version.php @@ -19,10 +19,13 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target("PROPERTY") */ +#[Attribute(Attribute::TARGET_PROPERTY)] final class Version implements Annotation { } diff --git a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php index 3eab2d6ae5c..8fdad5500eb 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php @@ -4,6 +4,7 @@ use Doctrine\ORM\EntityManager; use Doctrine\ORM\Events; +use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadataFactory; use Doctrine\ORM\Mapping\ClassMetadataInfo; @@ -1310,12 +1311,15 @@ public static function loadMetadata(ClassMetadataInfo $metadata) * @DiscriminatorMap({"cat" = "Cat", "dog" = "Dog"}) * @DiscriminatorColumn(name="discr", length=32, type="string") */ +#[ORM\Entity, ORM\InheritanceType("SINGLE_TABLE"), ORM\DiscriminatorColumn(name: "discr", length: 32, type: "string")] +#[ORM\DiscriminatorMap(["cat" => "Cat", "dog" => "Dog"])] abstract class Animal { /** * @Id @Column(type="string") @GeneratedValue(strategy="CUSTOM") * @CustomIdGenerator(class="stdClass") */ + #[ORM\Id, ORM\Column(type: "string"), ORM\GeneratedValue(strategy: "CUSTOM")] public $id; public static function loadMetadata(ClassMetadataInfo $metadata) @@ -1326,6 +1330,7 @@ public static function loadMetadata(ClassMetadataInfo $metadata) } /** @Entity */ +#[ORM\Entity] class Cat extends Animal { public static function loadMetadata(ClassMetadataInfo $metadata) @@ -1335,6 +1340,7 @@ public static function loadMetadata(ClassMetadataInfo $metadata) } /** @Entity */ +#[ORM\Entity] class Dog extends Animal { public static function loadMetadata(ClassMetadataInfo $metadata) @@ -1346,6 +1352,7 @@ public static function loadMetadata(ClassMetadataInfo $metadata) /** * @Entity */ +#[ORM\Entity] class DDC1170Entity { @@ -1362,11 +1369,13 @@ function __construct($value = null) * @GeneratedValue(strategy="NONE") * @Column(type="integer", columnDefinition = "INT unsigned NOT NULL") **/ + #[ORM\Id, ORM\GeneratedValue(strategy: "NONE"), ORM\Column(type: "integer", columnDefinition: "INT UNSIGNED NOT NULL")] private $id; /** * @Column(columnDefinition = "VARCHAR(255) NOT NULL") */ + #[ORM\Column(columnDefinition: "VARCHAR(255) NOT NULL")] private $value; /** @@ -1413,6 +1422,9 @@ public static function loadMetadata(ClassMetadataInfo $metadata) * @DiscriminatorMap({"ONE" = "DDC807SubClasse1", "TWO" = "DDC807SubClasse2"}) * @DiscriminatorColumn(name = "dtype", columnDefinition="ENUM('ONE','TWO')") */ +#[ORM\Entity, ORM\InheritanceType("SINGLE_TABLE")] +#[ORM\DiscriminatorColumn(name: "dtype", columnDefinition: "ENUM('ONE','TWO')")] +#[ORM\DiscriminatorMap(["ONE" => "DDC807SubClasse1", "TWO" => "DDC807SubClasse2"])] class DDC807Entity { /** @@ -1420,6 +1432,7 @@ class DDC807Entity * @Column(type="integer") * @GeneratedValue(strategy="NONE") **/ + #[ORM\Id, ORM\Column(type: "integer"), ORM\GeneratedValue(strategy: "NONE")] public $id; public static function loadMetadata(ClassMetadataInfo $metadata) @@ -1454,11 +1467,14 @@ class Group {} * @Entity * @Table(indexes={@Index(columns={"content"}, flags={"fulltext"}, options={"where": "content IS NOT NULL"})}) */ +#[ORM\Entity, ORM\Table(name: "Comment")] +#[ORM\Index(columns: ["content"], flags: ["fulltext"], options: ["where": "content IS NOT NULL"])] class Comment { /** * @Column(type="text") */ + #[ORM\Column(type: "text")] private $content; public static function loadMetadata(ClassMetadataInfo $metadata) @@ -1495,6 +1511,8 @@ public static function loadMetadata(ClassMetadataInfo $metadata) * "TWO" = "SingleTableEntityNoDiscriminatorColumnMappingSub2" * }) */ +#[ORM\Entity, ORM\InheritanceType("SINGLE_TABLE")] +#[ORM\DiscriminatorMap(["ONE" => "SingleTableEntityNoDiscriminatorColumnMappingSub1", "TWO" => "SingleTableEntityNoDiscriminatorColumnMappingSub2"])] class SingleTableEntityNoDiscriminatorColumnMapping { /** @@ -1502,6 +1520,7 @@ class SingleTableEntityNoDiscriminatorColumnMapping * @Column(type="integer") * @GeneratedValue(strategy="NONE") */ + #[ORM\Id, ORM\Column(type: "integer"), ORM\GeneratedValue(strategy: "NONE")] public $id; public static function loadMetadata(ClassMetadataInfo $metadata) @@ -1529,6 +1548,9 @@ class SingleTableEntityNoDiscriminatorColumnMappingSub2 extends SingleTableEntit * }) * @DiscriminatorColumn(name="dtype") */ +#[ORM\Entity, ORM\InheritanceType("SINGLE_TABLE")] +#[ORM\DiscriminatorMap(["ONE" => "SingleTableEntityNoDiscriminatorColumnMappingSub1", "TWO" => "SingleTableEntityNoDiscriminatorColumnMappingSub2"])] +#[ORM\DiscriminatorColumn(name: "dtype")] class SingleTableEntityIncompleteDiscriminatorColumnMapping { /** @@ -1536,6 +1558,7 @@ class SingleTableEntityIncompleteDiscriminatorColumnMapping * @Column(type="integer") * @GeneratedValue(strategy="NONE") */ + #[ORM\Id, ORM\Column(type: "integer"), ORM\GeneratedValue(strategy: "NONE")] public $id; public static function loadMetadata(ClassMetadataInfo $metadata) diff --git a/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php new file mode 100644 index 00000000000..4fc52ec7770 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php @@ -0,0 +1,15 @@ + Date: Sun, 15 Nov 2020 13:46:10 +0100 Subject: [PATCH 02/37] [GH-8265] Skip AttributeDriverTest on PHP 7. --- tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php index 4fc52ec7770..ea862e00f57 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php @@ -6,6 +6,14 @@ class AttributeDriverTest extends AbstractMappingDriverTest { + /** @before */ + public function requiresPhp8Assertion() + { + if (PHP_VERSION_ID <= 80000) { + $this->markTestSkipped('requies PHP 8.0'); + } + } + protected function _loadDriver() { $paths = []; From d0167459a442cf64b37d47fd6442de5766c691d8 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Sun, 15 Nov 2020 15:20:57 +0100 Subject: [PATCH 03/37] [GH-8265] Fill more test entities with Attribute declarations to pass tests. --- .../ORM/Mapping/Driver/AttributeReader.php | 7 +++--- .../ORM/Mapping/Driver/AttributesDriver.php | 12 +++++----- lib/Doctrine/ORM/Mapping/JoinColumn.php | 2 ++ .../DDC1476EntityWithDefaultFieldType.php | 6 ++++- .../Models/DDC869/DDC869ChequePayment.php | 5 +++- .../Models/DDC869/DDC869CreditCardPayment.php | 4 ++++ .../Tests/Models/DDC869/DDC869Payment.php | 7 ++++-- .../ORM/Mapping/AbstractMappingDriverTest.php | 23 ++++++++++++++++++- .../Tests/ORM/Mapping/AttributeDriverTest.php | 2 +- 9 files changed, 53 insertions(+), 15 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php b/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php index a4ad4806980..a537dccd070 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php @@ -48,7 +48,8 @@ private function convertToAttributeInstances(array $attributes) foreach ($attributes as $attribute) { // Make sure we only get Doctrine Annotations if (is_subclass_of($attribute->getName(), Annotation::class)) { - $instance = new $attribute->getName(); + $attributeClassName = $attribute->getName(); + $instance = new $attributeClassName; $arguments = $attribute->getArguments(); // unnamed argument is automatically "value" in Doctrine Annotations @@ -80,8 +81,8 @@ private function isRepeatable(string $attributeClassName) : bool } $reflectionClass = new \ReflectionClass($attributeClassName); - $attribute = $reflectionClass->getAttributes()[0]; + $attribute = $reflectionClass->getAttributes()[0]->newInstance(); - return $this->isRepeatableAttribute[$attributeClassName] = $attribute->flags && Attribute::IS_REPEATABLE; + return $this->isRepeatableAttribute[$attributeClassName] = $attribute->flags & \Attribute::IS_REPEATABLE; } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php b/lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php index aebab108918..099c4573318 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php @@ -182,8 +182,10 @@ public function loadMetadataForClass($className, ClassMetadata $metadata) // Check for JoinColumn/JoinColumns annotations $joinColumns = []; - if ($joinColumnAttribute = $this->reader->getPropertyAnnotation($property, Mapping\JoinColumn::class)) { - $joinColumns[] = $this->joinColumnToArray($joinColumnAttribute); + if ($joinColumnAttributes = $this->reader->getPropertyAnnotation($property, Mapping\JoinColumn::class)) { + foreach ($joinColumnAttributes as $joinColumnAttribute) { + $joinColumns[] = $this->joinColumnToArray($joinColumnAttribute); + } } // Field can only be annotated with one of: @@ -218,8 +220,6 @@ public function loadMetadataForClass($className, ClassMetadata $metadata) 'initialValue' => $seqGeneratorAttribute->initialValue ] ); - } else if ($this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\TableGenerator')) { - throw MappingException::tableIdGeneratorNotImplemented($className); } else if ($customGeneratorAttribute = $this->reader->getPropertyAnnotation($property, Mapping\CustomIdGenerator::class)) { $metadata->setCustomGeneratorDefinition( [ @@ -428,7 +428,7 @@ private function getMethodCallbacks(\ReflectionMethod $method) /** * Parse the given JoinColumn as array * - * @param Mapping\JoinColumn $joinColumn + * @param Mapping\JoinColumn|Mapping\InverseJoinColumn $joinColumn * * @return mixed[] * @@ -441,7 +441,7 @@ private function getMethodCallbacks(\ReflectionMethod $method) * referencedColumnName: string * } */ - private function joinColumnToArray(Mapping\JoinColumn $joinColumn) + private function joinColumnToArray(object $joinColumn) { return [ 'name' => $joinColumn->name, diff --git a/lib/Doctrine/ORM/Mapping/JoinColumn.php b/lib/Doctrine/ORM/Mapping/JoinColumn.php index 751946861d4..86651fa0851 100644 --- a/lib/Doctrine/ORM/Mapping/JoinColumn.php +++ b/lib/Doctrine/ORM/Mapping/JoinColumn.php @@ -19,6 +19,8 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * @Annotation * @Target({"PROPERTY","ANNOTATION"}) diff --git a/tests/Doctrine/Tests/Models/DDC1476/DDC1476EntityWithDefaultFieldType.php b/tests/Doctrine/Tests/Models/DDC1476/DDC1476EntityWithDefaultFieldType.php index b543b0fe589..581a54e0836 100644 --- a/tests/Doctrine/Tests/Models/DDC1476/DDC1476EntityWithDefaultFieldType.php +++ b/tests/Doctrine/Tests/Models/DDC1476/DDC1476EntityWithDefaultFieldType.php @@ -2,20 +2,24 @@ namespace Doctrine\Tests\Models\DDC1476; +use Doctrine\ORM\Mapping as ORM; + /** * @Entity() */ +#[ORM\Entity] class DDC1476EntityWithDefaultFieldType { - /** * @Id * @Column() * @GeneratedValue("NONE") */ + #[ORM\Id, ORM\Column, ORM\GeneratedValue("NONE")] protected $id; /** @column() */ + #[ORM\Column] protected $name; /** diff --git a/tests/Doctrine/Tests/Models/DDC869/DDC869ChequePayment.php b/tests/Doctrine/Tests/Models/DDC869/DDC869ChequePayment.php index 4690e068a4c..73771b823f8 100644 --- a/tests/Doctrine/Tests/Models/DDC869/DDC869ChequePayment.php +++ b/tests/Doctrine/Tests/Models/DDC869/DDC869ChequePayment.php @@ -2,13 +2,16 @@ namespace Doctrine\Tests\Models\DDC869; +use Doctrine\ORM\Mapping as ORM; + /** * @Entity */ +#[ORM\Entity] class DDC869ChequePayment extends DDC869Payment { - /** @Column(type="string") */ + #[ORM\Column(type: "string")] protected $serialNumber; public static function loadMetadata(\Doctrine\ORM\Mapping\ClassMetadataInfo $metadata) diff --git a/tests/Doctrine/Tests/Models/DDC869/DDC869CreditCardPayment.php b/tests/Doctrine/Tests/Models/DDC869/DDC869CreditCardPayment.php index 6f314e31889..0a7e61dc9dc 100644 --- a/tests/Doctrine/Tests/Models/DDC869/DDC869CreditCardPayment.php +++ b/tests/Doctrine/Tests/Models/DDC869/DDC869CreditCardPayment.php @@ -2,13 +2,17 @@ namespace Doctrine\Tests\Models\DDC869; +use Doctrine\ORM\Mapping as ORM; + /** * @Entity */ +#[ORM\Entity] class DDC869CreditCardPayment extends DDC869Payment { /** @Column(type="string") */ + #[ORM\Column(type: "string")] protected $creditCardNumber; public static function loadMetadata(\Doctrine\ORM\Mapping\ClassMetadataInfo $metadata) diff --git a/tests/Doctrine/Tests/Models/DDC869/DDC869Payment.php b/tests/Doctrine/Tests/Models/DDC869/DDC869Payment.php index 992c53ae27a..5d37c8f08a3 100644 --- a/tests/Doctrine/Tests/Models/DDC869/DDC869Payment.php +++ b/tests/Doctrine/Tests/Models/DDC869/DDC869Payment.php @@ -2,23 +2,26 @@ namespace Doctrine\Tests\Models\DDC869; +use Doctrine\ORM\Mapping as ORM; + /** * @MappedSuperclass(repositoryClass = "Doctrine\Tests\Models\DDC869\DDC869PaymentRepository") */ +#[ORM\MappedSuperclass(repositoryClass: DDC869PaymentRepository::class)] class DDC869Payment { - /** * @Id * @Column(type="integer") * @GeneratedValue */ + #[ORM\Id, ORM\Column(type: "integer"), ORM\GeneratedValue] protected $id; /** @Column(type="float") */ + #[ORM\Column(type: "float")] protected $value; - public static function loadMetadata(\Doctrine\ORM\Mapping\ClassMetadataInfo $metadata) { $metadata->mapField( diff --git a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php index 8fdad5500eb..ac31299dead 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php @@ -1092,6 +1092,10 @@ public function testDiscriminatorColumnDefaultName() * ) * @NamedQueries({@NamedQuery(name="all", query="SELECT u FROM __CLASS__ u")}) */ +#[ORM\Entity(), ORM\HasLifecycleCallbacks()] +#[ORM\Table(name: "cms_users", options: ["foo" => "bar", "baz" => ["key" => "val"]])] +#[ORM\Index(name: "name_idx", columns: ["name"]), ORM\Index(name: "0", columns: ["user_email"])] +#[ORM\UniqueConstraint(name: "search_idx", columns: ["name", "user_email"], options: ["where" => "name IS NOT NULL"])] class User { /** @@ -1100,28 +1104,37 @@ class User * @generatedValue(strategy="AUTO") * @SequenceGenerator(sequenceName="tablename_seq", initialValue=1, allocationSize=100) **/ + #[ORM\Id, ORM\Column(type: "integer", options: ["foo" => "bar", "unsigned" => false])] + #[ORM\GeneratedValue(strategy: "AUTO")] + #[ORM\SequenceGenerator(sequenceName: "tablename_seq", initialValue: 1, allocationSize: 100)] public $id; /** * @Column(length=50, nullable=true, unique=true, options={"foo": "bar", "baz": {"key": "val"}, "fixed": false}) */ + #[ORM\Column(length: 50, nullable: true, unique: true, options: ["foo" => "bar", "baz" => ["key" => "val"], "fixed" => false])] public $name; /** * @Column(name="user_email", columnDefinition="CHAR(32) NOT NULL") */ + #[ORM\Column(name: "user_email", columnDefinition: "CHAR(32) NOT NULL")] public $email; /** * @OneToOne(targetEntity="Address", cascade={"remove"}, inversedBy="user") * @JoinColumn(onDelete="CASCADE") */ + #[ORM\OneToOne(targetEntity: "Address", cascade: ["remove"], inverstedBy: "user")] + #[ORM\JoinColumn(onDelete: "CASCADE")] public $address; /** * @OneToMany(targetEntity="Phonenumber", mappedBy="user", cascade={"persist"}, orphanRemoval=true) * @OrderBy({"number"="ASC"}) */ + #[ORM\OneToMany(targetEntity: "Phonenumber", mappedBy: "user", cascade: ["persist"], orphanRemoval: true)] + #[ORM\OrderBy(["number" => "ASC"])] public $phonenumbers; /** @@ -1131,18 +1144,24 @@ class User * inverseJoinColumns={@JoinColumn(name="group_id", referencedColumnName="id", columnDefinition="INT NULL")} * ) */ + #[ORM\ManyToMany(targetEntity: "Group", cascade: ["all"])] + #[ORM\JoinTable(name: "cms_user_groups")] + #[ORM\JoinColumn(name: "user_id", referencedColumnName: "id", nullable: false, unique: false)] + #[ORM\InverseJoinColumn(name: "group_id", referencedColumnName: "id", columnDefinition: "INT NULL")] public $groups; /** * @Column(type="integer") * @Version */ + #[ORM\Column(type: "integer"), ORM\Version] public $version; /** * @PrePersist */ + #[ORM\PrePersist] public function doStuffOnPrePersist() { } @@ -1150,12 +1169,14 @@ public function doStuffOnPrePersist() /** * @PrePersist */ + #[ORM\PrePersist] public function doOtherStuffOnPrePersistToo() { } /** * @PostPersist */ + #[ORM\PostPersist] public function doStuffOnPostPersist() { @@ -1468,7 +1489,7 @@ class Group {} * @Table(indexes={@Index(columns={"content"}, flags={"fulltext"}, options={"where": "content IS NOT NULL"})}) */ #[ORM\Entity, ORM\Table(name: "Comment")] -#[ORM\Index(columns: ["content"], flags: ["fulltext"], options: ["where": "content IS NOT NULL"])] +#[ORM\Index(columns: ["content"], flags: ["fulltext"], options: ["where" => "content IS NOT NULL"])] class Comment { /** diff --git a/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php index ea862e00f57..2651705f2ff 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php @@ -9,7 +9,7 @@ class AttributeDriverTest extends AbstractMappingDriverTest /** @before */ public function requiresPhp8Assertion() { - if (PHP_VERSION_ID <= 80000) { + if (PHP_VERSION_ID < 80000) { $this->markTestSkipped('requies PHP 8.0'); } } From adbdb598edf5542be7ee730681495e3bc014a31b Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Sun, 15 Nov 2020 17:24:55 +0100 Subject: [PATCH 04/37] [GH-8265] More test entity attributes for passing AttributeDriverTest. --- lib/Doctrine/ORM/Mapping/EntityListeners.php | 3 ++ .../Doctrine/Tests/Models/CMS/CmsAddress.php | 6 ++++ tests/Doctrine/Tests/Models/Cache/City.php | 3 ++ .../Tests/Models/Company/CompanyContract.php | 8 +++++ .../Models/Company/CompanyFixContract.php | 3 ++ .../Models/Company/CompanyFlexContract.php | 3 ++ .../Company/CompanyFlexUltraContract.php | 4 +++ .../DDC1476EntityWithDefaultFieldType.php | 2 +- .../Models/DDC2825/ExplicitSchemaAndTable.php | 4 +++ .../DDC2825/SchemaAndTableInTableName.php | 4 +++ .../Tests/Models/DDC889/DDC889Entity.php | 3 ++ .../Tests/Models/DDC889/DDC889SuperClass.php | 5 ++- .../ORM/Functional/Ticket/DDC2825Test.php | 3 ++ .../ORM/Mapping/AbstractMappingDriverTest.php | 3 +- .../Tests/ORM/Mapping/AttributeDriverTest.php | 35 +++++++++++++++++++ 15 files changed, 86 insertions(+), 3 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/EntityListeners.php b/lib/Doctrine/ORM/Mapping/EntityListeners.php index ae6c9126bd7..ff2c14ba7d3 100644 --- a/lib/Doctrine/ORM/Mapping/EntityListeners.php +++ b/lib/Doctrine/ORM/Mapping/EntityListeners.php @@ -20,6 +20,8 @@ namespace Doctrine\ORM\Mapping; +use Attribute; + /** * 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. @@ -30,6 +32,7 @@ * @Annotation * @Target("CLASS") */ +#[Attribute(Attribute::TARGET_CLASS)] final class EntityListeners implements Annotation { /** diff --git a/tests/Doctrine/Tests/Models/CMS/CmsAddress.php b/tests/Doctrine/Tests/Models/CMS/CmsAddress.php index f5c0b9af766..9aa1b8ca9de 100644 --- a/tests/Doctrine/Tests/Models/CMS/CmsAddress.php +++ b/tests/Doctrine/Tests/Models/CMS/CmsAddress.php @@ -2,6 +2,8 @@ namespace Doctrine\Tests\Models\CMS; +use Doctrine\ORM\Mapping as ORM; + /** * CmsAddress * @@ -61,12 +63,16 @@ * * @EntityListeners({"CmsAddressListener"}) */ +#[ORM\Entity] +#[ORM\Table(name: "cms_addresses")] +#[ORM\Entitylisteners(["CmsAddressListener"])] class CmsAddress { /** * @Column(type="integer") * @Id @GeneratedValue */ + #[ORM\Id, ORM\GeneratedValue, ORM\Column(type: "integer")] public $id; /** diff --git a/tests/Doctrine/Tests/Models/Cache/City.php b/tests/Doctrine/Tests/Models/Cache/City.php index b3769fbe779..29323f2f11b 100644 --- a/tests/Doctrine/Tests/Models/Cache/City.php +++ b/tests/Doctrine/Tests/Models/Cache/City.php @@ -3,12 +3,14 @@ namespace Doctrine\Tests\Models\Cache; use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\ORM\Mapping as ORM; /** * @Cache * @Entity * @Table("cache_city") */ +#[ORM\Entity, ORM\Table(name: "cache_city"), ORM\Cache] class City { /** @@ -16,6 +18,7 @@ class City * @GeneratedValue * @Column(type="integer") */ + #[ORM\Id, ORM\GeneratedValue, ORM\Column(type: "integer")] protected $id; /** diff --git a/tests/Doctrine/Tests/Models/Company/CompanyContract.php b/tests/Doctrine/Tests/Models/Company/CompanyContract.php index 15e691ba087..092bcb9bd9a 100644 --- a/tests/Doctrine/Tests/Models/Company/CompanyContract.php +++ b/tests/Doctrine/Tests/Models/Company/CompanyContract.php @@ -2,6 +2,8 @@ namespace Doctrine\Tests\Models\Company; +use Doctrine\ORM\Mapping as ORM; + /** * @Entity * @Table(name="company_contracts") @@ -56,11 +58,17 @@ * ), * }) */ +#[ORM\Entity, ORM\Table(name: "company_contracts")] +#[ORM\InheritanceType("SINGLE_TABLE")] +#[ORM\DiscriminatorColumn(name: "discr", type: "string")] +#[ORM\DiscriminatorMap(["fix" => "CompanyFixContract", "flexible" => "CompanyFlexContract", "flexultra" => "CompanyFlexUltraContract"])] +#[ORM\EntityListeners(["CompanyContractListener"])] abstract class CompanyContract { /** * @Id @column(type="integer") @GeneratedValue */ + #[ORM\Id, ORM\Column(type: "integer"), ORM\GeneratedValue] private $id; /** diff --git a/tests/Doctrine/Tests/Models/Company/CompanyFixContract.php b/tests/Doctrine/Tests/Models/Company/CompanyFixContract.php index 8fe94e2584d..6cfc7d754ed 100644 --- a/tests/Doctrine/Tests/Models/Company/CompanyFixContract.php +++ b/tests/Doctrine/Tests/Models/Company/CompanyFixContract.php @@ -2,9 +2,12 @@ namespace Doctrine\Tests\Models\Company; +use Doctrine\ORM\Mapping as ORM; + /** * @Entity */ +#[ORM\Entity] class CompanyFixContract extends CompanyContract { /** diff --git a/tests/Doctrine/Tests/Models/Company/CompanyFlexContract.php b/tests/Doctrine/Tests/Models/Company/CompanyFlexContract.php index 978e8d5e6cd..e73ab282f2b 100644 --- a/tests/Doctrine/Tests/Models/Company/CompanyFlexContract.php +++ b/tests/Doctrine/Tests/Models/Company/CompanyFlexContract.php @@ -1,6 +1,8 @@ markTestSkipped('AttributeDriver does not support named queries.'); + } + + public function testNamedNativeQuery() + { + $this->markTestSkipped('AttributeDriver does not support named native queries.'); + } + + public function testSqlResultSetMapping() + { + $this->markTestSkipped('AttributeDriver does not support named sql resultset mapping.'); + } + + public function testAssociationOverridesMapping() + { + $this->markTestSkipped('AttributeDriver does not support association overrides.'); + } + + public function testInversedByOverrideMapping() + { + $this->markTestSkipped('AttributeDriver does not support association overrides.'); + } + + public function testFetchOverrideMapping() + { + $this->markTestSkipped('AttributeDriver does not support association overrides.'); + } + + public function testAttributeOverridesMapping() + { + $this->markTestSkipped('AttributeDriver does not support association overrides.'); + } } \ No newline at end of file From 4ba39979de3ed8f276b513b6544e0c63776f9181 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Sun, 15 Nov 2020 17:46:32 +0100 Subject: [PATCH 05/37] [GH-8265] Final changes to get AttributeDriverTest passing with test entities. --- tests/Doctrine/Tests/Models/CMS/CmsAddress.php | 2 +- tests/Doctrine/Tests/Models/Cache/City.php | 11 +++++++++-- .../Tests/Models/Company/CompanyContractListener.php | 10 ++++++++++ .../Company/CompanyFlexUltraContractListener.php | 3 +++ .../Tests/ORM/Mapping/AbstractMappingDriverTest.php | 4 ++-- 5 files changed, 25 insertions(+), 5 deletions(-) diff --git a/tests/Doctrine/Tests/Models/CMS/CmsAddress.php b/tests/Doctrine/Tests/Models/CMS/CmsAddress.php index 9aa1b8ca9de..464e14da8ae 100644 --- a/tests/Doctrine/Tests/Models/CMS/CmsAddress.php +++ b/tests/Doctrine/Tests/Models/CMS/CmsAddress.php @@ -65,7 +65,7 @@ */ #[ORM\Entity] #[ORM\Table(name: "cms_addresses")] -#[ORM\Entitylisteners(["CmsAddressListener"])] +#[ORM\EntityListeners(["CmsAddressListener"])] class CmsAddress { /** diff --git a/tests/Doctrine/Tests/Models/Cache/City.php b/tests/Doctrine/Tests/Models/Cache/City.php index 29323f2f11b..76108e61cef 100644 --- a/tests/Doctrine/Tests/Models/Cache/City.php +++ b/tests/Doctrine/Tests/Models/Cache/City.php @@ -24,6 +24,7 @@ class City /** * @Column(unique=true) */ + #[ORM\Column(unique: true)] protected $name; /** @@ -31,18 +32,24 @@ class City * @ManyToOne(targetEntity="State", inversedBy="cities") * @JoinColumn(name="state_id", referencedColumnName="id") */ + #[ORM\Cache] + #[ORM\ManyToOne(targetEntity: "State", inversedBy: "citities")] + #[ORM\JoinColumn(name: "state_id", referencedColumnName: "id")] protected $state; - /** + /** * @ManyToMany(targetEntity="Travel", mappedBy="visitedCities") */ + #[ORM\ManyToMany(targetEntity: "Travel", mappedBy: "visitedCities")] public $travels; - /** + /** * @Cache * @OrderBy({"name" = "ASC"}) * @OneToMany(targetEntity="Attraction", mappedBy="city") */ + #[ORM\Cache, ORM\OrderBy(["name" => "ASC"])] + #[ORM\OneToMany(targetEntity: "Attraction", mappedBy: "city")] public $attractions; public function __construct($name, State $state = null) diff --git a/tests/Doctrine/Tests/Models/Company/CompanyContractListener.php b/tests/Doctrine/Tests/Models/Company/CompanyContractListener.php index 23714f32983..91201f0b276 100644 --- a/tests/Doctrine/Tests/Models/Company/CompanyContractListener.php +++ b/tests/Doctrine/Tests/Models/Company/CompanyContractListener.php @@ -2,6 +2,8 @@ namespace Doctrine\Tests\Models\Company; +use Doctrine\ORM\Mapping as ORM; + class CompanyContractListener { public $postPersistCalls; @@ -20,6 +22,7 @@ class CompanyContractListener /** * @PostPersist */ + #[ORM\PostPersist] public function postPersistHandler(CompanyContract $contract) { $this->postPersistCalls[] = func_get_args(); @@ -28,6 +31,7 @@ public function postPersistHandler(CompanyContract $contract) /** * @PrePersist */ + #[ORM\PrePersist] public function prePersistHandler(CompanyContract $contract) { $this->prePersistCalls[] = func_get_args(); @@ -36,6 +40,7 @@ public function prePersistHandler(CompanyContract $contract) /** * @PostUpdate */ + #[ORM\PostUpdate] public function postUpdateHandler(CompanyContract $contract) { $this->postUpdateCalls[] = func_get_args(); @@ -44,6 +49,7 @@ public function postUpdateHandler(CompanyContract $contract) /** * @PreUpdate */ + #[ORM\PreUpdate] public function preUpdateHandler(CompanyContract $contract) { $this->preUpdateCalls[] = func_get_args(); @@ -52,6 +58,7 @@ public function preUpdateHandler(CompanyContract $contract) /** * @PostRemove */ + #[ORM\PostRemove] public function postRemoveHandler(CompanyContract $contract) { $this->postRemoveCalls[] = func_get_args(); @@ -60,6 +67,7 @@ public function postRemoveHandler(CompanyContract $contract) /** * @PreRemove */ + #[ORM\PreRemove] public function preRemoveHandler(CompanyContract $contract) { $this->preRemoveCalls[] = func_get_args(); @@ -68,6 +76,7 @@ public function preRemoveHandler(CompanyContract $contract) /** * @PreFlush */ + #[ORM\PreFlush] public function preFlushHandler(CompanyContract $contract) { $this->preFlushCalls[] = func_get_args(); @@ -76,6 +85,7 @@ public function preFlushHandler(CompanyContract $contract) /** * @PostLoad */ + #[ORM\PostLoad] public function postLoadHandler(CompanyContract $contract) { $this->postLoadCalls[] = func_get_args(); diff --git a/tests/Doctrine/Tests/Models/Company/CompanyFlexUltraContractListener.php b/tests/Doctrine/Tests/Models/Company/CompanyFlexUltraContractListener.php index 2f028e35f0f..be3e477e09c 100644 --- a/tests/Doctrine/Tests/Models/Company/CompanyFlexUltraContractListener.php +++ b/tests/Doctrine/Tests/Models/Company/CompanyFlexUltraContractListener.php @@ -3,6 +3,7 @@ namespace Doctrine\Tests\Models\Company; use Doctrine\ORM\Event\LifecycleEventArgs; +use Doctrine\ORM\Mapping as ORM; class CompanyFlexUltraContractListener { @@ -11,6 +12,7 @@ class CompanyFlexUltraContractListener /** * @PrePersist */ + #[ORM\PrePersist] public function prePersistHandler1(CompanyContract $contract, LifecycleEventArgs $args) { $this->prePersistCalls[] = func_get_args(); @@ -19,6 +21,7 @@ public function prePersistHandler1(CompanyContract $contract, LifecycleEventArgs /** * @PrePersist */ + #[ORM\PrePersist] public function prePersistHandler2(CompanyContract $contract, LifecycleEventArgs $args) { $this->prePersistCalls[] = func_get_args(); diff --git a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php index f565e2c575a..2073a47d5a6 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php @@ -514,8 +514,8 @@ public function testIdentifierColumnDefinition() $this->assertArrayHasKey('columnDefinition', $class->fieldMappings['id']); $this->assertArrayHasKey('columnDefinition', $class->fieldMappings['value']); - $this->assertEquals("INT unsigned NOT NULL", $class->fieldMappings['id']['columnDefinition']); - $this->assertEquals("VARCHAR(255) NOT NULL", $class->fieldMappings['value']['columnDefinition']); + $this->assertEquals("int unsigned not null", strtolower($class->fieldMappings['id']['columnDefinition'])); + $this->assertEquals("varchar(255) not null", strtolower($class->fieldMappings['value']['columnDefinition'])); } /** From ddded4430957a0875bf623bbc659b22139b5aa3b Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Sun, 15 Nov 2020 18:26:47 +0100 Subject: [PATCH 06/37] [GH-8265] automatically update cs for new code when possible. --- .../ORM/Mapping/Driver/AttributesDriver.php | 158 +++++++++--------- .../Tests/ORM/Mapping/AttributeDriverTest.php | 22 ++- 2 files changed, 94 insertions(+), 86 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php b/lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php index 099c4573318..b152c57a164 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php @@ -1,19 +1,27 @@ 1, Mapping\MappedSuperclass::class => 2, @@ -24,9 +32,9 @@ public function __construct(array $paths) parent::__construct(new AttributeReader(), $paths); } - public function loadMetadataForClass($className, ClassMetadata $metadata) + public function loadMetadataForClass($className, ClassMetadata $metadata): void { - /* @var $metadata \Doctrine\ORM\Mapping\ClassMetadataInfo */ + /** @var ClassMetadataInfo $metadata */ $reflectionClass = $metadata->getReflectionClass(); $classAttributes = $this->reader->getClassAnnotations($reflectionClass); @@ -41,12 +49,12 @@ public function loadMetadataForClass($className, ClassMetadata $metadata) if ($entityAttribute->readOnly) { $metadata->markReadOnly(); } - } else if (isset($classAttributes[Mapping\MappedSuperclass::class])) { + } elseif (isset($classAttributes[Mapping\MappedSuperclass::class])) { $mappedSuperclassAttribute = $classAttributes[Mapping\MappedSuperclass::class]; $metadata->setCustomRepositoryClass($mappedSuperclassAttribute->repositoryClass); $metadata->isMappedSuperclass = true; - } else if (isset($classAttributes[Mapping\Embeddable::class])) { + } elseif (isset($classAttributes[Mapping\Embeddable::class])) { $metadata->isEmbeddedClass = true; } else { throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className); @@ -57,22 +65,22 @@ public function loadMetadataForClass($className, ClassMetadata $metadata) $tableAnnot = $classAttributes[Mapping\Table::class]; $primaryTable = [ 'name' => $tableAnnot->name, - 'schema' => $tableAnnot->schema + 'schema' => $tableAnnot->schema, ]; if (isset($classAttributes[Mapping\Index::class])) { foreach ($classAttributes[Mapping\Index::class] as $indexAnnot) { $index = ['columns' => $indexAnnot->columns]; - if ( ! empty($indexAnnot->flags)) { + if (! empty($indexAnnot->flags)) { $index['flags'] = $indexAnnot->flags; } - if ( ! empty($indexAnnot->options)) { + if (! empty($indexAnnot->options)) { $index['options'] = $indexAnnot->options; } - if ( ! empty($indexAnnot->name)) { + if (! empty($indexAnnot->name)) { $primaryTable['indexes'][$indexAnnot->name] = $index; } else { $primaryTable['indexes'][] = $index; @@ -84,11 +92,11 @@ public function loadMetadataForClass($className, ClassMetadata $metadata) foreach ($classAttributes[Mapping\UniqueConstraint::class] as $uniqueConstraintAnnot) { $uniqueConstraint = ['columns' => $uniqueConstraintAnnot->columns]; - if ( ! empty($uniqueConstraintAnnot->options)) { + if (! empty($uniqueConstraintAnnot->options)) { $uniqueConstraint['options'] = $uniqueConstraintAnnot->options; } - if ( ! empty($uniqueConstraintAnnot->name)) { + if (! empty($uniqueConstraintAnnot->name)) { $primaryTable['uniqueConstraints'][$uniqueConstraintAnnot->name] = $uniqueConstraint; } else { $primaryTable['uniqueConstraints'][] = $uniqueConstraint; @@ -106,7 +114,7 @@ public function loadMetadataForClass($className, ClassMetadata $metadata) // Evaluate @Cache annotation if (isset($classAttributes[Mapping\Cache::class])) { $cacheAttribute = $classAttributes[Mapping\Cache::class]; - $cacheMap = [ + $cacheMap = [ 'region' => $cacheAttribute->region, 'usage' => constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $cacheAttribute->usage), ]; @@ -122,7 +130,7 @@ public function loadMetadataForClass($className, ClassMetadata $metadata) constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceTypeAttribute->value) ); - if ($metadata->inheritanceType != Mapping\ClassMetadata::INHERITANCE_TYPE_NONE) { + if ($metadata->inheritanceType !== Mapping\ClassMetadata::INHERITANCE_TYPE_NONE) { // Evaluate DiscriminatorColumn annotation if (isset($classAttributes[Mapping\DiscriminatorColumn::class])) { $discrColumnAttribute = $classAttributes[Mapping\DiscriminatorColumn::class]; @@ -153,20 +161,21 @@ public function loadMetadataForClass($className, ClassMetadata $metadata) $metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_' . $changeTrackingAttribute->value)); } - // Evaluate annotations on properties/fields - /* @var $property \ReflectionProperty */ foreach ($reflectionClass->getProperties() as $property) { - if ($metadata->isMappedSuperclass && ! $property->isPrivate() + assert($property instanceof ReflectionProperty); + if ( + $metadata->isMappedSuperclass && ! $property->isPrivate() || $metadata->isInheritedField($property->name) || $metadata->isInheritedAssociation($property->name) || - $metadata->isInheritedEmbeddedClass($property->name)) { + $metadata->isInheritedEmbeddedClass($property->name) + ) { continue; } - $mapping = []; + $mapping = []; $mapping['fieldName'] = $property->getName(); // Evaluate @Cache annotation @@ -179,6 +188,7 @@ public function loadMetadataForClass($className, ClassMetadata $metadata) ] ); } + // Check for JoinColumn/JoinColumns annotations $joinColumns = []; @@ -191,7 +201,7 @@ public function loadMetadataForClass($className, ClassMetadata $metadata) // Field can only be annotated with one of: // @Column, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany if ($columnAttribute = $this->reader->getPropertyAnnotation($property, Mapping\Column::class)) { - if ($columnAttribute->type == null) { + if ($columnAttribute->type === null) { throw MappingException::propertyTypeIsRequired($className, $property->getName()); } @@ -217,60 +227,60 @@ public function loadMetadataForClass($className, ClassMetadata $metadata) [ 'sequenceName' => $seqGeneratorAttribute->sequenceName, 'allocationSize' => $seqGeneratorAttribute->allocationSize, - 'initialValue' => $seqGeneratorAttribute->initialValue + 'initialValue' => $seqGeneratorAttribute->initialValue, ] ); - } else if ($customGeneratorAttribute = $this->reader->getPropertyAnnotation($property, Mapping\CustomIdGenerator::class)) { + } elseif ($customGeneratorAttribute = $this->reader->getPropertyAnnotation($property, Mapping\CustomIdGenerator::class)) { $metadata->setCustomGeneratorDefinition( [ - 'class' => $customGeneratorAttribute->class + 'class' => $customGeneratorAttribute->class, ] ); } - } else if ($oneToOneAttribute = $this->reader->getPropertyAnnotation($property, Mapping\OneToOne::class)) { + } elseif ($oneToOneAttribute = $this->reader->getPropertyAnnotation($property, Mapping\OneToOne::class)) { if ($this->reader->getPropertyAnnotation($property, Mapping\Id::class)) { $mapping['id'] = true; } - $mapping['targetEntity'] = $oneToOneAttribute->targetEntity; - $mapping['joinColumns'] = $joinColumns; - $mapping['mappedBy'] = $oneToOneAttribute->mappedBy; - $mapping['inversedBy'] = $oneToOneAttribute->inversedBy; - $mapping['cascade'] = $oneToOneAttribute->cascade; + $mapping['targetEntity'] = $oneToOneAttribute->targetEntity; + $mapping['joinColumns'] = $joinColumns; + $mapping['mappedBy'] = $oneToOneAttribute->mappedBy; + $mapping['inversedBy'] = $oneToOneAttribute->inversedBy; + $mapping['cascade'] = $oneToOneAttribute->cascade; $mapping['orphanRemoval'] = $oneToOneAttribute->orphanRemoval; - $mapping['fetch'] = $this->getFetchMode($className, $oneToOneAttribute->fetch); + $mapping['fetch'] = $this->getFetchMode($className, $oneToOneAttribute->fetch); $metadata->mapOneToOne($mapping); - } else if ($oneToManyAttribute = $this->reader->getPropertyAnnotation($property, Mapping\OneToMany::class)) { - $mapping['mappedBy'] = $oneToManyAttribute->mappedBy; - $mapping['targetEntity'] = $oneToManyAttribute->targetEntity; - $mapping['cascade'] = $oneToManyAttribute->cascade; - $mapping['indexBy'] = $oneToManyAttribute->indexBy; + } elseif ($oneToManyAttribute = $this->reader->getPropertyAnnotation($property, Mapping\OneToMany::class)) { + $mapping['mappedBy'] = $oneToManyAttribute->mappedBy; + $mapping['targetEntity'] = $oneToManyAttribute->targetEntity; + $mapping['cascade'] = $oneToManyAttribute->cascade; + $mapping['indexBy'] = $oneToManyAttribute->indexBy; $mapping['orphanRemoval'] = $oneToManyAttribute->orphanRemoval; - $mapping['fetch'] = $this->getFetchMode($className, $oneToManyAttribute->fetch); + $mapping['fetch'] = $this->getFetchMode($className, $oneToManyAttribute->fetch); if ($orderByAttribute = $this->reader->getPropertyAnnotation($property, Mapping\OrderBy::class)) { $mapping['orderBy'] = $orderByAttribute->value; } $metadata->mapOneToMany($mapping); - } else if ($manyToOneAttribute = $this->reader->getPropertyAnnotation($property, Mapping\ManyToOne::class)) { + } elseif ($manyToOneAttribute = $this->reader->getPropertyAnnotation($property, Mapping\ManyToOne::class)) { if ($idAttribute = $this->reader->getPropertyAnnotation($property, Mapping\Id::class)) { $mapping['id'] = true; } - $mapping['joinColumns'] = $joinColumns; - $mapping['cascade'] = $manyToOneAttribute->cascade; - $mapping['inversedBy'] = $manyToOneAttribute->inversedBy; + $mapping['joinColumns'] = $joinColumns; + $mapping['cascade'] = $manyToOneAttribute->cascade; + $mapping['inversedBy'] = $manyToOneAttribute->inversedBy; $mapping['targetEntity'] = $manyToOneAttribute->targetEntity; - $mapping['fetch'] = $this->getFetchMode($className, $manyToOneAttribute->fetch); + $mapping['fetch'] = $this->getFetchMode($className, $manyToOneAttribute->fetch); $metadata->mapManyToOne($mapping); - } else if ($manyToManyAttribute = $this->reader->getPropertyAnnotation($property, Mapping\ManyToMany::class)) { + } elseif ($manyToManyAttribute = $this->reader->getPropertyAnnotation($property, Mapping\ManyToMany::class)) { $joinTable = []; if ($joinTableAttribute = $this->reader->getPropertyAnnotation($property, Mapping\JoinTable::class)) { $joinTable = [ 'name' => $joinTableAttribute->name, - 'schema' => $joinTableAttribute->schema + 'schema' => $joinTableAttribute->schema, ]; foreach ($this->reader->getPropertyAnnotation($property, Mapping\JoinColumn::class) as $joinColumn) { @@ -282,22 +292,22 @@ public function loadMetadataForClass($className, ClassMetadata $metadata) } } - $mapping['joinTable'] = $joinTable; - $mapping['targetEntity'] = $manyToManyAttribute->targetEntity; - $mapping['mappedBy'] = $manyToManyAttribute->mappedBy; - $mapping['inversedBy'] = $manyToManyAttribute->inversedBy; - $mapping['cascade'] = $manyToManyAttribute->cascade; - $mapping['indexBy'] = $manyToManyAttribute->indexBy; + $mapping['joinTable'] = $joinTable; + $mapping['targetEntity'] = $manyToManyAttribute->targetEntity; + $mapping['mappedBy'] = $manyToManyAttribute->mappedBy; + $mapping['inversedBy'] = $manyToManyAttribute->inversedBy; + $mapping['cascade'] = $manyToManyAttribute->cascade; + $mapping['indexBy'] = $manyToManyAttribute->indexBy; $mapping['orphanRemoval'] = $manyToManyAttribute->orphanRemoval; - $mapping['fetch'] = $this->getFetchMode($className, $manyToManyAttribute->fetch); + $mapping['fetch'] = $this->getFetchMode($className, $manyToManyAttribute->fetch); if ($orderByAttribute = $this->reader->getPropertyAnnotation($property, Mapping\OrderBy::class)) { $mapping['orderBy'] = $orderByAttribute->value; } $metadata->mapManyToMany($mapping); - } else if ($embeddedAttribute = $this->reader->getPropertyAnnotation($property, Mapping\Embedded::class)) { - $mapping['class'] = $embeddedAttribute->class; + } elseif ($embeddedAttribute = $this->reader->getPropertyAnnotation($property, Mapping\Embedded::class)) { + $mapping['class'] = $embeddedAttribute->class; $mapping['columnPrefix'] = $embeddedAttribute->columnPrefix; $metadata->mapEmbedded($mapping); @@ -306,7 +316,6 @@ public function loadMetadataForClass($className, ClassMetadata $metadata) // Evaluate AttributeOverrides annotation if (isset($classAttributes[Mapping\AttributeOverride::class])) { - foreach ($classAttributes[Mapping\AttributeOverride::class] as $attributeOverrideAttribute) { $attributeOverride = $this->columnToArray($attributeOverrideAttribute->name, $attributeOverrideAttribute->column); @@ -321,18 +330,18 @@ public function loadMetadataForClass($className, ClassMetadata $metadata) foreach ($entityListenersAttribute->value as $item) { $listenerClassName = $metadata->fullyQualifiedClassName($item); - if ( ! class_exists($listenerClassName)) { + if (! class_exists($listenerClassName)) { throw MappingException::entityListenerClassNotFound($listenerClassName, $className); } - $hasMapping = false; - $listenerClass = new \ReflectionClass($listenerClassName); + $hasMapping = false; + $listenerClass = new ReflectionClass($listenerClassName); - /* @var $method \ReflectionMethod */ - foreach ($listenerClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) { + foreach ($listenerClass->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { + assert($method instanceof ReflectionMethod); // find method callbacks. $callbacks = $this->getMethodCallbacks($method); - $hasMapping = $hasMapping ?: ( ! empty($callbacks)); + $hasMapping = $hasMapping ?: ! empty($callbacks); foreach ($callbacks as $value) { $metadata->addEntityListener($value[1], $listenerClassName, $value[0]); @@ -340,7 +349,7 @@ public function loadMetadataForClass($className, ClassMetadata $metadata) } // Evaluate the listener using naming convention. - if ( ! $hasMapping ) { + if (! $hasMapping) { EntityListenerBuilder::bindEntityListener($metadata, $listenerClassName); } } @@ -348,8 +357,8 @@ public function loadMetadataForClass($className, ClassMetadata $metadata) // Evaluate @HasLifecycleCallbacks annotation if (isset($classAttributes[Mapping\HasLifecycleCallbacks::class])) { - /* @var $method \ReflectionMethod */ - foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) { + foreach ($reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { + assert($method instanceof ReflectionMethod); foreach ($this->getMethodCallbacks($method) as $value) { $metadata->addLifecycleCallback($value[0], $value[1]); } @@ -363,13 +372,13 @@ public function loadMetadataForClass($className, ClassMetadata $metadata) * @param string $className The class name. * @param string $fetchMode The fetch mode. * - * @return integer The fetch mode as defined in ClassMetadata. + * @return int The fetch mode as defined in ClassMetadata. * * @throws MappingException If the fetch mode is not valid. */ - private function getFetchMode($className, $fetchMode) + private function getFetchMode(string $className, string $fetchMode): int { - if ( ! defined('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $fetchMode)) { + if (! defined('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $fetchMode)) { throw MappingException::invalidFetchMode($className, $fetchMode); } @@ -379,13 +388,11 @@ private function getFetchMode($className, $fetchMode) /** * Parses the given method. * - * @param \ReflectionMethod $method - * * @return callable[] */ - private function getMethodCallbacks(\ReflectionMethod $method) + private function getMethodCallbacks(ReflectionMethod $method): array { - $callbacks = []; + $callbacks = []; $attributes = $this->reader->getMethodAnnotations($method); foreach ($attributes as $attribute) { @@ -441,7 +448,7 @@ private function getMethodCallbacks(\ReflectionMethod $method) * referencedColumnName: string * } */ - private function joinColumnToArray(object $joinColumn) + private function joinColumnToArray(object $joinColumn): array { return [ 'name' => $joinColumn->name, @@ -456,9 +463,6 @@ private function joinColumnToArray(object $joinColumn) /** * Parse the given Column as array * - * @param string $fieldName - * @param Mapping\Column $column - * * @return mixed[] * * @psalm-return array{ @@ -474,7 +478,7 @@ private function joinColumnToArray(object $joinColumn) * columnDefinition?: string * } */ - private function columnToArray($fieldName, Mapping\Column $column) + private function columnToArray(string $fieldName, Mapping\Column $column): array { $mapping = [ 'fieldName' => $fieldName, @@ -483,7 +487,7 @@ private function columnToArray($fieldName, Mapping\Column $column) 'length' => $column->length, 'unique' => $column->unique, 'nullable' => $column->nullable, - 'precision' => $column->precision + 'precision' => $column->precision, ]; if ($column->options) { @@ -500,4 +504,4 @@ private function columnToArray($fieldName, Mapping\Column $column) return $mapping; } -} \ No newline at end of file +} diff --git a/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php index 7771017b255..8e185e9f361 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php @@ -1,13 +1,17 @@ markTestSkipped('requies PHP 8.0'); @@ -21,38 +25,38 @@ protected function _loadDriver() return new AttributesDriver($paths); } - public function testNamedQuery() + public function testNamedQuery(): void { $this->markTestSkipped('AttributeDriver does not support named queries.'); } - public function testNamedNativeQuery() + public function testNamedNativeQuery(): void { $this->markTestSkipped('AttributeDriver does not support named native queries.'); } - public function testSqlResultSetMapping() + public function testSqlResultSetMapping(): void { $this->markTestSkipped('AttributeDriver does not support named sql resultset mapping.'); } - public function testAssociationOverridesMapping() + public function testAssociationOverridesMapping(): void { $this->markTestSkipped('AttributeDriver does not support association overrides.'); } - public function testInversedByOverrideMapping() + public function testInversedByOverrideMapping(): void { $this->markTestSkipped('AttributeDriver does not support association overrides.'); } - public function testFetchOverrideMapping() + public function testFetchOverrideMapping(): void { $this->markTestSkipped('AttributeDriver does not support association overrides.'); } - public function testAttributeOverridesMapping() + public function testAttributeOverridesMapping(): void { $this->markTestSkipped('AttributeDriver does not support association overrides.'); } -} \ No newline at end of file +} From 76d6fb6b427f9c5c84dda8176fe256a67df9e26f Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Sun, 15 Nov 2020 18:36:57 +0100 Subject: [PATCH 07/37] [GH-8265] exclude sniffs that break because of phpcs not knowing attributes. --- phpcs.xml.dist | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 68bcaa5f4b0..e55dd9a5f2e 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -22,6 +22,12 @@ + + + + + + From 78d999fe1aba853d38f908f7f94220faadeba261 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Sun, 15 Nov 2020 18:46:48 +0100 Subject: [PATCH 08/37] [GH-8265] Fix AttributeReader styles. --- .../ORM/Mapping/Driver/AttributeReader.php | 51 ++++++++++++------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php b/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php index a537dccd070..1aecca6a1a8 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php @@ -1,47 +1,64 @@ */ - private $isRepeatableAttribute = []; + private array $isRepeatableAttribute = []; - function getClassAnnotations(\ReflectionClass $class) + /** @return array */ + public function getClassAnnotations(ReflectionClass $class): array { return $this->convertToAttributeInstances($class->getAttributes()); } - function getClassAnnotation(\ReflectionClass $class, $annotationName) + public function getClassAnnotation(ReflectionClass $class, $annotationName): ?object { return $this->getClassAnnotations($class)[$annotationName] ?? ($this->isRepeatable($annotationName) ? [] : null); } - function getMethodAnnotations(\ReflectionMethod $method) + /** @return array */ + public function getMethodAnnotations(ReflectionMethod $method): array { return $this->convertToAttributeInstances($method->getAttributes()); } - function getMethodAnnotation(\ReflectionMethod $method, $annotationName) + public function getMethodAnnotation(ReflectionMethod $method, $annotationName): ?object { return $this->getMethodAnnotations($method)[$annotationName] ?? ($this->isRepeatable($annotationName) ? [] : null); } - function getPropertyAnnotations(\ReflectionProperty $property) + /** @return array */ + public function getPropertyAnnotations(ReflectionProperty $property): array { return $this->convertToAttributeInstances($property->getAttributes()); } - function getPropertyAnnotation(\ReflectionProperty $property, $annotationName) + public function getPropertyAnnotation(ReflectionProperty $property, $annotationName): ?object { return $this->getPropertyAnnotations($property)[$annotationName] ?? ($this->isRepeatable($annotationName) ? [] : null); } - private function convertToAttributeInstances(array $attributes) + /** + * @param array $attributes + * + * @return array + */ + private function convertToAttributeInstances(array $attributes): array { $instances = []; @@ -49,8 +66,8 @@ private function convertToAttributeInstances(array $attributes) // Make sure we only get Doctrine Annotations if (is_subclass_of($attribute->getName(), Annotation::class)) { $attributeClassName = $attribute->getName(); - $instance = new $attributeClassName; - $arguments = $attribute->getArguments(); + $instance = new $attributeClassName(); + $arguments = $attribute->getArguments(); // unnamed argument is automatically "value" in Doctrine Annotations if (count($arguments) >= 1 && isset($arguments[0])) { @@ -74,15 +91,15 @@ private function convertToAttributeInstances(array $attributes) return $instances; } - private function isRepeatable(string $attributeClassName) : bool + private function isRepeatable(string $attributeClassName): bool { if (isset($this->isRepeatableAttribute[$attributeClassName])) { return $this->isRepeatableAttribute[$attributeClassName]; } - $reflectionClass = new \ReflectionClass($attributeClassName); - $attribute = $reflectionClass->getAttributes()[0]->newInstance(); + $reflectionClass = new ReflectionClass($attributeClassName); + $attribute = $reflectionClass->getAttributes()[0]->newInstance(); - return $this->isRepeatableAttribute[$attributeClassName] = $attribute->flags & \Attribute::IS_REPEATABLE; + return $this->isRepeatableAttribute[$attributeClassName] = ($attribute->flags & Attribute::IS_REPEATABLE) > 0; } -} \ No newline at end of file +} From cf3d052c6fe2a396b5fa3be8b57408bd64ce31f0 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Sun, 15 Nov 2020 18:56:05 +0100 Subject: [PATCH 09/37] [GH-8265] Fix AttributeReader styles. --- lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php b/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php index 1aecca6a1a8..52bf1820c19 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php @@ -26,7 +26,8 @@ public function getClassAnnotations(ReflectionClass $class): array return $this->convertToAttributeInstances($class->getAttributes()); } - public function getClassAnnotation(ReflectionClass $class, $annotationName): ?object + /** @return array|?object */ + public function getClassAnnotation(ReflectionClass $class, $annotationName) { return $this->getClassAnnotations($class)[$annotationName] ?? ($this->isRepeatable($annotationName) ? [] : null); } @@ -37,7 +38,8 @@ public function getMethodAnnotations(ReflectionMethod $method): array return $this->convertToAttributeInstances($method->getAttributes()); } - public function getMethodAnnotation(ReflectionMethod $method, $annotationName): ?object + /** @return array|?object */ + public function getMethodAnnotation(ReflectionMethod $method, $annotationName) { return $this->getMethodAnnotations($method)[$annotationName] ?? ($this->isRepeatable($annotationName) ? [] : null); } @@ -48,7 +50,8 @@ public function getPropertyAnnotations(ReflectionProperty $property): array return $this->convertToAttributeInstances($property->getAttributes()); } - public function getPropertyAnnotation(ReflectionProperty $property, $annotationName): ?object + /** @return array|?object */ + public function getPropertyAnnotation(ReflectionProperty $property, $annotationName) { return $this->getPropertyAnnotations($property)[$annotationName] ?? ($this->isRepeatable($annotationName) ? [] : null); } From cf4c09feb5ac2583f9c8cb12dd5a503e7fb10fc6 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Sun, 15 Nov 2020 19:06:12 +0100 Subject: [PATCH 10/37] [GH-8265] Missing changes to AttributeDriver --- .../ORM/Mapping/Driver/AttributesDriver.php | 71 +++++++++++++------ 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php b/lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php index b152c57a164..e7257a8de28 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php @@ -22,11 +22,15 @@ class AttributesDriver extends AnnotationDriver { - protected $entityAnnotationClasses = [ + /** @var array */ + protected array $entityAnnotationClasses = [ Mapping\Entity::class => 1, Mapping\MappedSuperclass::class => 2, ]; + /** + * @param array $paths + */ public function __construct(array $paths) { parent::__construct(new AttributeReader(), $paths); @@ -34,7 +38,8 @@ public function __construct(array $paths) public function loadMetadataForClass($className, ClassMetadata $metadata): void { - /** @var ClassMetadataInfo $metadata */ + assert($metadata instanceof ClassMetadataInfo); + $reflectionClass = $metadata->getReflectionClass(); $classAttributes = $this->reader->getClassAnnotations($reflectionClass); @@ -179,7 +184,8 @@ public function loadMetadataForClass($className, ClassMetadata $metadata): void $mapping['fieldName'] = $property->getName(); // Evaluate @Cache annotation - if (($cacheAttribute = $this->reader->getPropertyAnnotation($property, Mapping\Cache::class)) !== null) { + $cacheAttribute = $this->reader->getPropertyAnnotation($property, Mapping\Cache::class); + if ($cacheAttribute !== null) { $mapping['cache'] = $metadata->getAssociationCacheDefaults( $mapping['fieldName'], [ @@ -192,15 +198,22 @@ public function loadMetadataForClass($className, ClassMetadata $metadata): void // Check for JoinColumn/JoinColumns annotations $joinColumns = []; - if ($joinColumnAttributes = $this->reader->getPropertyAnnotation($property, Mapping\JoinColumn::class)) { - foreach ($joinColumnAttributes as $joinColumnAttribute) { - $joinColumns[] = $this->joinColumnToArray($joinColumnAttribute); - } + $joinColumnAttributes = $this->reader->getPropertyAnnotation($property, Mapping\JoinColumn::class); + + foreach ($joinColumnAttributes as $joinColumnAttribute) { + $joinColumns[] = $this->joinColumnToArray($joinColumnAttribute); } - // Field can only be annotated with one of: - // @Column, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany - if ($columnAttribute = $this->reader->getPropertyAnnotation($property, Mapping\Column::class)) { + // Field can only be attributed with one of: + // Column, OneToOne, OneToMany, ManyToOne, ManyToMany, Embedded + $columnAttribute = $this->reader->getPropertyAnnotation($property, Mapping\Column::class); + $oneToOneAttribute = $this->reader->getPropertyAnnotation($property, Mapping\OneToOne::class); + $oneToManyAttribute = $this->reader->getPropertyAnnotation($property, Mapping\OneToMany::class); + $manyToOneAttribute = $this->reader->getPropertyAnnotation($property, Mapping\ManyToOne::class); + $manyToManyAttribute = $this->reader->getPropertyAnnotation($property, Mapping\ManyToMany::class); + $embeddedAttribute = $this->reader->getPropertyAnnotation($property, Mapping\Embedded::class); + + if ($columnAttribute !== null) { if ($columnAttribute->type === null) { throw MappingException::propertyTypeIsRequired($className, $property->getName()); } @@ -211,7 +224,9 @@ public function loadMetadataForClass($className, ClassMetadata $metadata): void $mapping['id'] = true; } - if ($generatedValueAttribute = $this->reader->getPropertyAnnotation($property, Mapping\GeneratedValue::class)) { + $generatedValueAttribute = $this->reader->getPropertyAnnotation($property, Mapping\GeneratedValue::class); + + if ($generatedValueAttribute !== null) { $metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' . $generatedValueAttribute->strategy)); } @@ -222,7 +237,10 @@ public function loadMetadataForClass($className, ClassMetadata $metadata): void $metadata->mapField($mapping); // Check for SequenceGenerator/TableGenerator definition - if ($seqGeneratorAttribute = $this->reader->getPropertyAnnotation($property, Mapping\SequenceGenerator::class)) { + $seqGeneratorAttribute = $this->reader->getPropertyAnnotation($property, Mapping\SequenceGenerator::class); + $customGeneratorAttribute = $this->reader->getPropertyAnnotation($property, Mapping\CustomIdGenerator::class); + + if ($seqGeneratorAttribute !== null) { $metadata->setSequenceGeneratorDefinition( [ 'sequenceName' => $seqGeneratorAttribute->sequenceName, @@ -230,14 +248,14 @@ public function loadMetadataForClass($className, ClassMetadata $metadata): void 'initialValue' => $seqGeneratorAttribute->initialValue, ] ); - } elseif ($customGeneratorAttribute = $this->reader->getPropertyAnnotation($property, Mapping\CustomIdGenerator::class)) { + } elseif ($customGeneratorAttribute !== null) { $metadata->setCustomGeneratorDefinition( [ 'class' => $customGeneratorAttribute->class, ] ); } - } elseif ($oneToOneAttribute = $this->reader->getPropertyAnnotation($property, Mapping\OneToOne::class)) { + } elseif ($oneToOneAttribute !== null) { if ($this->reader->getPropertyAnnotation($property, Mapping\Id::class)) { $mapping['id'] = true; } @@ -250,7 +268,7 @@ public function loadMetadataForClass($className, ClassMetadata $metadata): void $mapping['orphanRemoval'] = $oneToOneAttribute->orphanRemoval; $mapping['fetch'] = $this->getFetchMode($className, $oneToOneAttribute->fetch); $metadata->mapOneToOne($mapping); - } elseif ($oneToManyAttribute = $this->reader->getPropertyAnnotation($property, Mapping\OneToMany::class)) { + } elseif ($oneToManyAttribute !== null) { $mapping['mappedBy'] = $oneToManyAttribute->mappedBy; $mapping['targetEntity'] = $oneToManyAttribute->targetEntity; $mapping['cascade'] = $oneToManyAttribute->cascade; @@ -258,13 +276,17 @@ public function loadMetadataForClass($className, ClassMetadata $metadata): void $mapping['orphanRemoval'] = $oneToManyAttribute->orphanRemoval; $mapping['fetch'] = $this->getFetchMode($className, $oneToManyAttribute->fetch); - if ($orderByAttribute = $this->reader->getPropertyAnnotation($property, Mapping\OrderBy::class)) { + $orderByAttribute = $this->reader->getPropertyAnnotation($property, Mapping\OrderBy::class); + + if ($orderByAttribute !== null) { $mapping['orderBy'] = $orderByAttribute->value; } $metadata->mapOneToMany($mapping); - } elseif ($manyToOneAttribute = $this->reader->getPropertyAnnotation($property, Mapping\ManyToOne::class)) { - if ($idAttribute = $this->reader->getPropertyAnnotation($property, Mapping\Id::class)) { + } elseif ($manyToOneAttribute !== null) { + $idAttribute = $this->reader->getPropertyAnnotation($property, Mapping\Id::class); + + if ($idAttribute !== null) { $mapping['id'] = true; } @@ -274,10 +296,11 @@ public function loadMetadataForClass($className, ClassMetadata $metadata): void $mapping['targetEntity'] = $manyToOneAttribute->targetEntity; $mapping['fetch'] = $this->getFetchMode($className, $manyToOneAttribute->fetch); $metadata->mapManyToOne($mapping); - } elseif ($manyToManyAttribute = $this->reader->getPropertyAnnotation($property, Mapping\ManyToMany::class)) { - $joinTable = []; + } elseif ($manyToManyAttribute !== null) { + $joinTable = []; + $joinTableAttribute = $this->reader->getPropertyAnnotation($property, Mapping\JoinTable::class); - if ($joinTableAttribute = $this->reader->getPropertyAnnotation($property, Mapping\JoinTable::class)) { + if ($joinTableAttribute !== null) { $joinTable = [ 'name' => $joinTableAttribute->name, 'schema' => $joinTableAttribute->schema, @@ -301,12 +324,14 @@ public function loadMetadataForClass($className, ClassMetadata $metadata): void $mapping['orphanRemoval'] = $manyToManyAttribute->orphanRemoval; $mapping['fetch'] = $this->getFetchMode($className, $manyToManyAttribute->fetch); - if ($orderByAttribute = $this->reader->getPropertyAnnotation($property, Mapping\OrderBy::class)) { + $orderByAttribute = $this->reader->getPropertyAnnotation($property, Mapping\OrderBy::class); + + if ($orderByAttribute !== null) { $mapping['orderBy'] = $orderByAttribute->value; } $metadata->mapManyToMany($mapping); - } elseif ($embeddedAttribute = $this->reader->getPropertyAnnotation($property, Mapping\Embedded::class)) { + } elseif ($embeddedAttribute !== null) { $mapping['class'] = $embeddedAttribute->class; $mapping['columnPrefix'] = $embeddedAttribute->columnPrefix; From 907579e85864681648619c4df97786d5761c403a Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Sun, 15 Nov 2020 19:08:09 +0100 Subject: [PATCH 11/37] [GH-8265] Fix InverseJoinColumn attribute cs violations. --- .../ORM/Mapping/InverseJoinColumn.php | 36 ++++++------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php b/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php index 14b5518b9c3..5f27d73a64e 100644 --- a/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php +++ b/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php @@ -1,4 +1,7 @@ Date: Sun, 15 Nov 2020 19:14:40 +0100 Subject: [PATCH 12/37] [GH-8265] Fix AbstractMappingDriverTest::_loadDriver and other CS --- .../ORM/Functional/Ticket/DDC3711Test.php | 2 +- .../ORM/Mapping/AbstractMappingDriverTest.php | 15 +++++++------ .../ORM/Mapping/AnnotationDriverTest.php | 21 ++++++++++--------- .../Tests/ORM/Mapping/AttributeDriverTest.php | 3 ++- .../ORM/Mapping/PHPMappingDriverTest.php | 5 +++-- .../Mapping/StaticPHPMappingDriverTest.php | 3 ++- .../ORM/Mapping/XmlMappingDriverTest.php | 17 ++++++++------- .../ORM/Mapping/YamlMappingDriverTest.php | 5 +++-- 8 files changed, 40 insertions(+), 31 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3711Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3711Test.php index dc633c7aa88..0ca5c1711e3 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3711Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3711Test.php @@ -17,7 +17,7 @@ class DDC3711Test extends YamlMappingDriverTest public function testCompositeKeyForJoinTableInManyToManyCreation() { - $yamlDriver = $this->_loadDriver(); + $yamlDriver = $this->loadDriver(); $em = $this->_getTestEntityManager(); $em->getConfiguration()->setMetadataDriverImpl($yamlDriver); diff --git a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php index 2073a47d5a6..7a0b3652727 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php @@ -13,6 +13,7 @@ use Doctrine\ORM\Mapping\Id; use Doctrine\ORM\Mapping\MappingException; use Doctrine\ORM\Mapping\UnderscoreNamingStrategy; +use Doctrine\Persistence\Mapping\Driver\MappingDriver; use Doctrine\Persistence\Mapping\RuntimeReflectionService; use Doctrine\Tests\Models\Cache\City; use Doctrine\Tests\Models\CMS\CmsAddress; @@ -39,13 +40,15 @@ use Doctrine\Tests\Models\DDC964\DDC964Guest; use Doctrine\Tests\OrmTestCase; +use function strtolower; + abstract class AbstractMappingDriverTest extends OrmTestCase { - abstract protected function _loadDriver(); + abstract protected function loadDriver(): MappingDriver; public function createClassMetadata($entityClassName) { - $mappingDriver = $this->_loadDriver(); + $mappingDriver = $this->loadDriver(); $class = new ClassMetadata($entityClassName); $class->initializeReflection(new RuntimeReflectionService()); @@ -60,7 +63,7 @@ public function createClassMetadata($entityClassName) */ protected function createClassMetadataFactory(EntityManager $em = null) { - $driver = $this->_loadDriver(); + $driver = $this->loadDriver(); $em = $em ?: $this->_getTestEntityManager(); $factory = new ClassMetadataFactory(); $em->getConfiguration()->setMetadataDriverImpl($driver); @@ -514,8 +517,8 @@ public function testIdentifierColumnDefinition() $this->assertArrayHasKey('columnDefinition', $class->fieldMappings['id']); $this->assertArrayHasKey('columnDefinition', $class->fieldMappings['value']); - $this->assertEquals("int unsigned not null", strtolower($class->fieldMappings['id']['columnDefinition'])); - $this->assertEquals("varchar(255) not null", strtolower($class->fieldMappings['value']['columnDefinition'])); + $this->assertEquals('int unsigned not null', strtolower($class->fieldMappings['id']['columnDefinition'])); + $this->assertEquals('varchar(255) not null', strtolower($class->fieldMappings['value']['columnDefinition'])); } /** @@ -579,7 +582,7 @@ public function testIdentifierRequiredShouldMentionParentClasses() public function testNamedQuery() { - $driver = $this->_loadDriver(); + $driver = $this->loadDriver(); $class = $this->createClassMetadata(User::class); $this->assertCount(1, $class->getNamedQueries(), sprintf("Named queries not processed correctly by driver %s", get_class($driver))); diff --git a/tests/Doctrine/Tests/ORM/Mapping/AnnotationDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AnnotationDriverTest.php index e4be969de85..9efb5442f46 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/AnnotationDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/AnnotationDriverTest.php @@ -11,6 +11,7 @@ use Doctrine\ORM\Mapping\ClassMetadataFactory; use Doctrine\ORM\Mapping\Driver\AnnotationDriver; use Doctrine\ORM\Mapping\MappingException; +use Doctrine\Persistence\Mapping\Driver\MappingDriver; use Doctrine\Persistence\Mapping\RuntimeReflectionService; use Doctrine\Tests\Models\CMS\CmsUser; use Doctrine\Tests\Models\DDC1872\DDC1872ExampleEntityWithoutOverride; @@ -39,7 +40,7 @@ public function testFailingSecondLevelCacheAssociation() { $this->expectException('Doctrine\ORM\Cache\CacheException'); $this->expectExceptionMessage('Entity association field "Doctrine\Tests\ORM\Mapping\AnnotationSLC#foo" not configured as part of the second-level cache.'); - $mappingDriver = $this->_loadDriver(); + $mappingDriver = $this->loadDriver(); $class = new ClassMetadata(AnnotationSLC::class); $mappingDriver->loadMetadataForClass(AnnotationSLC::class, $class); @@ -52,7 +53,7 @@ public function testColumnWithMissingTypeDefaultsToString() { $cm = new ClassMetadata(ColumnWithoutType::class); $cm->initializeReflection(new RuntimeReflectionService()); - $annotationDriver = $this->_loadDriver(); + $annotationDriver = $this->loadDriver(); $annotationDriver->loadMetadataForClass(Mapping\InvalidColumn::class, $cm); $this->assertEquals('string', $cm->fieldMappings['id']['type']); @@ -114,13 +115,13 @@ public function testGetClassNamesReturnsOnlyTheAppropriateClasses() protected function _loadDriverForCMSModels() { - $annotationDriver = $this->_loadDriver(); + $annotationDriver = $this->loadDriver(); $annotationDriver->addPaths([__DIR__ . '/../../Models/CMS/']); return $annotationDriver; } - protected function _loadDriver() + protected function loadDriver(): MappingDriver { return $this->createAnnotationDriver(); } @@ -137,7 +138,7 @@ protected function _ensureIsLoaded($entityClassName) */ public function testJoinTablesWithMappedSuperclassForAnnotationDriver() { - $annotationDriver = $this->_loadDriver(); + $annotationDriver = $this->loadDriver(); $annotationDriver->addPaths([__DIR__ . '/../../Models/DirectoryTree/']); $em = $this->_getTestEntityManager(); @@ -157,7 +158,7 @@ public function testJoinTablesWithMappedSuperclassForAnnotationDriver() */ public function testInvalidMappedSuperClassWithManyToManyAssociation() { - $annotationDriver = $this->_loadDriver(); + $annotationDriver = $this->loadDriver(); $em = $this->_getTestEntityManager(); $em->getConfiguration()->setMetadataDriverImpl($annotationDriver); @@ -178,7 +179,7 @@ public function testInvalidMappedSuperClassWithManyToManyAssociation() */ public function testInvalidMappedSuperClassWithInheritanceInformation() { - $annotationDriver = $this->_loadDriver(); + $annotationDriver = $this->loadDriver(); $em = $this->_getTestEntityManager(); $em->getConfiguration()->setMetadataDriverImpl($annotationDriver); @@ -199,7 +200,7 @@ public function testInvalidMappedSuperClassWithInheritanceInformation() */ public function testInheritanceSkipsParentLifecycleCallbacks() { - $annotationDriver = $this->_loadDriver(); + $annotationDriver = $this->loadDriver(); $em = $this->_getTestEntityManager(); $em->getConfiguration()->setMetadataDriverImpl($annotationDriver); @@ -218,7 +219,7 @@ public function testInheritanceSkipsParentLifecycleCallbacks() */ public function testMappedSuperclassInMiddleOfInheritanceHierarchy() { - $annotationDriver = $this->_loadDriver(); + $annotationDriver = $this->loadDriver(); $em = $this->_getTestEntityManager(); $em->getConfiguration()->setMetadataDriverImpl($annotationDriver); @@ -231,7 +232,7 @@ public function testMappedSuperclassInMiddleOfInheritanceHierarchy() public function testInvalidFetchOptionThrowsException() { - $annotationDriver = $this->_loadDriver(); + $annotationDriver = $this->loadDriver(); $em = $this->_getTestEntityManager(); $em->getConfiguration()->setMetadataDriverImpl($annotationDriver); diff --git a/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php index 8e185e9f361..1eba6682858 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php @@ -6,6 +6,7 @@ use Doctrine\ORM\Mapping\Driver\AttributesDriver; +use Doctrine\Persistence\Mapping\Driver\MappingDriver; use const PHP_VERSION_ID; class AttributeDriverTest extends AbstractMappingDriverTest @@ -18,7 +19,7 @@ public function requiresPhp8Assertion(): void } } - protected function _loadDriver() + protected function loadDriver(): MappingDriver { $paths = []; diff --git a/tests/Doctrine/Tests/ORM/Mapping/PHPMappingDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/PHPMappingDriverTest.php index 5a30fc36f03..7b67b742106 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/PHPMappingDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/PHPMappingDriverTest.php @@ -3,13 +3,14 @@ namespace Doctrine\Tests\ORM\Mapping; use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\Persistence\Mapping\Driver\MappingDriver; use Doctrine\Persistence\Mapping\Driver\PHPDriver; use Doctrine\Tests\Models\DDC889\DDC889Class; use Doctrine\Tests\ORM\Mapping; class PHPMappingDriverTest extends AbstractMappingDriverTest { - protected function _loadDriver() + protected function loadDriver(): MappingDriver { $path = __DIR__ . DIRECTORY_SEPARATOR . 'php'; @@ -39,7 +40,7 @@ public function testFailingSecondLevelCacheAssociation() { $this->expectException('Doctrine\ORM\Cache\CacheException'); $this->expectExceptionMessage('Entity association field "Doctrine\Tests\ORM\Mapping\PHPSLC#foo" not configured as part of the second-level cache.'); - $mappingDriver = $this->_loadDriver(); + $mappingDriver = $this->loadDriver(); $class = new ClassMetadata(Mapping\PHPSLC::class); $mappingDriver->loadMetadataForClass(Mapping\PHPSLC::class, $class); diff --git a/tests/Doctrine/Tests/ORM/Mapping/StaticPHPMappingDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/StaticPHPMappingDriverTest.php index bdce6343d19..f9e8855a8a2 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/StaticPHPMappingDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/StaticPHPMappingDriverTest.php @@ -3,12 +3,13 @@ namespace Doctrine\Tests\ORM\Mapping; use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\Persistence\Mapping\Driver\MappingDriver; use Doctrine\Persistence\Mapping\Driver\StaticPHPDriver; use Doctrine\Tests\Models\DDC889\DDC889Class; class StaticPHPMappingDriverTest extends AbstractMappingDriverTest { - protected function _loadDriver() + protected function loadDriver(): MappingDriver { return new StaticPHPDriver(__DIR__ . DIRECTORY_SEPARATOR . 'php'); } diff --git a/tests/Doctrine/Tests/ORM/Mapping/XmlMappingDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/XmlMappingDriverTest.php index 30180a9909b..4f973feeb04 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/XmlMappingDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/XmlMappingDriverTest.php @@ -6,6 +6,7 @@ use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadataFactory; use Doctrine\ORM\Mapping\Driver\XmlDriver; +use Doctrine\Persistence\Mapping\Driver\MappingDriver; use Doctrine\Persistence\Mapping\RuntimeReflectionService; use Doctrine\Tests\Models\DDC117\DDC117Translation; use Doctrine\Tests\Models\DDC3293\DDC3293User; @@ -19,14 +20,14 @@ class XmlMappingDriverTest extends AbstractMappingDriverTest { - protected function _loadDriver() + protected function loadDriver(): MappingDriver { return new XmlDriver(__DIR__ . DIRECTORY_SEPARATOR . 'xml'); } public function testClassTableInheritanceDiscriminatorMap() { - $mappingDriver = $this->_loadDriver(); + $mappingDriver = $this->loadDriver(); $class = new ClassMetadata(CTI::class); $class->initializeReflection(new RuntimeReflectionService()); @@ -46,7 +47,7 @@ public function testFailingSecondLevelCacheAssociation() { $this->expectException('Doctrine\ORM\Cache\CacheException'); $this->expectExceptionMessage('Entity association field "Doctrine\Tests\ORM\Mapping\XMLSLC#foo" not configured as part of the second-level cache.'); - $mappingDriver = $this->_loadDriver(); + $mappingDriver = $this->loadDriver(); $class = new ClassMetadata(XMLSLC::class); $mappingDriver->loadMetadataForClass(XMLSLC::class, $class); @@ -54,7 +55,7 @@ public function testFailingSecondLevelCacheAssociation() public function testIdentifierWithAssociationKey() { - $driver = $this->_loadDriver(); + $driver = $this->loadDriver(); $em = $this->_getTestEntityManager(); $factory = new ClassMetadataFactory(); @@ -87,7 +88,7 @@ public function testEmbeddedMappingsWithUseColumnPrefix() $factory = new ClassMetadataFactory(); $em = $this->_getTestEntityManager(); - $em->getConfiguration()->setMetadataDriverImpl($this->_loadDriver()); + $em->getConfiguration()->setMetadataDriverImpl($this->loadDriver()); $factory->setEntityManager($em); $this->assertEquals( @@ -107,7 +108,7 @@ public function testEmbeddedMappingsWithFalseUseColumnPrefix() $factory = new ClassMetadataFactory(); $em = $this->_getTestEntityManager(); - $em->getConfiguration()->setMetadataDriverImpl($this->_loadDriver()); + $em->getConfiguration()->setMetadataDriverImpl($this->loadDriver()); $factory->setEntityManager($em); $this->assertFalse( @@ -179,7 +180,7 @@ static public function dataValidSchema() */ public function testOneToManyDefaultOrderByAsc() { - $driver = $this->_loadDriver(); + $driver = $this->loadDriver(); $class = new ClassMetadata(GH7141Article::class); $class->initializeReflection(new RuntimeReflectionService()); @@ -197,7 +198,7 @@ public function testManyToManyDefaultOrderByAsc() : void $class = new ClassMetadata(GH7316Article::class); $class->initializeReflection(new RuntimeReflectionService()); - $driver = $this->_loadDriver(); + $driver = $this->loadDriver(); $driver->loadMetadataForClass(GH7316Article::class, $class); self::assertEquals( diff --git a/tests/Doctrine/Tests/ORM/Mapping/YamlMappingDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/YamlMappingDriverTest.php index 1edc4a1010e..e8f9c602e02 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/YamlMappingDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/YamlMappingDriverTest.php @@ -5,6 +5,7 @@ use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadataFactory; use Doctrine\ORM\Mapping\Driver\YamlDriver; +use Doctrine\Persistence\Mapping\Driver\MappingDriver; use Doctrine\Tests\Models\DirectoryTree\Directory; use Doctrine\Tests\Models\DirectoryTree\File; use Doctrine\Tests\Models\Generic\SerializationModel; @@ -15,7 +16,7 @@ class YamlMappingDriverTest extends AbstractMappingDriverTest { use VerifyDeprecations; - protected function _loadDriver() + protected function loadDriver(): MappingDriver { if (!class_exists(Yaml::class, true)) { $this->markTestSkipped('Please install Symfony YAML Component into the include path of your PHP installation.'); @@ -31,7 +32,7 @@ protected function _loadDriver() */ public function testJoinTablesWithMappedSuperclassForYamlDriver() { - $yamlDriver = $this->_loadDriver(); + $yamlDriver = $this->loadDriver(); $yamlDriver->getLocator()->addPaths([__DIR__ . DIRECTORY_SEPARATOR . 'yaml']); $em = $this->_getTestEntityManager(); From 47fdf6ec1ebce1612e760b48118a5f4b0be40d40 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Sun, 15 Nov 2020 19:34:33 +0100 Subject: [PATCH 13/37] [GH-8265] Coding styles --- .../ORM/Mapping/Driver/AttributeReader.php | 49 ++++++++++--------- .../ORM/Mapping/AbstractMappingDriverTest.php | 6 +-- .../Tests/ORM/Mapping/AttributeDriverTest.php | 1 - 3 files changed, 30 insertions(+), 26 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php b/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php index 52bf1820c19..b6318b5c306 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php @@ -27,6 +27,7 @@ public function getClassAnnotations(ReflectionClass $class): array } /** @return array|?object */ + // phpcs:ignore public function getClassAnnotation(ReflectionClass $class, $annotationName) { return $this->getClassAnnotations($class)[$annotationName] ?? ($this->isRepeatable($annotationName) ? [] : null); @@ -39,6 +40,7 @@ public function getMethodAnnotations(ReflectionMethod $method): array } /** @return array|?object */ + // phpcs:ignore public function getMethodAnnotation(ReflectionMethod $method, $annotationName) { return $this->getMethodAnnotations($method)[$annotationName] ?? ($this->isRepeatable($annotationName) ? [] : null); @@ -51,13 +53,14 @@ public function getPropertyAnnotations(ReflectionProperty $property): array } /** @return array|?object */ + // phpcs:ignore public function getPropertyAnnotation(ReflectionProperty $property, $annotationName) { return $this->getPropertyAnnotations($property)[$annotationName] ?? ($this->isRepeatable($annotationName) ? [] : null); } /** - * @param array $attributes + * @param array $attributes * * @return array */ @@ -67,27 +70,29 @@ private function convertToAttributeInstances(array $attributes): array foreach ($attributes as $attribute) { // Make sure we only get Doctrine Annotations - if (is_subclass_of($attribute->getName(), Annotation::class)) { - $attributeClassName = $attribute->getName(); - $instance = new $attributeClassName(); - $arguments = $attribute->getArguments(); - - // unnamed argument is automatically "value" in Doctrine Annotations - if (count($arguments) >= 1 && isset($arguments[0])) { - $arguments['value'] = $arguments[0]; - unset($arguments[0]); - } - - // This works using the old Annotation, but will probably break Attribute IDE autocomplete support - foreach ($arguments as $name => $value) { - $instance->$name = $value; - } - - if ($this->isRepeatable($attribute->getName())) { - $instances[$attribute->getName()][] = $instance; - } else { - $instances[$attribute->getName()] = $instance; - } + if (! is_subclass_of($attribute->getName(), Annotation::class)) { + continue; + } + + $attributeClassName = $attribute->getName(); + $instance = new $attributeClassName(); + $arguments = $attribute->getArguments(); + + // unnamed argument is automatically "value" in Doctrine Annotations + if (count($arguments) >= 1 && isset($arguments[0])) { + $arguments['value'] = $arguments[0]; + unset($arguments[0]); + } + + // This works using the old Annotation, but will probably break Attribute IDE autocomplete support + foreach ($arguments as $name => $value) { + $instance->$name = $value; + } + + if ($this->isRepeatable($attribute->getName())) { + $instances[$attribute->getName()][] = $instance; + } else { + $instances[$attribute->getName()] = $instance; } } diff --git a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php index 7a0b3652727..18767710100 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php @@ -63,9 +63,9 @@ public function createClassMetadata($entityClassName) */ protected function createClassMetadataFactory(EntityManager $em = null) { - $driver = $this->loadDriver(); - $em = $em ?: $this->_getTestEntityManager(); - $factory = new ClassMetadataFactory(); + $driver = $this->loadDriver(); + $em = $em ?: $this->_getTestEntityManager(); + $factory = new ClassMetadataFactory(); $em->getConfiguration()->setMetadataDriverImpl($driver); $factory->setEntityManager($em); diff --git a/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php index 1eba6682858..84c540bae47 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php @@ -5,7 +5,6 @@ namespace Doctrine\Tests\ORM\Mapping; use Doctrine\ORM\Mapping\Driver\AttributesDriver; - use Doctrine\Persistence\Mapping\Driver\MappingDriver; use const PHP_VERSION_ID; From 8776b1d005619d2a86c6dc388a03e39b0ca78467 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Sun, 15 Nov 2020 19:35:18 +0100 Subject: [PATCH 14/37] [GH-8265] Coding styles --- lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php b/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php index b6318b5c306..3f62c8e41ac 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php @@ -26,8 +26,7 @@ public function getClassAnnotations(ReflectionClass $class): array return $this->convertToAttributeInstances($class->getAttributes()); } - /** @return array|?object */ - // phpcs:ignore + /** @return array|object|null */ public function getClassAnnotation(ReflectionClass $class, $annotationName) { return $this->getClassAnnotations($class)[$annotationName] ?? ($this->isRepeatable($annotationName) ? [] : null); @@ -39,8 +38,7 @@ public function getMethodAnnotations(ReflectionMethod $method): array return $this->convertToAttributeInstances($method->getAttributes()); } - /** @return array|?object */ - // phpcs:ignore + /** @return array|object|null */ public function getMethodAnnotation(ReflectionMethod $method, $annotationName) { return $this->getMethodAnnotations($method)[$annotationName] ?? ($this->isRepeatable($annotationName) ? [] : null); @@ -52,8 +50,7 @@ public function getPropertyAnnotations(ReflectionProperty $property): array return $this->convertToAttributeInstances($property->getAttributes()); } - /** @return array|?object */ - // phpcs:ignore + /** @return array|object|null */ public function getPropertyAnnotation(ReflectionProperty $property, $annotationName) { return $this->getPropertyAnnotations($property)[$annotationName] ?? ($this->isRepeatable($annotationName) ? [] : null); From b3659f12cbedd3ba4a8e923ba9688b2afaf90448 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Sun, 15 Nov 2020 19:37:43 +0100 Subject: [PATCH 15/37] [GH-8265] Coding styles --- tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php index 84c540bae47..22a12355917 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php @@ -6,6 +6,7 @@ use Doctrine\ORM\Mapping\Driver\AttributesDriver; use Doctrine\Persistence\Mapping\Driver\MappingDriver; + use const PHP_VERSION_ID; class AttributeDriverTest extends AbstractMappingDriverTest From 26a3f8d4f765e86ed5601a440be6f3d06cef5c62 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Sun, 15 Nov 2020 19:43:26 +0100 Subject: [PATCH 16/37] [GH-8265] Coding styles --- lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php | 4 ++-- lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php b/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php index 3f62c8e41ac..987f30887d1 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php @@ -72,13 +72,13 @@ private function convertToAttributeInstances(array $attributes): array } $attributeClassName = $attribute->getName(); - $instance = new $attributeClassName(); + $instance = new $attributeClassName(); // @phpstan-ignore-line $arguments = $attribute->getArguments(); // unnamed argument is automatically "value" in Doctrine Annotations if (count($arguments) >= 1 && isset($arguments[0])) { $arguments['value'] = $arguments[0]; - unset($arguments[0]); + unset($arguments[0]); // @phpstan-ignore-line } // This works using the old Annotation, but will probably break Attribute IDE autocomplete support diff --git a/lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php b/lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php index e7257a8de28..f939bf814e0 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php @@ -23,7 +23,8 @@ class AttributesDriver extends AnnotationDriver { /** @var array */ - protected array $entityAnnotationClasses = [ + // @phpcs:ignore + protected $entityAnnotationClasses = [ Mapping\Entity::class => 1, Mapping\MappedSuperclass::class => 2, ]; From 796f0be974921da04ff06363f898ea5d9f864baf Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Tue, 8 Dec 2020 04:32:16 +0100 Subject: [PATCH 17/37] [GH-8265] Convert Cache, ChangeTrackingPolicy, Column to named annotations. --- lib/Doctrine/ORM/Mapping/Annotation.php | 2 ++ lib/Doctrine/ORM/Mapping/Cache.php | 9 ++++++- .../ORM/Mapping/ChangeTrackingPolicy.php | 8 +++++- lib/Doctrine/ORM/Mapping/Column.php | 26 ++++++++++++++++++- 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/Annotation.php b/lib/Doctrine/ORM/Mapping/Annotation.php index 19374ff3146..929ae0efd46 100644 --- a/lib/Doctrine/ORM/Mapping/Annotation.php +++ b/lib/Doctrine/ORM/Mapping/Annotation.php @@ -19,6 +19,8 @@ namespace Doctrine\ORM\Mapping; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; + interface Annotation { } diff --git a/lib/Doctrine/ORM/Mapping/Cache.php b/lib/Doctrine/ORM/Mapping/Cache.php index b3e992e32f8..88bb5714e4b 100644 --- a/lib/Doctrine/ORM/Mapping/Cache.php +++ b/lib/Doctrine/ORM/Mapping/Cache.php @@ -20,6 +20,7 @@ namespace Doctrine\ORM\Mapping; use Attribute; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** * Caching to an entity or a collection. @@ -31,7 +32,7 @@ * @Target({"CLASS","PROPERTY"}) */ #[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_PROPERTY)] -final class Cache implements Annotation +final class Cache implements Annotation, NamedArgumentConstructorAnnotation { /** * @Enum({"READ_ONLY", "NONSTRICT_READ_WRITE", "READ_WRITE"}) @@ -44,4 +45,10 @@ final class Cache implements Annotation * @var string Cache region name. */ public $region; + + public function __construct(string $usage = 'READ_ONLY', ?string $region = null, $value = null) + { + $this->usage = $value ?: $usage; + $this->region = $region; + } } diff --git a/lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php b/lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php index 8121c1fc958..ab60c25526c 100644 --- a/lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php +++ b/lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php @@ -20,13 +20,14 @@ namespace Doctrine\ORM\Mapping; use Attribute; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** * @Annotation * @Target("CLASS") */ #[Attribute(Attribute::TARGET_CLASS)] -final class ChangeTrackingPolicy implements Annotation +final class ChangeTrackingPolicy implements Annotation, NamedArgumentConstructorAnnotation { /** * The change tracking policy. @@ -36,4 +37,9 @@ final class ChangeTrackingPolicy implements Annotation * @Enum({"DEFERRED_IMPLICIT", "DEFERRED_EXPLICIT", "NOTIFY"}) */ public $value; + + public function __construct(string $value) + { + $this->value = $value; + } } diff --git a/lib/Doctrine/ORM/Mapping/Column.php b/lib/Doctrine/ORM/Mapping/Column.php index 0c1a4c1a075..4d4705904ba 100644 --- a/lib/Doctrine/ORM/Mapping/Column.php +++ b/lib/Doctrine/ORM/Mapping/Column.php @@ -20,13 +20,14 @@ namespace Doctrine\ORM\Mapping; use Attribute; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** * @Annotation * @Target({"PROPERTY","ANNOTATION"}) */ #[Attribute(Attribute::TARGET_PROPERTY)] -final class Column implements Annotation +final class Column implements Annotation, NamedArgumentConstructorAnnotation { /** * @var string @@ -76,4 +77,27 @@ final class Column implements Annotation * @var string */ public $columnDefinition; + + public function __construct( + ?string $name = null, + string $type = 'string', + ?int $length = null, + ?int $precision = null, + ?int $scale = null, + bool $unique = false, + bool $nullable = false, + array $options = [], + ?string $columnDefinition = null + ) + { + $this->name = $name; + $this->type = $type; + $this->length = $length; + $this->precision = $precision; + $this->scale = $scale; + $this->unique = $unique; + $this->nullable = $nullable; + $this->options = $options; + $this->columnDefinition = $columnDefinition; + } } From 0a76534b84e3d8234b33e9bfbc0af7a093a6f38f Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Tue, 8 Dec 2020 05:24:24 +0100 Subject: [PATCH 18/37] [GH-8265] Convert all annotations to named constructor for attribute support. --- .../ORM/Mapping/CustomIdGenerator.php | 8 ++++++- .../ORM/Mapping/DiscriminatorColumn.php | 16 ++++++++++++- lib/Doctrine/ORM/Mapping/DiscriminatorMap.php | 8 ++++++- lib/Doctrine/ORM/Mapping/Embedded.php | 11 +++++++-- lib/Doctrine/ORM/Mapping/Entity.php | 9 ++++++- lib/Doctrine/ORM/Mapping/EntityListeners.php | 8 ++++++- lib/Doctrine/ORM/Mapping/GeneratedValue.php | 8 ++++++- lib/Doctrine/ORM/Mapping/Index.php | 15 +++++++++++- lib/Doctrine/ORM/Mapping/InheritanceType.php | 8 ++++++- .../ORM/Mapping/InverseJoinColumn.php | 24 ++++++++++--------- lib/Doctrine/ORM/Mapping/JoinColumn.php | 21 +++++++++++++++- lib/Doctrine/ORM/Mapping/JoinTable.php | 17 ++++++++++++- lib/Doctrine/ORM/Mapping/ManyToMany.php | 21 +++++++++++++++- lib/Doctrine/ORM/Mapping/ManyToOne.php | 15 +++++++++++- lib/Doctrine/ORM/Mapping/MappedSuperclass.php | 8 ++++++- lib/Doctrine/ORM/Mapping/OneToMany.php | 19 ++++++++++++++- lib/Doctrine/ORM/Mapping/OneToOne.php | 19 ++++++++++++++- lib/Doctrine/ORM/Mapping/OrderBy.php | 8 ++++++- .../ORM/Mapping/SequenceGenerator.php | 13 +++++++++- lib/Doctrine/ORM/Mapping/Table.php | 18 +++++++++++++- lib/Doctrine/ORM/Mapping/UniqueConstraint.php | 13 +++++++++- .../ORM/Mapping/AnnotationDriverTest.php | 4 ++-- 22 files changed, 257 insertions(+), 34 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/CustomIdGenerator.php b/lib/Doctrine/ORM/Mapping/CustomIdGenerator.php index a48ba1acb1b..b5159e78b56 100644 --- a/lib/Doctrine/ORM/Mapping/CustomIdGenerator.php +++ b/lib/Doctrine/ORM/Mapping/CustomIdGenerator.php @@ -20,16 +20,22 @@ namespace Doctrine\ORM\Mapping; use Attribute; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** * @Annotation * @Target("PROPERTY") */ #[Attribute(Attribute::TARGET_PROPERTY)] -final class CustomIdGenerator implements Annotation +final class CustomIdGenerator implements Annotation, NamedArgumentConstructorAnnotation { /** * @var string */ public $class; + + public function __construct(?string $class = null, ?string $value = null) + { + $this->class = $value ?: $class; + } } diff --git a/lib/Doctrine/ORM/Mapping/DiscriminatorColumn.php b/lib/Doctrine/ORM/Mapping/DiscriminatorColumn.php index 332f6d7ad5a..a2f0828282b 100644 --- a/lib/Doctrine/ORM/Mapping/DiscriminatorColumn.php +++ b/lib/Doctrine/ORM/Mapping/DiscriminatorColumn.php @@ -20,13 +20,14 @@ namespace Doctrine\ORM\Mapping; use Attribute; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** * @Annotation * @Target("CLASS") */ #[Attribute(Attribute::TARGET_CLASS)] -final class DiscriminatorColumn implements Annotation +final class DiscriminatorColumn implements Annotation, NamedArgumentConstructorAnnotation { /** * @var string @@ -54,4 +55,17 @@ final class DiscriminatorColumn implements Annotation * @var string */ public $columnDefinition; + + public function __construct( + ?string $name = null, + ?string $type = null, + ?int $length = null, + ?string $columnDefinition = null + ) + { + $this->name = $name; + $this->type = $type; + $this->length = $length; + $this->columnDefinition = $columnDefinition; + } } diff --git a/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php b/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php index 720b7dbe596..ad63c1f58de 100644 --- a/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php +++ b/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php @@ -20,16 +20,22 @@ namespace Doctrine\ORM\Mapping; use Attribute; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** * @Annotation * @Target("CLASS") */ #[Attribute(Attribute::TARGET_CLASS)] -final class DiscriminatorMap implements Annotation +final class DiscriminatorMap implements Annotation, NamedArgumentConstructorAnnotation { /** * @var array */ public $value; + + public function __construct(array $value) + { + $this->value = $value; + } } diff --git a/lib/Doctrine/ORM/Mapping/Embedded.php b/lib/Doctrine/ORM/Mapping/Embedded.php index 5da283efacc..c666d42e5e2 100644 --- a/lib/Doctrine/ORM/Mapping/Embedded.php +++ b/lib/Doctrine/ORM/Mapping/Embedded.php @@ -20,13 +20,14 @@ namespace Doctrine\ORM\Mapping; use Attribute; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** * @Annotation * @Target("PROPERTY") */ #[Attribute(Attribute::TARGET_PROPERTY)] -final class Embedded implements Annotation +final class Embedded implements Annotation, NamedArgumentConstructorAnnotation { /** * @Required @@ -35,7 +36,13 @@ final class Embedded implements Annotation public $class; /** - * @var mixed + * @var string|bool|null */ public $columnPrefix; + + public function __construct(string $class, $columnPrefix = null) + { + $this->class = $class; + $this->columnPrefix = $columnPrefix; + } } diff --git a/lib/Doctrine/ORM/Mapping/Entity.php b/lib/Doctrine/ORM/Mapping/Entity.php index 248a90be30e..79938f4eb39 100644 --- a/lib/Doctrine/ORM/Mapping/Entity.php +++ b/lib/Doctrine/ORM/Mapping/Entity.php @@ -20,13 +20,14 @@ namespace Doctrine\ORM\Mapping; use Attribute; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** * @Annotation * @Target("CLASS") */ #[Attribute(Attribute::TARGET_CLASS)] -final class Entity implements Annotation +final class Entity implements Annotation, NamedArgumentConstructorAnnotation { /** * @var string @@ -37,4 +38,10 @@ final class Entity implements Annotation * @var boolean */ public $readOnly = false; + + public function __construct(?string $repositoryClass = null, bool $readOnly = false) + { + $this->repositoryClass = $repositoryClass; + $this->readOnly = $readOnly; + } } diff --git a/lib/Doctrine/ORM/Mapping/EntityListeners.php b/lib/Doctrine/ORM/Mapping/EntityListeners.php index ff2c14ba7d3..fb69db524a7 100644 --- a/lib/Doctrine/ORM/Mapping/EntityListeners.php +++ b/lib/Doctrine/ORM/Mapping/EntityListeners.php @@ -21,6 +21,7 @@ namespace Doctrine\ORM\Mapping; use Attribute; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** * The EntityListeners annotation specifies the callback listener classes to be used for an entity or mapped superclass. @@ -33,7 +34,7 @@ * @Target("CLASS") */ #[Attribute(Attribute::TARGET_CLASS)] -final class EntityListeners implements Annotation +final class EntityListeners implements Annotation, NamedArgumentConstructorAnnotation { /** * Specifies the names of the entity listeners. @@ -41,4 +42,9 @@ final class EntityListeners implements Annotation * @var array */ public $value = []; + + public function __construct(array $value = []) + { + $this->value = $value; + } } diff --git a/lib/Doctrine/ORM/Mapping/GeneratedValue.php b/lib/Doctrine/ORM/Mapping/GeneratedValue.php index 1a2f572eeb8..8ded483d419 100644 --- a/lib/Doctrine/ORM/Mapping/GeneratedValue.php +++ b/lib/Doctrine/ORM/Mapping/GeneratedValue.php @@ -20,13 +20,14 @@ namespace Doctrine\ORM\Mapping; use Attribute; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** * @Annotation * @Target("PROPERTY") */ #[Attribute(Attribute::TARGET_PROPERTY)] -final class GeneratedValue implements Annotation +final class GeneratedValue implements Annotation, NamedArgumentConstructorAnnotation { /** * The type of Id generator. @@ -36,4 +37,9 @@ final class GeneratedValue implements Annotation * @Enum({"AUTO", "SEQUENCE", "TABLE", "IDENTITY", "NONE", "UUID", "CUSTOM"}) */ public $strategy = 'AUTO'; + + public function __construct(string $strategy = 'AUTO', ?string $value = null) + { + $this->strategy = $value ?: $strategy; + } } diff --git a/lib/Doctrine/ORM/Mapping/Index.php b/lib/Doctrine/ORM/Mapping/Index.php index 24eb752a8b7..8530e8aa5de 100644 --- a/lib/Doctrine/ORM/Mapping/Index.php +++ b/lib/Doctrine/ORM/Mapping/Index.php @@ -20,13 +20,14 @@ namespace Doctrine\ORM\Mapping; use Attribute; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** * @Annotation * @Target("ANNOTATION") */ #[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] -final class Index implements Annotation +final class Index implements Annotation, NamedArgumentConstructorAnnotation { /** * @var string @@ -47,4 +48,16 @@ final class Index implements Annotation * @var array */ public $options; + + public function __construct( + array $columns, + ?string $name = null, + ?array $flags = null, + ?array $options = null + ) { + $this->columns = $columns; + $this->name = $name; + $this->flags = $flags; + $this->options = $options; + } } diff --git a/lib/Doctrine/ORM/Mapping/InheritanceType.php b/lib/Doctrine/ORM/Mapping/InheritanceType.php index 5f42fb095d2..c207e9c7d6b 100644 --- a/lib/Doctrine/ORM/Mapping/InheritanceType.php +++ b/lib/Doctrine/ORM/Mapping/InheritanceType.php @@ -20,13 +20,14 @@ namespace Doctrine\ORM\Mapping; use Attribute; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** * @Annotation * @Target("CLASS") */ #[Attribute(Attribute::TARGET_CLASS)] -final class InheritanceType implements Annotation +final class InheritanceType implements Annotation, NamedArgumentConstructorAnnotation { /** * The inheritance type used by the class and its subclasses. @@ -36,4 +37,9 @@ final class InheritanceType implements Annotation * @Enum({"NONE", "JOINED", "SINGLE_TABLE", "TABLE_PER_CLASS"}) */ public $value; + + public function __construct(string $value) + { + $this->value = $value; + } } diff --git a/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php b/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php index 5f27d73a64e..a4ff7204397 100644 --- a/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php +++ b/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php @@ -27,21 +27,23 @@ #[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] final class InverseJoinColumn implements Annotation { - public string $name; + public function __construct( + public ?string $name = null, - public string $referencedColumnName = 'id'; + public string $referencedColumnName = 'id', - public bool $unique = false; + public bool $unique = false, - public bool $nullable = true; + public bool $nullable = true, - /** @var mixed */ - public $onDelete; + /** @var mixed */ + public $onDelete = null, - public string $columnDefinition; + public ?string $columnDefinition = null, - /** - * Field name used in non-object hydration (array/scalar). - */ - public string $fieldName; + /** + * Field name used in non-object hydration (array/scalar). + */ + public ?string $fieldName = null, + ) {} } diff --git a/lib/Doctrine/ORM/Mapping/JoinColumn.php b/lib/Doctrine/ORM/Mapping/JoinColumn.php index 86651fa0851..206c22d0b10 100644 --- a/lib/Doctrine/ORM/Mapping/JoinColumn.php +++ b/lib/Doctrine/ORM/Mapping/JoinColumn.php @@ -20,13 +20,14 @@ namespace Doctrine\ORM\Mapping; use Attribute; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** * @Annotation * @Target({"PROPERTY","ANNOTATION"}) */ #[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] -final class JoinColumn implements Annotation +final class JoinColumn implements Annotation, NamedArgumentConstructorAnnotation { /** * @var string @@ -64,4 +65,22 @@ final class JoinColumn implements Annotation * @var string */ public $fieldName; + + public function __construct( + ?string $name = null, + string $referencedColumnName = 'id', + bool $unique = false, + bool $nullable = true, + $onDelete = null, + ?string $columnDefinition = null, + ?string $fieldName = null + ) { + $this->name = $name; + $this->referencedColumnName = $referencedColumnName; + $this->unique = $unique; + $this->nullable = $nullable; + $this->onDelete = $onDelete; + $this->columnDefinition = $columnDefinition; + $this->fieldName = $fieldName; + } } diff --git a/lib/Doctrine/ORM/Mapping/JoinTable.php b/lib/Doctrine/ORM/Mapping/JoinTable.php index 90664ca888a..3eabf367ebe 100644 --- a/lib/Doctrine/ORM/Mapping/JoinTable.php +++ b/lib/Doctrine/ORM/Mapping/JoinTable.php @@ -20,13 +20,14 @@ namespace Doctrine\ORM\Mapping; use Attribute; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** * @Annotation * @Target({"PROPERTY","ANNOTATION"}) */ #[Attribute(Attribute::TARGET_PROPERTY)] -final class JoinTable implements Annotation +final class JoinTable implements Annotation, NamedArgumentConstructorAnnotation { /** * @var string @@ -47,4 +48,18 @@ final class JoinTable implements Annotation * @var array<\Doctrine\ORM\Mapping\JoinColumn> */ public $inverseJoinColumns = []; + + public function __construct( + ?string $name = null, + ?string $schema = null, + $joinColumns = [], + $inverseJoinColumns = [] + ) { + $this->name = $name; + $this->schema = $schema; + $this->joinColumns = $joinColumns instanceof JoinColumn ? [$joinColumns] : $joinColumns; + $this->inverseJoinColumns = $inverseJoinColumns instanceof JoinColumn + ? [$inverseJoinColumns] + : $inverseJoinColumns; + } } diff --git a/lib/Doctrine/ORM/Mapping/ManyToMany.php b/lib/Doctrine/ORM/Mapping/ManyToMany.php index e7bd6ac69fe..3cd7793a300 100644 --- a/lib/Doctrine/ORM/Mapping/ManyToMany.php +++ b/lib/Doctrine/ORM/Mapping/ManyToMany.php @@ -20,13 +20,14 @@ namespace Doctrine\ORM\Mapping; use Attribute; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** * @Annotation * @Target("PROPERTY") */ #[Attribute(Attribute::TARGET_PROPERTY)] -final class ManyToMany implements Annotation +final class ManyToMany implements Annotation, NamedArgumentConstructorAnnotation { /** * @var string @@ -66,4 +67,22 @@ final class ManyToMany implements Annotation * @var string */ public $indexBy; + + public function __construct( + string $targetEntity, + ?string $mappedBy = null, + ?string $inversedBy = null, + ?array $cascade = null, + string $fetch = 'LAZY', + bool $orphanRemoval = false, + ?string $indexBy = null + ) { + $this->targetEntity = $targetEntity; + $this->mappedBy = $mappedBy; + $this->inversedBy = $inversedBy; + $this->cascade = $cascade; + $this->fetch = $fetch; + $this->orphanRemoval = $orphanRemoval; + $this->indexBy = $indexBy; + } } diff --git a/lib/Doctrine/ORM/Mapping/ManyToOne.php b/lib/Doctrine/ORM/Mapping/ManyToOne.php index 8147d932de4..4e64735b701 100644 --- a/lib/Doctrine/ORM/Mapping/ManyToOne.php +++ b/lib/Doctrine/ORM/Mapping/ManyToOne.php @@ -20,13 +20,14 @@ namespace Doctrine\ORM\Mapping; use Attribute; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** * @Annotation * @Target("PROPERTY") */ #[Attribute(Attribute::TARGET_PROPERTY)] -final class ManyToOne implements Annotation +final class ManyToOne implements Annotation, NamedArgumentConstructorAnnotation { /** * @var string @@ -51,4 +52,16 @@ final class ManyToOne implements Annotation * @var string */ public $inversedBy; + + public function __construct( + string $targetEntity, + ?array $cascade = null, + string $fetch = 'LAZY', + ?string $inversedBy = null + ) { + $this->targetEntity = $targetEntity; + $this->cascade = $cascade; + $this->fetch = $fetch; + $this->inversedBy = $inversedBy; + } } diff --git a/lib/Doctrine/ORM/Mapping/MappedSuperclass.php b/lib/Doctrine/ORM/Mapping/MappedSuperclass.php index 73b6766f417..fe41a89324e 100644 --- a/lib/Doctrine/ORM/Mapping/MappedSuperclass.php +++ b/lib/Doctrine/ORM/Mapping/MappedSuperclass.php @@ -20,16 +20,22 @@ namespace Doctrine\ORM\Mapping; use Attribute; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** * @Annotation * @Target("CLASS") */ #[Attribute(Attribute::TARGET_CLASS)] -final class MappedSuperclass implements Annotation +final class MappedSuperclass implements Annotation, NamedArgumentConstructorAnnotation { /** * @var string */ public $repositoryClass; + + public function __construct(?string $repositoryClass = null) + { + $this->repositoryClass = $repositoryClass; + } } diff --git a/lib/Doctrine/ORM/Mapping/OneToMany.php b/lib/Doctrine/ORM/Mapping/OneToMany.php index c7519158d8f..64b81a47f46 100644 --- a/lib/Doctrine/ORM/Mapping/OneToMany.php +++ b/lib/Doctrine/ORM/Mapping/OneToMany.php @@ -20,13 +20,14 @@ namespace Doctrine\ORM\Mapping; use Attribute; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** * @Annotation * @Target("PROPERTY") */ #[Attribute(Attribute::TARGET_PROPERTY)] -final class OneToMany implements Annotation +final class OneToMany implements Annotation, NamedArgumentConstructorAnnotation { /** * @var string @@ -61,4 +62,20 @@ final class OneToMany implements Annotation * @var string */ public $indexBy; + + public function __construct( + ?string $mappedBy = null, + ?string $targetEntity = null, + ?array $cascade = null, + string $fetch = 'LAZY', + bool $orphanRemoval = false, + ?string $indexBy = null + ) { + $this->mappedBy = $mappedBy; + $this->targetEntity = $targetEntity; + $this->cascade = $cascade; + $this->fetch = $fetch; + $this->orphanRemoval = $orphanRemoval; + $this->indexBy = $indexBy; + } } diff --git a/lib/Doctrine/ORM/Mapping/OneToOne.php b/lib/Doctrine/ORM/Mapping/OneToOne.php index de6a601547c..79debec4433 100644 --- a/lib/Doctrine/ORM/Mapping/OneToOne.php +++ b/lib/Doctrine/ORM/Mapping/OneToOne.php @@ -20,13 +20,14 @@ namespace Doctrine\ORM\Mapping; use Attribute; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** * @Annotation * @Target("PROPERTY") */ #[Attribute(Attribute::TARGET_PROPERTY)] -final class OneToOne implements Annotation +final class OneToOne implements Annotation, NamedArgumentConstructorAnnotation { /** * @var string @@ -61,4 +62,20 @@ final class OneToOne implements Annotation * @var boolean */ public $orphanRemoval = false; + + public function __construct( + ?string $mappedBy = null, + ?string $inversedBy = null, + ?string $targetEntity = null, + ?array $cascade = null, + string $fetch = 'LAZY', + bool $orphanRemoval = false + ) { + $this->mappedBy = $mappedBy; + $this->inversedBy = $inversedBy; + $this->targetEntity = $targetEntity; + $this->cascade = $cascade; + $this->fetch = $fetch; + $this->orphanRemoval = $orphanRemoval; + } } diff --git a/lib/Doctrine/ORM/Mapping/OrderBy.php b/lib/Doctrine/ORM/Mapping/OrderBy.php index cf6cdfe223a..63a8ecb6470 100644 --- a/lib/Doctrine/ORM/Mapping/OrderBy.php +++ b/lib/Doctrine/ORM/Mapping/OrderBy.php @@ -20,16 +20,22 @@ namespace Doctrine\ORM\Mapping; use Attribute; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** * @Annotation * @Target("PROPERTY") */ #[Attribute(Attribute::TARGET_PROPERTY)] -final class OrderBy implements Annotation +final class OrderBy implements Annotation, NamedArgumentConstructorAnnotation { /** * @var array */ public $value; + + public function __construct(array $value) + { + $this->value = $value; + } } diff --git a/lib/Doctrine/ORM/Mapping/SequenceGenerator.php b/lib/Doctrine/ORM/Mapping/SequenceGenerator.php index f53c84bd9ab..7279d15dc25 100644 --- a/lib/Doctrine/ORM/Mapping/SequenceGenerator.php +++ b/lib/Doctrine/ORM/Mapping/SequenceGenerator.php @@ -20,13 +20,14 @@ namespace Doctrine\ORM\Mapping; use Attribute; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** * @Annotation * @Target("PROPERTY") */ #[Attribute(Attribute::TARGET_PROPERTY)] -final class SequenceGenerator implements Annotation +final class SequenceGenerator implements Annotation, NamedArgumentConstructorAnnotation { /** * @var string @@ -42,4 +43,14 @@ final class SequenceGenerator implements Annotation * @var integer */ public $initialValue = 1; + + public function __construct( + ?string $sequenceName = null, + int $allocationSize = 1, + int $initialValue = 1 + ) { + $this->sequenceName = $sequenceName; + $this->allocationSize = $allocationSize; + $this->initialValue = $initialValue; + } } diff --git a/lib/Doctrine/ORM/Mapping/Table.php b/lib/Doctrine/ORM/Mapping/Table.php index cceff201082..ef8aa24af59 100644 --- a/lib/Doctrine/ORM/Mapping/Table.php +++ b/lib/Doctrine/ORM/Mapping/Table.php @@ -20,13 +20,14 @@ namespace Doctrine\ORM\Mapping; use Attribute; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** * @Annotation * @Target("CLASS") */ #[Attribute(Attribute::TARGET_CLASS)] -final class Table implements Annotation +final class Table implements Annotation, NamedArgumentConstructorAnnotation { /** * @var string @@ -52,4 +53,19 @@ final class Table implements Annotation * @var array */ public $options = []; + + public function __construct( + ?string $name = null, + ?string $schema = null, + ?array $indexes = null, + ?array $uniqueConstraints = null, + array $options = [], + ?string $value = null + ) { + $this->name = $value ?: $name; + $this->schema = $schema; + $this->indexes = $indexes; + $this->uniqueConstraints = $uniqueConstraints; + $this->options = $options; + } } diff --git a/lib/Doctrine/ORM/Mapping/UniqueConstraint.php b/lib/Doctrine/ORM/Mapping/UniqueConstraint.php index ce087a8c266..0cd3ba6291e 100644 --- a/lib/Doctrine/ORM/Mapping/UniqueConstraint.php +++ b/lib/Doctrine/ORM/Mapping/UniqueConstraint.php @@ -20,13 +20,14 @@ namespace Doctrine\ORM\Mapping; use Attribute; +use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** * @Annotation * @Target("ANNOTATION") */ #[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] -final class UniqueConstraint implements Annotation +final class UniqueConstraint implements Annotation, NamedArgumentConstructorAnnotation { /** * @var string @@ -42,4 +43,14 @@ final class UniqueConstraint implements Annotation * @var array */ public $options; + + public function __construct( + ?string $name = null, + array $columns = null, + array $options = null + ) { + $this->name = $name; + $this->columns = $columns; + $this->options = $options; + } } diff --git a/tests/Doctrine/Tests/ORM/Mapping/AnnotationDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AnnotationDriverTest.php index 9efb5442f46..bc91bd44438 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/AnnotationDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/AnnotationDriverTest.php @@ -239,8 +239,8 @@ public function testInvalidFetchOptionThrowsException() $factory = new ClassMetadataFactory(); $factory->setEntityManager($em); - $this->expectException(AnnotationException::class); - $this->expectExceptionMessage('[Enum Error] Attribute "fetch" of @Doctrine\ORM\Mapping\OneToMany declared on property Doctrine\Tests\ORM\Mapping\InvalidFetchOption::$collection accept'); + $this->expectException(MappingException::class); + $this->expectExceptionMessage("Entity 'Doctrine\Tests\ORM\Mapping\InvalidFetchOption' has a mapping with invalid fetch mode 'eager'"); $factory->getMetadataFor(InvalidFetchOption::class); } From 17b141bf5979b4d68d414737c9a99c4907b4840f Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Tue, 8 Dec 2020 05:31:28 +0100 Subject: [PATCH 19/37] [GH-8265] Style after attribute changes. --- lib/Doctrine/ORM/Mapping/Cache.php | 13 ++--- .../ORM/Mapping/ChangeTrackingPolicy.php | 4 +- lib/Doctrine/ORM/Mapping/Column.php | 54 ++++++++----------- .../ORM/Mapping/CustomIdGenerator.php | 7 +-- .../ORM/Mapping/DiscriminatorColumn.php | 28 ++++------ lib/Doctrine/ORM/Mapping/DiscriminatorMap.php | 7 +-- lib/Doctrine/ORM/Mapping/Embedded.php | 9 ++-- lib/Doctrine/ORM/Mapping/Entity.php | 13 +++-- lib/Doctrine/ORM/Mapping/GeneratedValue.php | 4 +- lib/Doctrine/ORM/Mapping/Id.php | 3 ++ lib/Doctrine/ORM/Mapping/Index.php | 23 ++++---- lib/Doctrine/ORM/Mapping/InheritanceType.php | 4 +- lib/Doctrine/ORM/Mapping/JoinColumn.php | 39 ++++++-------- lib/Doctrine/ORM/Mapping/JoinColumns.php | 7 +-- lib/Doctrine/ORM/Mapping/JoinTable.php | 25 ++++----- lib/Doctrine/ORM/Mapping/ManyToMany.php | 40 ++++++-------- lib/Doctrine/ORM/Mapping/ManyToOne.php | 22 ++++---- lib/Doctrine/ORM/Mapping/MappedSuperclass.php | 7 +-- lib/Doctrine/ORM/Mapping/OneToMany.php | 34 +++++------- lib/Doctrine/ORM/Mapping/OneToOne.php | 34 +++++------- lib/Doctrine/ORM/Mapping/OrderBy.php | 7 +-- .../ORM/Mapping/SequenceGenerator.php | 19 +++---- lib/Doctrine/ORM/Mapping/Table.php | 31 +++++------ lib/Doctrine/ORM/Mapping/UniqueConstraint.php | 21 ++++---- phpcs.xml.dist | 1 + 25 files changed, 194 insertions(+), 262 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/Cache.php b/lib/Doctrine/ORM/Mapping/Cache.php index 88bb5714e4b..38e4201d494 100644 --- a/lib/Doctrine/ORM/Mapping/Cache.php +++ b/lib/Doctrine/ORM/Mapping/Cache.php @@ -1,4 +1,7 @@ - * @since 2.5 - * * @Annotation * @Target({"CLASS","PROPERTY"}) */ @@ -36,19 +36,16 @@ final class Cache implements Annotation, NamedArgumentConstructorAnnotation { /** * @Enum({"READ_ONLY", "NONSTRICT_READ_WRITE", "READ_WRITE"}) - * * @var string The concurrency strategy. */ public $usage = 'READ_ONLY'; - /** - * @var string Cache region name. - */ + /** @var string Cache region name. */ public $region; public function __construct(string $usage = 'READ_ONLY', ?string $region = null, $value = null) { - $this->usage = $value ?: $usage; + $this->usage = $value ?: $usage; $this->region = $region; } } diff --git a/lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php b/lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php index ab60c25526c..0cc31ac98ec 100644 --- a/lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php +++ b/lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php @@ -1,4 +1,7 @@ name = $name; - $this->type = $type; - $this->length = $length; - $this->precision = $precision; - $this->scale = $scale; - $this->unique = $unique; - $this->nullable = $nullable; - $this->options = $options; + ) { + $this->name = $name; + $this->type = $type; + $this->length = $length; + $this->precision = $precision; + $this->scale = $scale; + $this->unique = $unique; + $this->nullable = $nullable; + $this->options = $options; $this->columnDefinition = $columnDefinition; } } diff --git a/lib/Doctrine/ORM/Mapping/CustomIdGenerator.php b/lib/Doctrine/ORM/Mapping/CustomIdGenerator.php index b5159e78b56..121c08ccf2c 100644 --- a/lib/Doctrine/ORM/Mapping/CustomIdGenerator.php +++ b/lib/Doctrine/ORM/Mapping/CustomIdGenerator.php @@ -1,4 +1,7 @@ name = $name; - $this->type = $type; - $this->length = $length; + ) { + $this->name = $name; + $this->type = $type; + $this->length = $length; $this->columnDefinition = $columnDefinition; } } diff --git a/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php b/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php index ad63c1f58de..b23deeb0ce4 100644 --- a/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php +++ b/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php @@ -1,4 +1,7 @@ - */ + /** @var array */ public $value; public function __construct(array $value) diff --git a/lib/Doctrine/ORM/Mapping/Embedded.php b/lib/Doctrine/ORM/Mapping/Embedded.php index c666d42e5e2..c2817d633bb 100644 --- a/lib/Doctrine/ORM/Mapping/Embedded.php +++ b/lib/Doctrine/ORM/Mapping/Embedded.php @@ -1,4 +1,7 @@ class = $class; + $this->class = $class; $this->columnPrefix = $columnPrefix; } } diff --git a/lib/Doctrine/ORM/Mapping/Entity.php b/lib/Doctrine/ORM/Mapping/Entity.php index 79938f4eb39..6913cd923e1 100644 --- a/lib/Doctrine/ORM/Mapping/Entity.php +++ b/lib/Doctrine/ORM/Mapping/Entity.php @@ -1,4 +1,7 @@ repositoryClass = $repositoryClass; - $this->readOnly = $readOnly; + $this->readOnly = $readOnly; } } diff --git a/lib/Doctrine/ORM/Mapping/GeneratedValue.php b/lib/Doctrine/ORM/Mapping/GeneratedValue.php index 8ded483d419..cc9123a9ad5 100644 --- a/lib/Doctrine/ORM/Mapping/GeneratedValue.php +++ b/lib/Doctrine/ORM/Mapping/GeneratedValue.php @@ -1,4 +1,7 @@ - */ + /** @var array */ public $columns; - /** - * @var array - */ + /** @var array */ public $flags; - /** - * @var array - */ + /** @var array */ public $options; public function __construct( @@ -56,8 +51,8 @@ public function __construct( ?array $options = null ) { $this->columns = $columns; - $this->name = $name; - $this->flags = $flags; + $this->name = $name; + $this->flags = $flags; $this->options = $options; } } diff --git a/lib/Doctrine/ORM/Mapping/InheritanceType.php b/lib/Doctrine/ORM/Mapping/InheritanceType.php index c207e9c7d6b..ba226a4175e 100644 --- a/lib/Doctrine/ORM/Mapping/InheritanceType.php +++ b/lib/Doctrine/ORM/Mapping/InheritanceType.php @@ -1,4 +1,7 @@ name = $name; + $this->name = $name; $this->referencedColumnName = $referencedColumnName; - $this->unique = $unique; - $this->nullable = $nullable; - $this->onDelete = $onDelete; - $this->columnDefinition = $columnDefinition; - $this->fieldName = $fieldName; + $this->unique = $unique; + $this->nullable = $nullable; + $this->onDelete = $onDelete; + $this->columnDefinition = $columnDefinition; + $this->fieldName = $fieldName; } } diff --git a/lib/Doctrine/ORM/Mapping/JoinColumns.php b/lib/Doctrine/ORM/Mapping/JoinColumns.php index ae096c27503..98d03b165aa 100644 --- a/lib/Doctrine/ORM/Mapping/JoinColumns.php +++ b/lib/Doctrine/ORM/Mapping/JoinColumns.php @@ -1,4 +1,7 @@ - */ + /** @var array<\Doctrine\ORM\Mapping\JoinColumn> */ public $value; } diff --git a/lib/Doctrine/ORM/Mapping/JoinTable.php b/lib/Doctrine/ORM/Mapping/JoinTable.php index 3eabf367ebe..b4d5c39b282 100644 --- a/lib/Doctrine/ORM/Mapping/JoinTable.php +++ b/lib/Doctrine/ORM/Mapping/JoinTable.php @@ -1,4 +1,7 @@ - */ + /** @var array<\Doctrine\ORM\Mapping\JoinColumn> */ public $joinColumns = []; - /** - * @var array<\Doctrine\ORM\Mapping\JoinColumn> - */ + /** @var array<\Doctrine\ORM\Mapping\JoinColumn> */ public $inverseJoinColumns = []; public function __construct( @@ -55,9 +50,9 @@ public function __construct( $joinColumns = [], $inverseJoinColumns = [] ) { - $this->name = $name; - $this->schema = $schema; - $this->joinColumns = $joinColumns instanceof JoinColumn ? [$joinColumns] : $joinColumns; + $this->name = $name; + $this->schema = $schema; + $this->joinColumns = $joinColumns instanceof JoinColumn ? [$joinColumns] : $joinColumns; $this->inverseJoinColumns = $inverseJoinColumns instanceof JoinColumn ? [$inverseJoinColumns] : $inverseJoinColumns; diff --git a/lib/Doctrine/ORM/Mapping/ManyToMany.php b/lib/Doctrine/ORM/Mapping/ManyToMany.php index 3cd7793a300..52c9acc5615 100644 --- a/lib/Doctrine/ORM/Mapping/ManyToMany.php +++ b/lib/Doctrine/ORM/Mapping/ManyToMany.php @@ -1,4 +1,7 @@ - */ + /** @var array */ public $cascade; /** * The fetching strategy to use for the association. * * @var string - * * @Enum({"LAZY", "EAGER", "EXTRA_LAZY"}) */ public $fetch = 'LAZY'; - /** - * @var boolean - */ + /** @var bool */ public $orphanRemoval = false; - /** - * @var string - */ + /** @var string */ public $indexBy; public function __construct( @@ -77,12 +67,12 @@ public function __construct( bool $orphanRemoval = false, ?string $indexBy = null ) { - $this->targetEntity = $targetEntity; - $this->mappedBy = $mappedBy; - $this->inversedBy = $inversedBy; - $this->cascade = $cascade; - $this->fetch = $fetch; + $this->targetEntity = $targetEntity; + $this->mappedBy = $mappedBy; + $this->inversedBy = $inversedBy; + $this->cascade = $cascade; + $this->fetch = $fetch; $this->orphanRemoval = $orphanRemoval; - $this->indexBy = $indexBy; + $this->indexBy = $indexBy; } } diff --git a/lib/Doctrine/ORM/Mapping/ManyToOne.php b/lib/Doctrine/ORM/Mapping/ManyToOne.php index 4e64735b701..cfb8611d34a 100644 --- a/lib/Doctrine/ORM/Mapping/ManyToOne.php +++ b/lib/Doctrine/ORM/Mapping/ManyToOne.php @@ -1,4 +1,7 @@ - */ + /** @var array */ public $cascade; /** * The fetching strategy to use for the association. * * @var string - * * @Enum({"LAZY", "EAGER", "EXTRA_LAZY"}) */ public $fetch = 'LAZY'; - /** - * @var string - */ + /** @var string */ public $inversedBy; public function __construct( @@ -60,8 +56,8 @@ public function __construct( ?string $inversedBy = null ) { $this->targetEntity = $targetEntity; - $this->cascade = $cascade; - $this->fetch = $fetch; - $this->inversedBy = $inversedBy; + $this->cascade = $cascade; + $this->fetch = $fetch; + $this->inversedBy = $inversedBy; } } diff --git a/lib/Doctrine/ORM/Mapping/MappedSuperclass.php b/lib/Doctrine/ORM/Mapping/MappedSuperclass.php index fe41a89324e..f385bcb73a1 100644 --- a/lib/Doctrine/ORM/Mapping/MappedSuperclass.php +++ b/lib/Doctrine/ORM/Mapping/MappedSuperclass.php @@ -1,4 +1,7 @@ - */ + /** @var array */ public $cascade; /** * The fetching strategy to use for the association. * * @var string - * * @Enum({"LAZY", "EAGER", "EXTRA_LAZY"}) */ public $fetch = 'LAZY'; - /** - * @var boolean - */ + /** @var bool */ public $orphanRemoval = false; - /** - * @var string - */ + /** @var string */ public $indexBy; public function __construct( @@ -71,11 +63,11 @@ public function __construct( bool $orphanRemoval = false, ?string $indexBy = null ) { - $this->mappedBy = $mappedBy; - $this->targetEntity = $targetEntity; - $this->cascade = $cascade; - $this->fetch = $fetch; + $this->mappedBy = $mappedBy; + $this->targetEntity = $targetEntity; + $this->cascade = $cascade; + $this->fetch = $fetch; $this->orphanRemoval = $orphanRemoval; - $this->indexBy = $indexBy; + $this->indexBy = $indexBy; } } diff --git a/lib/Doctrine/ORM/Mapping/OneToOne.php b/lib/Doctrine/ORM/Mapping/OneToOne.php index 79debec4433..2338269f7ea 100644 --- a/lib/Doctrine/ORM/Mapping/OneToOne.php +++ b/lib/Doctrine/ORM/Mapping/OneToOne.php @@ -1,4 +1,7 @@ - */ + /** @var array */ public $cascade; /** * The fetching strategy to use for the association. * * @var string - * * @Enum({"LAZY", "EAGER", "EXTRA_LAZY"}) */ public $fetch = 'LAZY'; - /** - * @var boolean - */ + /** @var bool */ public $orphanRemoval = false; public function __construct( @@ -71,11 +63,11 @@ public function __construct( string $fetch = 'LAZY', bool $orphanRemoval = false ) { - $this->mappedBy = $mappedBy; - $this->inversedBy = $inversedBy; - $this->targetEntity = $targetEntity; - $this->cascade = $cascade; - $this->fetch = $fetch; + $this->mappedBy = $mappedBy; + $this->inversedBy = $inversedBy; + $this->targetEntity = $targetEntity; + $this->cascade = $cascade; + $this->fetch = $fetch; $this->orphanRemoval = $orphanRemoval; } } diff --git a/lib/Doctrine/ORM/Mapping/OrderBy.php b/lib/Doctrine/ORM/Mapping/OrderBy.php index 63a8ecb6470..2136ccc6fcc 100644 --- a/lib/Doctrine/ORM/Mapping/OrderBy.php +++ b/lib/Doctrine/ORM/Mapping/OrderBy.php @@ -1,4 +1,7 @@ - */ + /** @var array */ public $value; public function __construct(array $value) diff --git a/lib/Doctrine/ORM/Mapping/SequenceGenerator.php b/lib/Doctrine/ORM/Mapping/SequenceGenerator.php index 7279d15dc25..5431a8e24c0 100644 --- a/lib/Doctrine/ORM/Mapping/SequenceGenerator.php +++ b/lib/Doctrine/ORM/Mapping/SequenceGenerator.php @@ -1,4 +1,7 @@ sequenceName = $sequenceName; + $this->sequenceName = $sequenceName; $this->allocationSize = $allocationSize; - $this->initialValue = $initialValue; + $this->initialValue = $initialValue; } } diff --git a/lib/Doctrine/ORM/Mapping/Table.php b/lib/Doctrine/ORM/Mapping/Table.php index ef8aa24af59..ef81cff7f5d 100644 --- a/lib/Doctrine/ORM/Mapping/Table.php +++ b/lib/Doctrine/ORM/Mapping/Table.php @@ -1,4 +1,7 @@ - */ + /** @var array<\Doctrine\ORM\Mapping\Index> */ public $indexes; - /** - * @var array<\Doctrine\ORM\Mapping\UniqueConstraint> - */ + /** @var array<\Doctrine\ORM\Mapping\UniqueConstraint> */ public $uniqueConstraints; - /** - * @var array - */ + /** @var array */ public $options = []; public function __construct( @@ -62,10 +55,10 @@ public function __construct( array $options = [], ?string $value = null ) { - $this->name = $value ?: $name; - $this->schema = $schema; - $this->indexes = $indexes; + $this->name = $value ?: $name; + $this->schema = $schema; + $this->indexes = $indexes; $this->uniqueConstraints = $uniqueConstraints; - $this->options = $options; + $this->options = $options; } } diff --git a/lib/Doctrine/ORM/Mapping/UniqueConstraint.php b/lib/Doctrine/ORM/Mapping/UniqueConstraint.php index 0cd3ba6291e..3bef179cf33 100644 --- a/lib/Doctrine/ORM/Mapping/UniqueConstraint.php +++ b/lib/Doctrine/ORM/Mapping/UniqueConstraint.php @@ -1,4 +1,7 @@ - */ + /** @var array */ public $columns; - /** - * @var array - */ + /** @var array */ public $options; public function __construct( ?string $name = null, - array $columns = null, - array $options = null + ?array $columns = null, + ?array $options = null ) { - $this->name = $name; + $this->name = $name; $this->columns = $columns; $this->options = $options; } diff --git a/phpcs.xml.dist b/phpcs.xml.dist index e55dd9a5f2e..d6eddf0fc1b 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -18,6 +18,7 @@ + From 700b7eda9b603c6ecc71230b970e209e340a2fec Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Tue, 8 Dec 2020 05:37:31 +0100 Subject: [PATCH 20/37] [GH-8265] more styles --- lib/Doctrine/ORM/Mapping/Column.php | 5 ++++- lib/Doctrine/ORM/Mapping/DiscriminatorMap.php | 1 + lib/Doctrine/ORM/Mapping/EntityListeners.php | 3 +++ lib/Doctrine/ORM/Mapping/Index.php | 5 +++++ phpcs.xml.dist | 1 + 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/Doctrine/ORM/Mapping/Column.php b/lib/Doctrine/ORM/Mapping/Column.php index 996c05f886d..0906956f271 100644 --- a/lib/Doctrine/ORM/Mapping/Column.php +++ b/lib/Doctrine/ORM/Mapping/Column.php @@ -61,12 +61,15 @@ final class Column implements Annotation, NamedArgumentConstructorAnnotation /** @var bool */ public $nullable = false; - /** @var array */ + /** @var array */ public $options = []; /** @var string */ public $columnDefinition; + /** + * @param array $options + */ public function __construct( ?string $name = null, string $type = 'string', diff --git a/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php b/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php index b23deeb0ce4..7de57a4c1a0 100644 --- a/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php +++ b/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php @@ -35,6 +35,7 @@ final class DiscriminatorMap implements Annotation, NamedArgumentConstructorAnno /** @var array */ public $value; + /** @param array $value */ public function __construct(array $value) { $this->value = $value; diff --git a/lib/Doctrine/ORM/Mapping/EntityListeners.php b/lib/Doctrine/ORM/Mapping/EntityListeners.php index fb69db524a7..af1ac63ce35 100644 --- a/lib/Doctrine/ORM/Mapping/EntityListeners.php +++ b/lib/Doctrine/ORM/Mapping/EntityListeners.php @@ -43,6 +43,9 @@ final class EntityListeners implements Annotation, NamedArgumentConstructorAnnot */ public $value = []; + /** + * @param array $value + */ public function __construct(array $value = []) { $this->value = $value; diff --git a/lib/Doctrine/ORM/Mapping/Index.php b/lib/Doctrine/ORM/Mapping/Index.php index 488dd9c6e92..66bb089c18f 100644 --- a/lib/Doctrine/ORM/Mapping/Index.php +++ b/lib/Doctrine/ORM/Mapping/Index.php @@ -44,6 +44,11 @@ final class Index implements Annotation, NamedArgumentConstructorAnnotation /** @var array */ public $options; + /** + * @param array $columns + * @param array $flags + * @param array $options + */ public function __construct( array $columns, ?string $name = null, diff --git a/phpcs.xml.dist b/phpcs.xml.dist index d6eddf0fc1b..f199a2628b0 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -14,6 +14,7 @@ tools */tests/Doctrine/Tests/Proxies/__CG__/* + */lib/Doctrine/ORM/Mapping/InverseJoinColumn.php From 749a2a64f2b1c4cd70536bfaf056040999a71f44 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Tue, 8 Dec 2020 05:41:07 +0100 Subject: [PATCH 21/37] [GH-8265] Remove workaround code for attributes. --- .../ORM/Mapping/Driver/AttributeReader.php | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php b/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php index 987f30887d1..31c107e2bcb 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php @@ -14,7 +14,6 @@ use function count; use function is_subclass_of; -// TODO: Should we move this to doctrine/annotations? class AttributeReader { /** @var array */ @@ -71,20 +70,7 @@ private function convertToAttributeInstances(array $attributes): array continue; } - $attributeClassName = $attribute->getName(); - $instance = new $attributeClassName(); // @phpstan-ignore-line - $arguments = $attribute->getArguments(); - - // unnamed argument is automatically "value" in Doctrine Annotations - if (count($arguments) >= 1 && isset($arguments[0])) { - $arguments['value'] = $arguments[0]; - unset($arguments[0]); // @phpstan-ignore-line - } - - // This works using the old Annotation, but will probably break Attribute IDE autocomplete support - foreach ($arguments as $name => $value) { - $instance->$name = $value; - } + $instance = $attribute->newInstance(); if ($this->isRepeatable($attribute->getName())) { $instances[$attribute->getName()][] = $instance; From fc311bc650eccb2fe51b6528304daee53ca7383a Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Tue, 8 Dec 2020 05:48:25 +0100 Subject: [PATCH 22/37] More cs --- lib/Doctrine/ORM/Mapping/Index.php | 2 +- .../ORM/Mapping/InverseJoinColumn.php | 22 +++++++++---------- lib/Doctrine/ORM/Mapping/ManyToMany.php | 3 +++ lib/Doctrine/ORM/Mapping/ManyToOne.php | 3 +++ lib/Doctrine/ORM/Mapping/OneToMany.php | 3 +++ lib/Doctrine/ORM/Mapping/OneToOne.php | 3 +++ lib/Doctrine/ORM/Mapping/OrderBy.php | 3 +++ lib/Doctrine/ORM/Mapping/Table.php | 7 +++++- lib/Doctrine/ORM/Mapping/UniqueConstraint.php | 3 +++ 9 files changed, 36 insertions(+), 13 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/Index.php b/lib/Doctrine/ORM/Mapping/Index.php index 66bb089c18f..3f09925515f 100644 --- a/lib/Doctrine/ORM/Mapping/Index.php +++ b/lib/Doctrine/ORM/Mapping/Index.php @@ -41,7 +41,7 @@ final class Index implements Annotation, NamedArgumentConstructorAnnotation /** @var array */ public $flags; - /** @var array */ + /** @var array */ public $options; /** diff --git a/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php b/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php index a4ff7204397..fbf2daa7e4f 100644 --- a/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php +++ b/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php @@ -28,22 +28,22 @@ final class InverseJoinColumn implements Annotation { public function __construct( - public ?string $name = null, + public ?string $name = null, - public string $referencedColumnName = 'id', + public string $referencedColumnName = 'id', - public bool $unique = false, + public bool $unique = false, - public bool $nullable = true, + public bool $nullable = true, - /** @var mixed */ - public $onDelete = null, + /** @var mixed */ + public $onDelete = null, - public ?string $columnDefinition = null, + public ?string $columnDefinition = null, - /** - * Field name used in non-object hydration (array/scalar). - */ - public ?string $fieldName = null, + /** + * Field name used in non-object hydration (array/scalar). + */ + public ?string $fieldName = null, ) {} } diff --git a/lib/Doctrine/ORM/Mapping/ManyToMany.php b/lib/Doctrine/ORM/Mapping/ManyToMany.php index 52c9acc5615..5f63dc7e7a7 100644 --- a/lib/Doctrine/ORM/Mapping/ManyToMany.php +++ b/lib/Doctrine/ORM/Mapping/ManyToMany.php @@ -58,6 +58,9 @@ final class ManyToMany implements Annotation, NamedArgumentConstructorAnnotation /** @var string */ public $indexBy; + /** + * @param array $cascade + */ public function __construct( string $targetEntity, ?string $mappedBy = null, diff --git a/lib/Doctrine/ORM/Mapping/ManyToOne.php b/lib/Doctrine/ORM/Mapping/ManyToOne.php index cfb8611d34a..ac0bc9ea0be 100644 --- a/lib/Doctrine/ORM/Mapping/ManyToOne.php +++ b/lib/Doctrine/ORM/Mapping/ManyToOne.php @@ -49,6 +49,9 @@ final class ManyToOne implements Annotation, NamedArgumentConstructorAnnotation /** @var string */ public $inversedBy; + /** + * @param array $cascade + */ public function __construct( string $targetEntity, ?array $cascade = null, diff --git a/lib/Doctrine/ORM/Mapping/OneToMany.php b/lib/Doctrine/ORM/Mapping/OneToMany.php index 6fd0bdf2485..6e748935706 100644 --- a/lib/Doctrine/ORM/Mapping/OneToMany.php +++ b/lib/Doctrine/ORM/Mapping/OneToMany.php @@ -55,6 +55,9 @@ final class OneToMany implements Annotation, NamedArgumentConstructorAnnotation /** @var string */ public $indexBy; + /** + * @param array $cascade + */ public function __construct( ?string $mappedBy = null, ?string $targetEntity = null, diff --git a/lib/Doctrine/ORM/Mapping/OneToOne.php b/lib/Doctrine/ORM/Mapping/OneToOne.php index 2338269f7ea..1a7257090bf 100644 --- a/lib/Doctrine/ORM/Mapping/OneToOne.php +++ b/lib/Doctrine/ORM/Mapping/OneToOne.php @@ -55,6 +55,9 @@ final class OneToOne implements Annotation, NamedArgumentConstructorAnnotation /** @var bool */ public $orphanRemoval = false; + /** + * @param array $cascade + */ public function __construct( ?string $mappedBy = null, ?string $inversedBy = null, diff --git a/lib/Doctrine/ORM/Mapping/OrderBy.php b/lib/Doctrine/ORM/Mapping/OrderBy.php index 2136ccc6fcc..96c9ca5d969 100644 --- a/lib/Doctrine/ORM/Mapping/OrderBy.php +++ b/lib/Doctrine/ORM/Mapping/OrderBy.php @@ -35,6 +35,9 @@ final class OrderBy implements Annotation, NamedArgumentConstructorAnnotation /** @var array */ public $value; + /** + * @param array $value + */ public function __construct(array $value) { $this->value = $value; diff --git a/lib/Doctrine/ORM/Mapping/Table.php b/lib/Doctrine/ORM/Mapping/Table.php index ef81cff7f5d..39db7866ba4 100644 --- a/lib/Doctrine/ORM/Mapping/Table.php +++ b/lib/Doctrine/ORM/Mapping/Table.php @@ -44,9 +44,14 @@ final class Table implements Annotation, NamedArgumentConstructorAnnotation /** @var array<\Doctrine\ORM\Mapping\UniqueConstraint> */ public $uniqueConstraints; - /** @var array */ + /** @var array */ public $options = []; + /** + * @param array<\Doctrine\ORM\Mapping\Index> $indexes + * @param array<\Doctrine\ORM\Mapping\UniqueConstraint> $uniqueConstraints + * @param array + */ public function __construct( ?string $name = null, ?string $schema = null, diff --git a/lib/Doctrine/ORM/Mapping/UniqueConstraint.php b/lib/Doctrine/ORM/Mapping/UniqueConstraint.php index 3bef179cf33..73338aeda75 100644 --- a/lib/Doctrine/ORM/Mapping/UniqueConstraint.php +++ b/lib/Doctrine/ORM/Mapping/UniqueConstraint.php @@ -41,6 +41,9 @@ final class UniqueConstraint implements Annotation, NamedArgumentConstructorAnno /** @var array */ public $options; + /** + * @param array $columns + */ public function __construct( ?string $name = null, ?array $columns = null, From 60fb7a65b061bd925f41284985cb487571d564ad Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Tue, 8 Dec 2020 05:52:25 +0100 Subject: [PATCH 23/37] More cs --- .../ORM/Mapping/InverseJoinColumn.php | 24 +++++++++---------- lib/Doctrine/ORM/Mapping/Table.php | 2 +- lib/Doctrine/ORM/Mapping/UniqueConstraint.php | 3 ++- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php b/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php index fbf2daa7e4f..041ac25a167 100644 --- a/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php +++ b/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php @@ -28,22 +28,22 @@ final class InverseJoinColumn implements Annotation { public function __construct( - public ?string $name = null, + public ?string $name = null, - public string $referencedColumnName = 'id', + public string $referencedColumnName = 'id', - public bool $unique = false, + public bool $unique = false, - public bool $nullable = true, + public bool $nullable = true, + + /** @var mixed */ + public $onDelete = null, - /** @var mixed */ - public $onDelete = null, + public ?string $columnDefinition = null, - public ?string $columnDefinition = null, - - /** - * Field name used in non-object hydration (array/scalar). - */ - public ?string $fieldName = null, + /** + * Field name used in non-object hydration (array/scalar). + */ + public ?string $fieldName = null, ) {} } diff --git a/lib/Doctrine/ORM/Mapping/Table.php b/lib/Doctrine/ORM/Mapping/Table.php index 39db7866ba4..9f962327ab9 100644 --- a/lib/Doctrine/ORM/Mapping/Table.php +++ b/lib/Doctrine/ORM/Mapping/Table.php @@ -50,7 +50,7 @@ final class Table implements Annotation, NamedArgumentConstructorAnnotation /** * @param array<\Doctrine\ORM\Mapping\Index> $indexes * @param array<\Doctrine\ORM\Mapping\UniqueConstraint> $uniqueConstraints - * @param array + * @param array $options */ public function __construct( ?string $name = null, diff --git a/lib/Doctrine/ORM/Mapping/UniqueConstraint.php b/lib/Doctrine/ORM/Mapping/UniqueConstraint.php index 73338aeda75..b0d4945382c 100644 --- a/lib/Doctrine/ORM/Mapping/UniqueConstraint.php +++ b/lib/Doctrine/ORM/Mapping/UniqueConstraint.php @@ -38,11 +38,12 @@ final class UniqueConstraint implements Annotation, NamedArgumentConstructorAnno /** @var array */ public $columns; - /** @var array */ + /** @var array */ public $options; /** * @param array $columns + * @param array $options */ public function __construct( ?string $name = null, From 98a7d4c62901a85a794db7674ec943f73c50863c Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Tue, 8 Dec 2020 05:55:00 +0100 Subject: [PATCH 24/37] More cs --- .../ORM/Mapping/InverseJoinColumn.php | 51 ++++++++++++++----- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php b/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php index 041ac25a167..8092d143533 100644 --- a/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php +++ b/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php @@ -27,23 +27,46 @@ #[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] final class InverseJoinColumn implements Annotation { - public function __construct( - public ?string $name = null, + /** @var string */ + public $name; + + /** @var string */ + public $referencedColumnName = 'id'; - public string $referencedColumnName = 'id', + /** @var bool */ + public $unique = false; - public bool $unique = false, + /** @var bool */ + public $nullable = true; - public bool $nullable = true, - - /** @var mixed */ - public $onDelete = null, + /** @var mixed */ + public $onDelete; - public ?string $columnDefinition = null, + /** @var string */ + public $columnDefinition; - /** - * Field name used in non-object hydration (array/scalar). - */ - public ?string $fieldName = null, - ) {} + /** + * Field name used in non-object hydration (array/scalar). + * + * @var string + */ + public $fieldName; + + public function __construct( + ?string $name = null, + string $referencedColumnName = 'id', + bool $unique = false, + bool $nullable = true, + $onDelete = null, + ?string $columnDefinition = null, + ?string $fieldName = null + ) { + $this->name = $name; + $this->referencedColumnName = $referencedColumnName; + $this->unique = $unique; + $this->nullable = $nullable; + $this->onDelete = $onDelete; + $this->columnDefinition = $columnDefinition; + $this->fieldName = $fieldName; + } } From 5cfd56a170f36ecd9b89856da7f02af52e8d603c Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Tue, 8 Dec 2020 05:58:15 +0100 Subject: [PATCH 25/37] More cs --- lib/Doctrine/ORM/Mapping/Table.php | 4 ++-- lib/Doctrine/ORM/Mapping/UniqueConstraint.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/Table.php b/lib/Doctrine/ORM/Mapping/Table.php index 9f962327ab9..74da0d4e525 100644 --- a/lib/Doctrine/ORM/Mapping/Table.php +++ b/lib/Doctrine/ORM/Mapping/Table.php @@ -48,9 +48,9 @@ final class Table implements Annotation, NamedArgumentConstructorAnnotation public $options = []; /** - * @param array<\Doctrine\ORM\Mapping\Index> $indexes + * @param array<\Doctrine\ORM\Mapping\Index> $indexes * @param array<\Doctrine\ORM\Mapping\UniqueConstraint> $uniqueConstraints - * @param array $options + * @param array $options */ public function __construct( ?string $name = null, diff --git a/lib/Doctrine/ORM/Mapping/UniqueConstraint.php b/lib/Doctrine/ORM/Mapping/UniqueConstraint.php index b0d4945382c..df112dfd514 100644 --- a/lib/Doctrine/ORM/Mapping/UniqueConstraint.php +++ b/lib/Doctrine/ORM/Mapping/UniqueConstraint.php @@ -42,7 +42,7 @@ final class UniqueConstraint implements Annotation, NamedArgumentConstructorAnno public $options; /** - * @param array $columns + * @param array $columns * @param array $options */ public function __construct( From 0a6c9ca20c0f07cf2bfa316c19ad6ef363a5a51c Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Sun, 13 Dec 2020 13:57:18 +0100 Subject: [PATCH 26/37] Add Attribute Metadata driver reference. --- docs/en/reference/attributes-reference.rst | 1023 ++++++++++++++++++++ 1 file changed, 1023 insertions(+) create mode 100644 docs/en/reference/attributes-reference.rst diff --git a/docs/en/reference/attributes-reference.rst b/docs/en/reference/attributes-reference.rst new file mode 100644 index 00000000000..e4d79440fc7 --- /dev/null +++ b/docs/en/reference/attributes-reference.rst @@ -0,0 +1,1023 @@ +Attributes Reference +==================== + +PHP 8 adds native support for metadata with its "Attributes" feature. +Doctrine ORM provides support for mapping metadata using PHP attributes as of version 2.9. + +The attributes metadata support is closely modelled after the already existing +annotation metadata supported since the first version 2.0. + +Index +----- + +- :ref:`#[Column] ` +- :ref:`#[Cache] ` +- :ref:`#[ChangeTrackingPolicy ` +- :ref:`#[CustomIdGenerator] ` +- :ref:`#[DiscriminatorColumn] ` +- :ref:`#[DiscriminatorMap] ` +- :ref:`#[Embeddable] ` +- :ref:`#[Embedded] ` +- :ref:`#[Entity] ` +- :ref:`#[GeneratedValue] ` +- :ref:`#[HasLifecycleCallbacks] ` +- :ref:`#[Index] ` +- :ref:`#[Id] ` +- :ref:`#[InheritanceType] ` +- :ref:`#[JoinColumn] ` +- :ref:`#[JoinColumns] ` +- :ref:`#[JoinTable] ` +- :ref:`#[ManyToOne] ` +- :ref:`#[ManyToMany] ` +- :ref:`#[MappedSuperclass] ` +- :ref:`#[OneToOne] ` +- :ref:`#[OneToMany] ` +- :ref:`#[OrderBy] ` +- :ref:`#[PostLoad] ` +- :ref:`#[PostPersist] ` +- :ref:`#[PostRemove] ` +- :ref:`#[PostUpdate] ` +- :ref:`#[PrePersist] ` +- :ref:`#[PreRemove] ` +- :ref:`#[PreUpdate] ` +- :ref:`#[SequenceGenerator] ` +- :ref:`#[Table] ` +- :ref:`#[UniqueConstraint] ` +- :ref:`#[Version] ` + + +Reference +--------- + +.. _annref_column: + +#[Column] +~~~~~~~~~ + +Marks an annotated instance variable as "persistent". It has to be +inside the instance variables PHP DocBlock comment. Any value hold +inside this variable will be saved to and loaded from the database +as part of the lifecycle of the instance variables entity-class. + +Required attributes: + +- **type**: Name of the Doctrine Type which is converted between PHP + and Database representation. + +Optional attributes: + +- **name**: By default the property name is used for the database + column name also, however the 'name' attribute allows you to + determine the column name. + +- **length**: Used by the "string" type to determine its maximum + length in the database. Doctrine does not validate the length of a + string value for you. + +- **precision**: The precision for a decimal (exact numeric) column + (applies only for decimal column), which is the maximum number of + digits that are stored for the values. + +- **scale**: The scale for a decimal (exact numeric) column (applies + only for decimal column), which represents the number of digits + to the right of the decimal point and must not be greater than + *precision*. + +- **unique**: Boolean value to determine if the value of the column + should be unique across all rows of the underlying entities table. + +- **nullable**: Determines if NULL values allowed for this column. If not specified, default value is false. + +- **options**: Array of additional options: + + - ``default``: The default value to set for the column if no value + is supplied. + + - ``unsigned``: Boolean value to determine if the column should + be capable of representing only non-negative integers + (applies only for integer column and might not be supported by + all vendors). + + - ``fixed``: Boolean value to determine if the specified length of + a string column should be fixed or varying (applies only for + string/binary column and might not be supported by all vendors). + + - ``comment``: The comment of the column in the schema (might not + be supported by all vendors). + + - ``collation``: The collation of the column (only supported by Drizzle, Mysql, PostgreSQL>=9.1, Sqlite and SQLServer). + + - ``check``: Adds a check constraint type to the column (might not + be supported by all vendors). + +- **columnDefinition**: DDL SQL snippet that starts after the column + name and specifies the complete (non-portable!) column definition. + This attribute allows to make use of advanced RMDBS features. + However you should make careful use of this feature and the + consequences. SchemaTool will not detect changes on the column correctly + anymore if you use "columnDefinition". + + Additionally you should remember that the "type" + attribute still handles the conversion between PHP and Database + values. If you use this attribute on a column that is used for + joins between tables you should also take a look at + :ref:`#[JoinColumn] `. + +.. note:: + + For more detailed information on each attribute, please refer to + the DBAL ``Schema-Representation`` documentation. + +Examples: + +.. code-block:: php + + true, "comment" => "Initial letters of first and last name"])] + protected $initials; + + #[Column(type: "integer", name: "login_count", nullable: false, options: ["unsigned" => true, "default" => 0])] + protected $loginCount; + +.. _annref_cache: + +#[Cache] +~~~~~~~~ +Add caching strategy to a root entity or a collection. + +Optional attributes: + +- **usage**: One of ``READ_ONLY``, ``READ_WRITE`` or ``NONSTRICT_READ_WRITE``, By default this is ``READ_ONLY``. +- **region**: An specific region name + +.. _annref_changetrackingpolicy: + +#[ChangeTrackingPolicy] +~~~~~~~~~~~~~~~~~~~~~~~ + +The Change Tracking Policy attribute allows to specify how the +Doctrine ORM UnitOfWork should detect changes in properties of +entities during flush. By default each entity is checked according +to a deferred implicit strategy, which means upon flush UnitOfWork +compares all the properties of an entity to a previously stored +snapshot. This works out of the box, however you might want to +tweak the flush performance where using another change tracking +policy is an interesting option. + +The :doc:`details on all the available change tracking policies ` +can be found in the configuration section. + +Example: + +.. code-block:: php + + ` and :ref:`@GeneratedValue(strategy="CUSTOM") ` are specified. + +Required attributes: + +- **class**: name of the class which should extend Doctrine\ORM\Id\AbstractIdGenerator + +Example: + +.. code-block:: php + + Person::class, "employee" => Employee::class])] + class Person + { + // ... + } + + +.. _annref_embeddable: + +#[Embeddable] +~~~~~~~~~~~~~ + +The embeddable attribute is required on a class, in order to make it +embeddable inside an entity. It works together with the :ref:`#[Embedded] ` +attribute to establish the relationship between the two classes. + +.. code-block:: php + + `. This +attribute is optional and only has meaning when used in +conjunction with #[Id]. + +If this attribute is not specified with #[Id] the NONE strategy is +used as default. + +Optional attributes: + +- **strategy**: Set the name of the identifier generation strategy. + Valid values are AUTO, SEQUENCE, TABLE, IDENTITY, UUID, CUSTOM and NONE. + If not specified, default value is AUTO. + +Example: + +.. code-block:: php + + ` and +:ref:`#[DiscriminatorColumn] ` attributes. + +Examples: + +.. code-block:: php + + `, :ref:`#[OneToOne] ` fields +and in the Context of a :ref:`#[ManyToMany] `. If this attribute or both *name* and *referencedColumnName* +are missing they will be computed considering the field's name and the current +:doc:`naming strategy `. + +The #[InverseJoinColumn] is the same as #[JoinColumn] and is used in the context +of a #[ManyToMany] attribute declaration to specifiy the details of the join table's +column information used for the join to the inverse entity. + +Optional attributes: + +- **name**: Column name that holds the foreign key identifier for + this relation. In the context of @JoinTable it specifies the column + name in the join table. +- **referencedColumnName**: Name of the primary key identifier that + is used for joining of this relation. Defaults to *id*. +- **unique**: Determines whether this relation is exclusive between the + affected entities and should be enforced as such on the database + constraint level. Defaults to false. +- **nullable**: Determine whether the related entity is required, or if + null is an allowed state for the relation. Defaults to true. +- **onDelete**: Cascade Action (Database-level) +- **columnDefinition**: DDL SQL snippet that starts after the column + name and specifies the complete (non-portable!) column definition. + This attribute enables the use of advanced RMDBS features. Using + this attribute on @JoinColumn is necessary if you need slightly + different column definitions for joining columns, for example + regarding NULL/NOT NULL defaults. However by default a + "columnDefinition" attribute on :ref:`#[Column] ` also sets + the related #[JoinColumn]'s columnDefinition. This is necessary to + make foreign keys work. + +Example: + +.. code-block:: php + + ` on the owning side of the relation +requires to specify the #[JoinTable] attribute which describes the +details of the database join table. If you do not specify +#[JoinTable] on these relations reasonable mapping defaults apply +using the affected table and the column names. + +A notable difference to the annotation metadata support, #[JoinColumn] +and #[InverseJoinColumn] are specified at the property level and are not +nested within the #[JoinTable] attribute. + +Required attribute: + +- **name**: Database name of the join-table + +Example: + +.. code-block:: php + + ` is an +additional, optional attribute that has reasonable default +configuration values using the table and names of the two related +entities. + +Required attributes: + + +- **targetEntity**: FQCN of the referenced target entity. Can be the + unqualified class name if both classes are in the same namespace. + *IMPORTANT:* No leading backslash! + +Optional attributes: + + +- **mappedBy**: This option specifies the property name on the + targetEntity that is the owning side of this relation. It is a + required attribute for the inverse side of a relationship. +- **inversedBy**: The inversedBy attribute designates the field in the + entity that is the inverse side of the relationship. +- **cascade**: Cascade Option +- **fetch**: One of LAZY, EXTRA_LAZY or EAGER +- **indexBy**: Index the collection by a field on the target entity. + +.. note:: + + For ManyToMany bidirectional relationships either side may + be the owning side (the side that defines the @JoinTable and/or + does not make use of the mappedBy attribute, thus using a default + join table). + +Example: + +.. code-block:: php + + `. + +Optional attributes: + +- **repositoryClass**: Specifies the FQCN of a subclass of the EntityRepository. + That will be inherited for all subclasses of that Mapped Superclass. + +Example: + +.. code-block:: php + + ` with one additional option which can +be specified. When no +:ref:`#[JoinColumn] ` is specified it defaults to using the target entity table and +primary key column names and the current naming strategy to determine a name for the join column. + +Required attributes: + +- **targetEntity**: FQCN of the referenced target entity. Can be the + unqualified class name if both classes are in the same namespace. + *IMPORTANT:* No leading backslash! + +Optional attributes: + +- **cascade**: Cascade Option +- **fetch**: One of LAZY or EAGER +- **orphanRemoval**: Boolean that specifies if orphans, inverse + OneToOne entities that are not connected to any owning instance, + should be removed by Doctrine. Defaults to false. +- **inversedBy**: The inversedBy attribute designates the field in the + entity that is the inverse side of the relationship. + +Example: + +.. code-block:: php + + ` or :ref:`#[OneToMany] ` +attribute to specify by which criteria the collection should be +retrieved from the database by using an ORDER BY clause. + +Example: + +.. code-block:: php + + "ASC"])] + private $groups; + +The key in OrderBy is only allowed to consist of +unqualified, unquoted field names and of an optional ASC/DESC +positional statement. Multiple Fields are separated by a comma (,). +The referenced field names have to exist on the ``targetEntity`` +class of the ``#[ManyToMany]`` or ``#[OneToMany]`` attribute. + +.. _annref_postload: + +#[PostLoad] +~~~~~~~~~~~~~~ + +Marks a method on the entity to be called as a #[PostLoad] event. +Only works with #[HasLifecycleCallbacks] in the entity class PHP +level. + +.. _annref_postpersist: + +#[PostPersist] +~~~~~~~~~~~~~~ + +Marks a method on the entity to be called as a #[PostPersist] event. +Only works with #[HasLifecycleCallbacks] in the entity class PHP +level. + +.. _annref_postremove: + +#[PostRemove] +~~~~~~~~~~~~~~ + +Marks a method on the entity to be called as a #[PostRemove] event. +Only works with #[HasLifecycleCallbacks] in the entity class PHP +level. + +.. _annref_postupdate: + +#[PostUpdate] +~~~~~~~~~~~~~~ + +Marks a method on the entity to be called as a #[PostUpdate] event. +Only works with #[HasLifecycleCallbacks] in the entity class PHP +level. + +.. _annref_prepersist: + +#[PrePersist] +~~~~~~~~~~~~~~ + +Marks a method on the entity to be called as a #[PrePersist] event. +Only works with #[HasLifecycleCallbacks] in the entity class PHP +level. + +.. _annref_preremove: + +#[PreRemove] +~~~~~~~~~~~~~~ + +Marks a method on the entity to be called as a #[PreRemove] event. +Only works with #[HasLifecycleCallbacks] in the entity class PHP +level. + +.. _annref_preupdate: + +#[PreUpdate] +~~~~~~~~~~~~~~ + +Marks a method on the entity to be called as a #[PreUpdate] event. +Only works with #[HasLifecycleCallbacks] in the entity class PHP +level. + +.. _annref_sequencegenerator: + +#[SequenceGenerator] +~~~~~~~~~~~~~~~~~~~~~ + +For use with #[GeneratedValue(strategy: "SEQUENCE")] this +attribute allows to specify details about the sequence, such as +the increment size and initial values of the sequence. + +Required attributes: + +- **sequenceName**: Name of the sequence + +Optional attributes: + +- **allocationSize**: Increment the sequence by the allocation size + when its fetched. A value larger than 1 allows optimization for + scenarios where you create more than one new entity per request. + Defaults to 10 +- **initialValue**: Where the sequence starts, defaults to 1. + +Example: + +.. code-block:: php + + ` +scenario. It only works on :ref:`#[Column] ` attributes that have +the type ``integer`` or ``datetime``. Setting ``#[Version]`` on a property with +:ref:`#[Id ` is not supported. + +Example: + +.. code-block:: php + + Date: Fri, 5 Feb 2021 21:46:25 +0100 Subject: [PATCH 27/37] Housekeeping: phpcs --- tests/Doctrine/Tests/Models/Company/CompanyContractListener.php | 1 + .../Doctrine/Tests/Models/Company/CompanyFlexUltraContract.php | 2 ++ 2 files changed, 3 insertions(+) diff --git a/tests/Doctrine/Tests/Models/Company/CompanyContractListener.php b/tests/Doctrine/Tests/Models/Company/CompanyContractListener.php index c8da865b714..15eaea578f1 100644 --- a/tests/Doctrine/Tests/Models/Company/CompanyContractListener.php +++ b/tests/Doctrine/Tests/Models/Company/CompanyContractListener.php @@ -3,6 +3,7 @@ namespace Doctrine\Tests\Models\Company; use Doctrine\ORM\Mapping as ORM; + use function func_get_args; class CompanyContractListener diff --git a/tests/Doctrine/Tests/Models/Company/CompanyFlexUltraContract.php b/tests/Doctrine/Tests/Models/Company/CompanyFlexUltraContract.php index 5cf1ba6df3a..aa2880c3e6a 100644 --- a/tests/Doctrine/Tests/Models/Company/CompanyFlexUltraContract.php +++ b/tests/Doctrine/Tests/Models/Company/CompanyFlexUltraContract.php @@ -6,6 +6,8 @@ use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping\ClassMetadataInfo; +use function max; + /** * @Entity * @EntityListeners({"CompanyContractListener","CompanyFlexUltraContractListener"}) From 035f496be314cb0b8c103bd5368ad37ea196c2d9 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Mon, 1 Mar 2021 18:42:29 +0100 Subject: [PATCH 28/37] More merge conflict resolutions --- .../ORM/Mapping/AbstractMappingDriverTest.php | 27 ++++--------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php index 8d2d567c402..e039fe81e02 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php @@ -1091,25 +1091,18 @@ class User #[ORM\SequenceGenerator(sequenceName: "tablename_seq", initialValue: 1, allocationSize: 100)] public $id; -<<<<<<< HEAD - /** @Column(length=50, nullable=true, unique=true, options={"foo": "bar", "baz": {"key": "val"}, "fixed": false}) */ - #[ORM\Column(length: 50, nullable: true, unique: true, options: ["foo" => "bar", "baz" => ["key" => "val"], "fixed" => false])] - public $name; - - /** @Column(name="user_email", columnDefinition="CHAR(32) NOT NULL") */ - #[ORM\Column(name: "user_email", columnDefinition: "CHAR(32) NOT NULL")] -======= /** * @var string * @Column(length=50, nullable=true, unique=true, options={"foo": "bar", "baz": {"key": "val"}, "fixed": false}) */ + #[ORM\Column(length: 50, nullable: true, unique: true, options: ["foo" => "bar", "baz" => ["key" => "val"], "fixed" => false])] public $name; /** * @var string * @Column(name="user_email", columnDefinition="CHAR(32) NOT NULL") */ ->>>>>>> 2.9.x + #[ORM\Column(name: "user_email", columnDefinition: "CHAR(32) NOT NULL")] public $email; /** @@ -1377,22 +1370,16 @@ public function __construct(?string $value = null) * @Id * @GeneratedValue(strategy="NONE") * @Column(type="integer", columnDefinition = "INT unsigned NOT NULL") -<<<<<<< HEAD + #[ORM\Id, ORM\GeneratedValue(strategy: "NONE"), ORM\Column(type: "integer", columnDefinition: "INT UNSIGNED NOT NULL")] **/ - #[ORM\Id, ORM\GeneratedValue(strategy: "NONE"), ORM\Column(type: "integer", columnDefinition: "INT UNSIGNED NOT NULL")] private $id; - /** @Column(columnDefinition = "VARCHAR(255) NOT NULL") */ - #[ORM\Column(columnDefinition: "VARCHAR(255) NOT NULL")] -======= - */ - private $id; /** * @var string|null * @Column(columnDefinition = "VARCHAR(255) NOT NULL") */ ->>>>>>> 2.9.x + #[ORM\Column(columnDefinition: "VARCHAR(255) NOT NULL")] private $value; public function getId(): int @@ -1492,15 +1479,11 @@ class Group #[ORM\Index(columns: ["content"], flags: ["fulltext"], options: ["where" => "content IS NOT NULL"])] class Comment { -<<<<<<< HEAD - /** @Column(type="text") */ - #[ORM\Column(type: "text")] -======= /** * @var string * @Column(type="text") */ ->>>>>>> 2.9.x + #[ORM\Column(type: "text")] private $content; public static function loadMetadata(ClassMetadataInfo $metadata): void From b3c8eef1498710693030944c1ff1e0bb93a418d0 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Mon, 1 Mar 2021 18:44:28 +0100 Subject: [PATCH 29/37] phpcs --- tests/Doctrine/Tests/Models/Cache/City.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Doctrine/Tests/Models/Cache/City.php b/tests/Doctrine/Tests/Models/Cache/City.php index d25c282134d..1a8a60db122 100644 --- a/tests/Doctrine/Tests/Models/Cache/City.php +++ b/tests/Doctrine/Tests/Models/Cache/City.php @@ -5,8 +5,8 @@ namespace Doctrine\Tests\Models\Cache; use Doctrine\Common\Collections\ArrayCollection; -use Doctrine\ORM\Mapping as ORM; use Doctrine\Common\Collections\Collection; +use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping\ClassMetadataInfo; /** From fe276be9adeaaddc1a7a9789527e64a584169cc5 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Mon, 1 Mar 2021 18:48:45 +0100 Subject: [PATCH 30/37] fix broken merge --- tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php index e039fe81e02..0d4dd5938f0 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php @@ -1370,8 +1370,8 @@ public function __construct(?string $value = null) * @Id * @GeneratedValue(strategy="NONE") * @Column(type="integer", columnDefinition = "INT unsigned NOT NULL") - #[ORM\Id, ORM\GeneratedValue(strategy: "NONE"), ORM\Column(type: "integer", columnDefinition: "INT UNSIGNED NOT NULL")] **/ + #[ORM\Id, ORM\GeneratedValue(strategy: "NONE"), ORM\Column(type: "integer", columnDefinition: "INT UNSIGNED NOT NULL")] private $id; From 276f88a65e1064a0e6224149cc3bf9123af079f7 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Mon, 1 Mar 2021 19:20:45 +0100 Subject: [PATCH 31/37] Change NamedArgumentConstructorAnnotation interface to use NamedArgumentConstructor annotation instead. --- composer.json | 2 +- lib/Doctrine/ORM/Mapping/Annotation.php | 1 - lib/Doctrine/ORM/Mapping/Cache.php | 9 +++++---- lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php | 5 +++-- lib/Doctrine/ORM/Mapping/Column.php | 5 +++-- lib/Doctrine/ORM/Mapping/CustomIdGenerator.php | 9 +++++---- lib/Doctrine/ORM/Mapping/DiscriminatorColumn.php | 5 +++-- lib/Doctrine/ORM/Mapping/DiscriminatorMap.php | 5 +++-- lib/Doctrine/ORM/Mapping/Embedded.php | 5 +++-- lib/Doctrine/ORM/Mapping/Entity.php | 5 +++-- lib/Doctrine/ORM/Mapping/EntityListeners.php | 5 +++-- lib/Doctrine/ORM/Mapping/GeneratedValue.php | 9 +++++---- lib/Doctrine/ORM/Mapping/Index.php | 5 +++-- lib/Doctrine/ORM/Mapping/InheritanceType.php | 5 +++-- lib/Doctrine/ORM/Mapping/JoinColumn.php | 5 +++-- lib/Doctrine/ORM/Mapping/JoinTable.php | 5 +++-- lib/Doctrine/ORM/Mapping/ManyToMany.php | 5 +++-- lib/Doctrine/ORM/Mapping/ManyToOne.php | 5 +++-- lib/Doctrine/ORM/Mapping/MappedSuperclass.php | 5 +++-- lib/Doctrine/ORM/Mapping/OneToMany.php | 5 +++-- lib/Doctrine/ORM/Mapping/OneToOne.php | 5 +++-- lib/Doctrine/ORM/Mapping/OrderBy.php | 5 +++-- lib/Doctrine/ORM/Mapping/SequenceGenerator.php | 5 +++-- lib/Doctrine/ORM/Mapping/Table.php | 10 +++++----- lib/Doctrine/ORM/Mapping/UniqueConstraint.php | 5 +++-- 25 files changed, 78 insertions(+), 57 deletions(-) diff --git a/composer.json b/composer.json index 34f3491a3fb..6f4ad568761 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,7 @@ "php": "^7.2|^8.0", "ext-pdo": "*", "composer/package-versions-deprecated": "^1.8", - "doctrine/annotations": "^1.11.1", + "doctrine/annotations": "^1.12", "doctrine/cache": "^1.9.1", "doctrine/collections": "^1.5", "doctrine/common": "^3.0.3", diff --git a/lib/Doctrine/ORM/Mapping/Annotation.php b/lib/Doctrine/ORM/Mapping/Annotation.php index 4593ad41362..edbea1510b6 100644 --- a/lib/Doctrine/ORM/Mapping/Annotation.php +++ b/lib/Doctrine/ORM/Mapping/Annotation.php @@ -20,7 +20,6 @@ namespace Doctrine\ORM\Mapping; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; interface Annotation { diff --git a/lib/Doctrine/ORM/Mapping/Cache.php b/lib/Doctrine/ORM/Mapping/Cache.php index c030f11f30f..1f56e9110ad 100644 --- a/lib/Doctrine/ORM/Mapping/Cache.php +++ b/lib/Doctrine/ORM/Mapping/Cache.php @@ -21,16 +21,17 @@ namespace Doctrine\ORM\Mapping; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * Caching to an entity or a collection. * * @Annotation + * @NamedArgumentConstructor() * @Target({"CLASS","PROPERTY"}) */ #[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_PROPERTY)] -final class Cache implements Annotation, NamedArgumentConstructorAnnotation +final class Cache implements Annotation { /** * @Enum({"READ_ONLY", "NONSTRICT_READ_WRITE", "READ_WRITE"}) @@ -41,9 +42,9 @@ final class Cache implements Annotation, NamedArgumentConstructorAnnotation /** @var string Cache region name. */ public $region; - public function __construct(string $usage = 'READ_ONLY', ?string $region = null, $value = null) + public function __construct(string $usage = 'READ_ONLY', ?string $region = null) { - $this->usage = $value ?: $usage; + $this->usage = $usage; $this->region = $region; } } diff --git a/lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php b/lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php index 6dcf86d75cc..f57cbf27461 100644 --- a/lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php +++ b/lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php @@ -21,14 +21,15 @@ namespace Doctrine\ORM\Mapping; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * @Annotation + * @NamedArgumentConstructor() * @Target("CLASS") */ #[Attribute(Attribute::TARGET_CLASS)] -final class ChangeTrackingPolicy implements Annotation, NamedArgumentConstructorAnnotation +final class ChangeTrackingPolicy implements Annotation { /** * The change tracking policy. diff --git a/lib/Doctrine/ORM/Mapping/Column.php b/lib/Doctrine/ORM/Mapping/Column.php index c679a12e5f9..4b57501833d 100644 --- a/lib/Doctrine/ORM/Mapping/Column.php +++ b/lib/Doctrine/ORM/Mapping/Column.php @@ -21,14 +21,15 @@ namespace Doctrine\ORM\Mapping; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * @Annotation + * @NamedArgumentConstructor() * @Target({"PROPERTY","ANNOTATION"}) */ #[Attribute(Attribute::TARGET_PROPERTY)] -final class Column implements Annotation, NamedArgumentConstructorAnnotation +final class Column implements Annotation { /** @var string */ public $name; diff --git a/lib/Doctrine/ORM/Mapping/CustomIdGenerator.php b/lib/Doctrine/ORM/Mapping/CustomIdGenerator.php index 632b6308fa0..cbb9b792ecf 100644 --- a/lib/Doctrine/ORM/Mapping/CustomIdGenerator.php +++ b/lib/Doctrine/ORM/Mapping/CustomIdGenerator.php @@ -21,20 +21,21 @@ namespace Doctrine\ORM\Mapping; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * @Annotation + * @NamedArgumentConstructor * @Target("PROPERTY") */ #[Attribute(Attribute::TARGET_PROPERTY)] -final class CustomIdGenerator implements Annotation, NamedArgumentConstructorAnnotation +final class CustomIdGenerator implements Annotation { /** @var string */ public $class; - public function __construct(?string $class = null, ?string $value = null) + public function __construct(?string $class = null) { - $this->class = $value ?: $class; + $this->class = $class; } } diff --git a/lib/Doctrine/ORM/Mapping/DiscriminatorColumn.php b/lib/Doctrine/ORM/Mapping/DiscriminatorColumn.php index 30316bfc46c..e59725b94d2 100644 --- a/lib/Doctrine/ORM/Mapping/DiscriminatorColumn.php +++ b/lib/Doctrine/ORM/Mapping/DiscriminatorColumn.php @@ -21,14 +21,15 @@ namespace Doctrine\ORM\Mapping; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * @Annotation + * @NamedArgumentConstructor() * @Target("CLASS") */ #[Attribute(Attribute::TARGET_CLASS)] -final class DiscriminatorColumn implements Annotation, NamedArgumentConstructorAnnotation +final class DiscriminatorColumn implements Annotation { /** @var string */ public $name; diff --git a/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php b/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php index c793bb42249..7ca25513d8b 100644 --- a/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php +++ b/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php @@ -21,14 +21,15 @@ namespace Doctrine\ORM\Mapping; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * @Annotation + * @NamedArgumentConstructor() * @Target("CLASS") */ #[Attribute(Attribute::TARGET_CLASS)] -final class DiscriminatorMap implements Annotation, NamedArgumentConstructorAnnotation +final class DiscriminatorMap implements Annotation { /** @var array */ public $value; diff --git a/lib/Doctrine/ORM/Mapping/Embedded.php b/lib/Doctrine/ORM/Mapping/Embedded.php index a96c409f0db..6090f75836c 100644 --- a/lib/Doctrine/ORM/Mapping/Embedded.php +++ b/lib/Doctrine/ORM/Mapping/Embedded.php @@ -21,14 +21,15 @@ namespace Doctrine\ORM\Mapping; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * @Annotation + * @NamedArgumentConstructor() * @Target("PROPERTY") */ #[Attribute(Attribute::TARGET_PROPERTY)] -final class Embedded implements Annotation, NamedArgumentConstructorAnnotation +final class Embedded implements Annotation { /** * @Required diff --git a/lib/Doctrine/ORM/Mapping/Entity.php b/lib/Doctrine/ORM/Mapping/Entity.php index 4000e747c6c..393b24ed6a1 100644 --- a/lib/Doctrine/ORM/Mapping/Entity.php +++ b/lib/Doctrine/ORM/Mapping/Entity.php @@ -21,14 +21,15 @@ namespace Doctrine\ORM\Mapping; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * @Annotation + * @NamedArgumentConstructor() * @Target("CLASS") */ #[Attribute(Attribute::TARGET_CLASS)] -final class Entity implements Annotation, NamedArgumentConstructorAnnotation +final class Entity implements Annotation { /** @var string */ public $repositoryClass; diff --git a/lib/Doctrine/ORM/Mapping/EntityListeners.php b/lib/Doctrine/ORM/Mapping/EntityListeners.php index a7f2c370f1f..b9f6605b34b 100644 --- a/lib/Doctrine/ORM/Mapping/EntityListeners.php +++ b/lib/Doctrine/ORM/Mapping/EntityListeners.php @@ -21,17 +21,18 @@ namespace Doctrine\ORM\Mapping; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * 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. * * @Annotation + * @NamedArgumentConstructor() * @Target("CLASS") */ #[Attribute(Attribute::TARGET_CLASS)] -final class EntityListeners implements Annotation, NamedArgumentConstructorAnnotation +final class EntityListeners implements Annotation { /** * Specifies the names of the entity listeners. diff --git a/lib/Doctrine/ORM/Mapping/GeneratedValue.php b/lib/Doctrine/ORM/Mapping/GeneratedValue.php index 553106886e0..8844784ac82 100644 --- a/lib/Doctrine/ORM/Mapping/GeneratedValue.php +++ b/lib/Doctrine/ORM/Mapping/GeneratedValue.php @@ -21,14 +21,15 @@ namespace Doctrine\ORM\Mapping; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * @Annotation + * @NamedArgumentConstructor() * @Target("PROPERTY") */ #[Attribute(Attribute::TARGET_PROPERTY)] -final class GeneratedValue implements Annotation, NamedArgumentConstructorAnnotation +final class GeneratedValue implements Annotation { /** * The type of Id generator. @@ -38,8 +39,8 @@ final class GeneratedValue implements Annotation, NamedArgumentConstructorAnnota */ public $strategy = 'AUTO'; - public function __construct(string $strategy = 'AUTO', ?string $value = null) + public function __construct(string $strategy = 'AUTO') { - $this->strategy = $value ?: $strategy; + $this->strategy = $strategy; } } diff --git a/lib/Doctrine/ORM/Mapping/Index.php b/lib/Doctrine/ORM/Mapping/Index.php index 33fb1d54b3a..3ed3339cf90 100644 --- a/lib/Doctrine/ORM/Mapping/Index.php +++ b/lib/Doctrine/ORM/Mapping/Index.php @@ -21,14 +21,15 @@ namespace Doctrine\ORM\Mapping; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * @Annotation + * @NamedArgumentConstructor() * @Target("ANNOTATION") */ #[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] -final class Index implements Annotation, NamedArgumentConstructorAnnotation +final class Index implements Annotation { /** @var string */ public $name; diff --git a/lib/Doctrine/ORM/Mapping/InheritanceType.php b/lib/Doctrine/ORM/Mapping/InheritanceType.php index ec16f0f51e5..ae4fa2ffdf0 100644 --- a/lib/Doctrine/ORM/Mapping/InheritanceType.php +++ b/lib/Doctrine/ORM/Mapping/InheritanceType.php @@ -21,14 +21,15 @@ namespace Doctrine\ORM\Mapping; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * @Annotation + * @NamedArgumentConstructor() * @Target("CLASS") */ #[Attribute(Attribute::TARGET_CLASS)] -final class InheritanceType implements Annotation, NamedArgumentConstructorAnnotation +final class InheritanceType implements Annotation { /** * The inheritance type used by the class and its subclasses. diff --git a/lib/Doctrine/ORM/Mapping/JoinColumn.php b/lib/Doctrine/ORM/Mapping/JoinColumn.php index 8630a1e6cf2..7511b7dd226 100644 --- a/lib/Doctrine/ORM/Mapping/JoinColumn.php +++ b/lib/Doctrine/ORM/Mapping/JoinColumn.php @@ -21,14 +21,15 @@ namespace Doctrine\ORM\Mapping; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * @Annotation + * @NamedArgumentConstructor() * @Target({"PROPERTY","ANNOTATION"}) */ #[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] -final class JoinColumn implements Annotation, NamedArgumentConstructorAnnotation +final class JoinColumn implements Annotation { /** @var string */ public $name; diff --git a/lib/Doctrine/ORM/Mapping/JoinTable.php b/lib/Doctrine/ORM/Mapping/JoinTable.php index 0bbb878187c..a4a5d10b8c5 100644 --- a/lib/Doctrine/ORM/Mapping/JoinTable.php +++ b/lib/Doctrine/ORM/Mapping/JoinTable.php @@ -21,14 +21,15 @@ namespace Doctrine\ORM\Mapping; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * @Annotation + * @NamedArgumentConstructor() * @Target({"PROPERTY","ANNOTATION"}) */ #[Attribute(Attribute::TARGET_PROPERTY)] -final class JoinTable implements Annotation, NamedArgumentConstructorAnnotation +final class JoinTable implements Annotation { /** @var string */ public $name; diff --git a/lib/Doctrine/ORM/Mapping/ManyToMany.php b/lib/Doctrine/ORM/Mapping/ManyToMany.php index 6780a8146b1..d9c8bedf650 100644 --- a/lib/Doctrine/ORM/Mapping/ManyToMany.php +++ b/lib/Doctrine/ORM/Mapping/ManyToMany.php @@ -21,14 +21,15 @@ namespace Doctrine\ORM\Mapping; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * @Annotation + * @NamedArgumentConstructor() * @Target("PROPERTY") */ #[Attribute(Attribute::TARGET_PROPERTY)] -final class ManyToMany implements Annotation, NamedArgumentConstructorAnnotation +final class ManyToMany implements Annotation { /** @var string */ public $targetEntity; diff --git a/lib/Doctrine/ORM/Mapping/ManyToOne.php b/lib/Doctrine/ORM/Mapping/ManyToOne.php index 10295fc17ae..00e59aa1310 100644 --- a/lib/Doctrine/ORM/Mapping/ManyToOne.php +++ b/lib/Doctrine/ORM/Mapping/ManyToOne.php @@ -21,14 +21,15 @@ namespace Doctrine\ORM\Mapping; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * @Annotation + * @NamedArgumentConstructor() * @Target("PROPERTY") */ #[Attribute(Attribute::TARGET_PROPERTY)] -final class ManyToOne implements Annotation, NamedArgumentConstructorAnnotation +final class ManyToOne implements Annotation { /** @var string */ public $targetEntity; diff --git a/lib/Doctrine/ORM/Mapping/MappedSuperclass.php b/lib/Doctrine/ORM/Mapping/MappedSuperclass.php index 52d53098099..479e9f73836 100644 --- a/lib/Doctrine/ORM/Mapping/MappedSuperclass.php +++ b/lib/Doctrine/ORM/Mapping/MappedSuperclass.php @@ -21,14 +21,15 @@ namespace Doctrine\ORM\Mapping; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * @Annotation + * @NamedArgumentConstructor() * @Target("CLASS") */ #[Attribute(Attribute::TARGET_CLASS)] -final class MappedSuperclass implements Annotation, NamedArgumentConstructorAnnotation +final class MappedSuperclass implements Annotation { /** @var string */ public $repositoryClass; diff --git a/lib/Doctrine/ORM/Mapping/OneToMany.php b/lib/Doctrine/ORM/Mapping/OneToMany.php index 2f558467a7d..a65730e8b4d 100644 --- a/lib/Doctrine/ORM/Mapping/OneToMany.php +++ b/lib/Doctrine/ORM/Mapping/OneToMany.php @@ -21,14 +21,15 @@ namespace Doctrine\ORM\Mapping; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * @Annotation + * @NamedArgumentConstructor() * @Target("PROPERTY") */ #[Attribute(Attribute::TARGET_PROPERTY)] -final class OneToMany implements Annotation, NamedArgumentConstructorAnnotation +final class OneToMany implements Annotation { /** @var string */ public $mappedBy; diff --git a/lib/Doctrine/ORM/Mapping/OneToOne.php b/lib/Doctrine/ORM/Mapping/OneToOne.php index 8684cc0b806..64dd8cbcf42 100644 --- a/lib/Doctrine/ORM/Mapping/OneToOne.php +++ b/lib/Doctrine/ORM/Mapping/OneToOne.php @@ -21,14 +21,15 @@ namespace Doctrine\ORM\Mapping; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * @Annotation + * @NamedArgumentConstructor() * @Target("PROPERTY") */ #[Attribute(Attribute::TARGET_PROPERTY)] -final class OneToOne implements Annotation, NamedArgumentConstructorAnnotation +final class OneToOne implements Annotation { /** @var string */ public $targetEntity; diff --git a/lib/Doctrine/ORM/Mapping/OrderBy.php b/lib/Doctrine/ORM/Mapping/OrderBy.php index c8782aaa0bd..d006380f98a 100644 --- a/lib/Doctrine/ORM/Mapping/OrderBy.php +++ b/lib/Doctrine/ORM/Mapping/OrderBy.php @@ -21,14 +21,15 @@ namespace Doctrine\ORM\Mapping; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * @Annotation + * @NamedArgumentConstructor() * @Target("PROPERTY") */ #[Attribute(Attribute::TARGET_PROPERTY)] -final class OrderBy implements Annotation, NamedArgumentConstructorAnnotation +final class OrderBy implements Annotation { /** @var array */ public $value; diff --git a/lib/Doctrine/ORM/Mapping/SequenceGenerator.php b/lib/Doctrine/ORM/Mapping/SequenceGenerator.php index 1078e7c2bb4..3f1c1696487 100644 --- a/lib/Doctrine/ORM/Mapping/SequenceGenerator.php +++ b/lib/Doctrine/ORM/Mapping/SequenceGenerator.php @@ -21,14 +21,15 @@ namespace Doctrine\ORM\Mapping; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * @Annotation + * @NamedArgumentConstructor() * @Target("PROPERTY") */ #[Attribute(Attribute::TARGET_PROPERTY)] -final class SequenceGenerator implements Annotation, NamedArgumentConstructorAnnotation +final class SequenceGenerator implements Annotation { /** @var string */ public $sequenceName; diff --git a/lib/Doctrine/ORM/Mapping/Table.php b/lib/Doctrine/ORM/Mapping/Table.php index 3dd65276e22..a570e4a9402 100644 --- a/lib/Doctrine/ORM/Mapping/Table.php +++ b/lib/Doctrine/ORM/Mapping/Table.php @@ -21,14 +21,15 @@ namespace Doctrine\ORM\Mapping; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * @Annotation + * @NamedArgumentConstructor * @Target("CLASS") */ #[Attribute(Attribute::TARGET_CLASS)] -final class Table implements Annotation, NamedArgumentConstructorAnnotation +final class Table implements Annotation { /** @var string */ public $name; @@ -55,10 +56,9 @@ public function __construct( ?string $schema = null, ?array $indexes = null, ?array $uniqueConstraints = null, - array $options = [], - ?string $value = null + array $options = [] ) { - $this->name = $value ?: $name; + $this->name = $name; $this->schema = $schema; $this->indexes = $indexes; $this->uniqueConstraints = $uniqueConstraints; diff --git a/lib/Doctrine/ORM/Mapping/UniqueConstraint.php b/lib/Doctrine/ORM/Mapping/UniqueConstraint.php index b82f767577f..f91467ec208 100644 --- a/lib/Doctrine/ORM/Mapping/UniqueConstraint.php +++ b/lib/Doctrine/ORM/Mapping/UniqueConstraint.php @@ -21,14 +21,15 @@ namespace Doctrine\ORM\Mapping; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * @Annotation + * @NamedArgumentConstructor() * @Target("ANNOTATION") */ #[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] -final class UniqueConstraint implements Annotation, NamedArgumentConstructorAnnotation +final class UniqueConstraint implements Annotation { /** @var string */ public $name; From 32108c4ca99c78e722305d177fbbc5f7468fab27 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Mon, 1 Mar 2021 19:21:19 +0100 Subject: [PATCH 32/37] phpcs --- lib/Doctrine/ORM/Mapping/Annotation.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/Doctrine/ORM/Mapping/Annotation.php b/lib/Doctrine/ORM/Mapping/Annotation.php index edbea1510b6..96e3a22aae3 100644 --- a/lib/Doctrine/ORM/Mapping/Annotation.php +++ b/lib/Doctrine/ORM/Mapping/Annotation.php @@ -20,7 +20,6 @@ namespace Doctrine\ORM\Mapping; - interface Annotation { } From 19d7072656229d5af9fed1c7d25f051984d4a8ad Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Mon, 22 Mar 2021 00:00:34 +0100 Subject: [PATCH 33/37] Housekeeping: cs --- tests/Doctrine/Tests/Models/Company/CompanyFlexContract.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Doctrine/Tests/Models/Company/CompanyFlexContract.php b/tests/Doctrine/Tests/Models/Company/CompanyFlexContract.php index 4717d0dd9d6..faaea762289 100644 --- a/tests/Doctrine/Tests/Models/Company/CompanyFlexContract.php +++ b/tests/Doctrine/Tests/Models/Company/CompanyFlexContract.php @@ -2,8 +2,8 @@ namespace Doctrine\Tests\Models\Company; -use Doctrine\ORM\Mapping as ORM; use Doctrine\Common\Collections\Collection; +use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping\ClassMetadataInfo; /** From 77abe20a3b228cf99f786acc65a02fe4833003e5 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Mon, 22 Mar 2021 00:04:03 +0100 Subject: [PATCH 34/37] Housekeeping: cs --- phpcs.xml.dist | 1 + 1 file changed, 1 insertion(+) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index dc0c766bf1f..d598042a355 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -31,6 +31,7 @@ + From 3779a9ba0d02835512d7b3fb539b5ac1d49bdcec Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Mon, 22 Mar 2021 00:34:32 +0100 Subject: [PATCH 35/37] Update docs with review comments --- docs/en/reference/attributes-reference.rst | 34 +++++++++++----------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/en/reference/attributes-reference.rst b/docs/en/reference/attributes-reference.rst index e4d79440fc7..4cdab7685a8 100644 --- a/docs/en/reference/attributes-reference.rst +++ b/docs/en/reference/attributes-reference.rst @@ -199,7 +199,7 @@ Example: #[CustomIdGenerator] ~~~~~~~~~~~~~~~~~~~~ -This attribute allows you to specify a user-provided class to generate identifiers. This attribute only works when both :ref:`@Id ` and :ref:`@GeneratedValue(strategy="CUSTOM") ` are specified. +This attribute allows you to specify a user-provided class to generate identifiers. This attribute only works when both :ref:`#[Id] ` and :ref:`#[GeneratedValue(strategy: "CUSTOM")] ` are specified. Required attributes: @@ -836,8 +836,8 @@ class of the ``#[ManyToMany]`` or ``#[OneToMany]`` attribute. #[PostLoad] ~~~~~~~~~~~~~~ -Marks a method on the entity to be called as a #[PostLoad] event. -Only works with #[HasLifecycleCallbacks] in the entity class PHP +Marks a method on the entity to be called as a ``#[PostLoad]`` event. +Only works with ``#[HasLifecycleCallbacks]`` in the entity class PHP level. .. _annref_postpersist: @@ -845,8 +845,8 @@ level. #[PostPersist] ~~~~~~~~~~~~~~ -Marks a method on the entity to be called as a #[PostPersist] event. -Only works with #[HasLifecycleCallbacks] in the entity class PHP +Marks a method on the entity to be called as a ``#[PostPersist]`` event. +Only works with ``#[HasLifecycleCallbacks]`` in the entity class PHP level. .. _annref_postremove: @@ -854,8 +854,8 @@ level. #[PostRemove] ~~~~~~~~~~~~~~ -Marks a method on the entity to be called as a #[PostRemove] event. -Only works with #[HasLifecycleCallbacks] in the entity class PHP +Marks a method on the entity to be called as a ``#[PostRemove]`` event. +Only works with ``#[HasLifecycleCallbacks]`` in the entity class PHP level. .. _annref_postupdate: @@ -863,8 +863,8 @@ level. #[PostUpdate] ~~~~~~~~~~~~~~ -Marks a method on the entity to be called as a #[PostUpdate] event. -Only works with #[HasLifecycleCallbacks] in the entity class PHP +Marks a method on the entity to be called as a ``#[PostUpdate]`` event. +Only works with ``#[HasLifecycleCallbacks]`` in the entity class PHP level. .. _annref_prepersist: @@ -872,8 +872,8 @@ level. #[PrePersist] ~~~~~~~~~~~~~~ -Marks a method on the entity to be called as a #[PrePersist] event. -Only works with #[HasLifecycleCallbacks] in the entity class PHP +Marks a method on the entity to be called as a ``#[PrePersist]`` event. +Only works with ``#[HasLifecycleCallbacks]`` in the entity class PHP level. .. _annref_preremove: @@ -881,8 +881,8 @@ level. #[PreRemove] ~~~~~~~~~~~~~~ -Marks a method on the entity to be called as a #[PreRemove] event. -Only works with #[HasLifecycleCallbacks] in the entity class PHP +Marks a method on the entity to be called as a #``[PreRemove]`` event. +Only works with ``#[HasLifecycleCallbacks]`` in the entity class PHP level. .. _annref_preupdate: @@ -890,8 +890,8 @@ level. #[PreUpdate] ~~~~~~~~~~~~~~ -Marks a method on the entity to be called as a #[PreUpdate] event. -Only works with #[HasLifecycleCallbacks] in the entity class PHP +Marks a method on the entity to be called as a ``#[PreUpdate]`` event. +Only works with ``#[HasLifecycleCallbacks]`` in the entity class PHP level. .. _annref_sequencegenerator: @@ -899,7 +899,7 @@ level. #[SequenceGenerator] ~~~~~~~~~~~~~~~~~~~~~ -For use with #[GeneratedValue(strategy: "SEQUENCE")] this +For use with ``#[GeneratedValue(strategy: "SEQUENCE")]`` this attribute allows to specify details about the sequence, such as the increment size and initial values of the sequence. @@ -967,7 +967,7 @@ Example: ~~~~~~~~~~~~~~~~~~~ Attribute is used on -the entity-class level. It allows to hint the SchemaTool to +the entity-class level. It allows to hint the ``SchemaTool`` to generate a database unique constraint on the specified table columns. It only has meaning in the SchemaTool schema generation context. From cee88ca8e948191c24ab004a9aae48540e39c56d Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Mon, 22 Mar 2021 00:43:45 +0100 Subject: [PATCH 36/37] Improve attribute docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Grégoire Paris --- docs/en/reference/attributes-reference.rst | 91 ++++++++++++---------- 1 file changed, 50 insertions(+), 41 deletions(-) diff --git a/docs/en/reference/attributes-reference.rst b/docs/en/reference/attributes-reference.rst index 4cdab7685a8..d8a3b0d734f 100644 --- a/docs/en/reference/attributes-reference.rst +++ b/docs/en/reference/attributes-reference.rst @@ -61,16 +61,16 @@ as part of the lifecycle of the instance variables entity-class. Required attributes: -- **type**: Name of the Doctrine Type which is converted between PHP +- **type**: Name of the DBAL Type which does the conversion between PHP and Database representation. Optional attributes: - **name**: By default the property name is used for the database - column name also, however the 'name' attribute allows you to + column name also, however the ``name`` attribute allows you to determine the column name. -- **length**: Used by the "string" type to determine its maximum +- **length**: Used by the ``string`` type to determine its maximum length in the database. Doctrine does not validate the length of a string value for you. @@ -86,7 +86,8 @@ Optional attributes: - **unique**: Boolean value to determine if the value of the column should be unique across all rows of the underlying entities table. -- **nullable**: Determines if NULL values allowed for this column. If not specified, default value is false. +- **nullable**: Determines if NULL values allowed for this column. + If not specified, default value is ``false``. - **options**: Array of additional options: @@ -105,7 +106,7 @@ Optional attributes: - ``comment``: The comment of the column in the schema (might not be supported by all vendors). - - ``collation``: The collation of the column (only supported by Drizzle, Mysql, PostgreSQL>=9.1, Sqlite and SQLServer). + - ``collation``: The collation of the column (only supported by Mysql, PostgreSQL, Sqlite and SQLServer). - ``check``: Adds a check constraint type to the column (might not be supported by all vendors). @@ -114,10 +115,10 @@ Optional attributes: name and specifies the complete (non-portable!) column definition. This attribute allows to make use of advanced RMDBS features. However you should make careful use of this feature and the - consequences. SchemaTool will not detect changes on the column correctly - anymore if you use "columnDefinition". + consequences. ``SchemaTool`` will not detect changes on the column correctly + anymore if you use ``columnDefinition``. - Additionally you should remember that the "type" + Additionally you should remember that the ``type`` attribute still handles the conversion between PHP and Database values. If you use this attribute on a column that is used for joins between tables you should also take a look at @@ -144,10 +145,18 @@ Examples: #[Column(type: "decimal", precision: 2, scale: 1)] protected $height; - #[Column(type: "string", length: 2, options: ["fixed" => true, "comment" => "Initial letters of first and last name"])] + #[Column(type: "string", length: 2, options: [ + "fixed" => true, + "comment" => "Initial letters of first and last name" + ])] protected $initials; - #[Column(type: "integer", name: "login_count", nullable: false, options: ["unsigned" => true, "default" => 0])] + #[Column( + type: "integer", + name: "login_count", + nullable: false, + options: ["unsigned" => true, "default" => 0] + )] protected $loginCount; .. _annref_cache: @@ -167,9 +176,9 @@ Optional attributes: ~~~~~~~~~~~~~~~~~~~~~~~ The Change Tracking Policy attribute allows to specify how the -Doctrine ORM UnitOfWork should detect changes in properties of +Doctrine ORM ``UnitOfWork`` should detect changes in properties of entities during flush. By default each entity is checked according -to a deferred implicit strategy, which means upon flush UnitOfWork +to a deferred implicit strategy, which means upon flush ``UnitOfWork`` compares all the properties of an entity to a previously stored snapshot. This works out of the box, however you might want to tweak the flush performance where using another change tracking @@ -227,7 +236,7 @@ Example: #[DiscriminatorColumn] ~~~~~~~~~~~~~~~~~~~~~~ -This attribute is an optional and set on the root entity +This attribute is optional and set on the root entity class of an inheritance hierarchy. It specifies the details of the column which saves the name of the class, which the entity is actually instantiated as. @@ -305,7 +314,7 @@ attribute to establish the relationship between the two classes. .. _annref_embedded: #[Embedded] -~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~ The embedded attribute is required on an entity's member variable, in order to specify that it is an embedded class. @@ -325,7 +334,7 @@ the persistence of all classes marked as entities. Optional attributes: - **repositoryClass**: Specifies the FQCN of a subclass of the - EntityRepository. Use of repositories for entities is encouraged to keep + ``EntityRepository``. Use of repositories for entities is encouraged to keep specialized DQL and SQL operations separated from the Model/Domain Layer. - **readOnly**: Specifies that this entity is marked as read only and not @@ -356,14 +365,15 @@ instance variable which is annotated by :ref:`#[Id] `. This attribute is optional and only has meaning when used in conjunction with #[Id]. -If this attribute is not specified with #[Id] the NONE strategy is +If this attribute is not specified with ``#[Id]`` the ``NONE`` strategy is used as default. Optional attributes: - **strategy**: Set the name of the identifier generation strategy. - Valid values are AUTO, SEQUENCE, TABLE, IDENTITY, UUID, CUSTOM and NONE. - If not specified, default value is AUTO. + Valid values are ``AUTO``, ``SEQUENCE``, ``TABLE``, ``IDENTITY``, + ``UUID``, ``CUSTOM`` and ``NONE``. + If not specified, the default value is ``AUTO``. Example: @@ -385,9 +395,9 @@ Example: This attribute has to be set on the entity-class to notify Doctrine that this entity has entity lifecycle callback attributes set on at least one of its methods. Using #[PostLoad], -#[PrePersist], #[PostPersist], #[PreRemove], #[PostRemove], #[PreUpdate] or -#[PostUpdate] without this marker attribute will make Doctrine -ignore the callbacks. +``#[PrePersist]``, ``#[PostPersist]``, ``#[PreRemove]``, ``#[PostRemove]``, +``#[PreUpdate]`` or ``#[PostUpdate]`` without this marker attribute will +make Doctrine ignore the callbacks. Example: @@ -412,7 +422,7 @@ Example: Attribute is used on the entity-class level. It provides a hint to the SchemaTool to generate a database index on the specified table columns. It only -has meaning in the SchemaTool schema generation context. +has meaning in the ``SchemaTool`` schema generation context. Required attributes: @@ -531,17 +541,17 @@ and in the Context of a :ref:`#[ManyToMany] `. If this attrib are missing they will be computed considering the field's name and the current :doc:`naming strategy `. -The #[InverseJoinColumn] is the same as #[JoinColumn] and is used in the context -of a #[ManyToMany] attribute declaration to specifiy the details of the join table's +The ``#[InverseJoinColumn]`` is the same as ``#[JoinColumn]`` and is used in the context +of a ``#[ManyToMany]`` attribute declaration to specifiy the details of the join table's column information used for the join to the inverse entity. Optional attributes: - **name**: Column name that holds the foreign key identifier for - this relation. In the context of @JoinTable it specifies the column + this relation. In the context of ``#[JoinTable]`` it specifies the column name in the join table. - **referencedColumnName**: Name of the primary key identifier that - is used for joining of this relation. Defaults to *id*. + is used for joining of this relation. Defaults to ``id``. - **unique**: Determines whether this relation is exclusive between the affected entities and should be enforced as such on the database constraint level. Defaults to false. @@ -551,11 +561,11 @@ Optional attributes: - **columnDefinition**: DDL SQL snippet that starts after the column name and specifies the complete (non-portable!) column definition. This attribute enables the use of advanced RMDBS features. Using - this attribute on @JoinColumn is necessary if you need slightly + this attribute on ``#[JoinColumn]`` is necessary if you need slightly different column definitions for joining columns, for example regarding NULL/NOT NULL defaults. However by default a "columnDefinition" attribute on :ref:`#[Column] ` also sets - the related #[JoinColumn]'s columnDefinition. This is necessary to + the related ``#[JoinColumn]``'s columnDefinition. This is necessary to make foreign keys work. Example: @@ -579,12 +589,12 @@ Using :ref:`#[ManytoMany] ` on the owning side of the relation requires to specify the #[JoinTable] attribute which describes the details of the database join table. If you do not specify -#[JoinTable] on these relations reasonable mapping defaults apply +``#[JoinTable]`` on these relations reasonable mapping defaults apply using the affected table and the column names. -A notable difference to the annotation metadata support, #[JoinColumn] -and #[InverseJoinColumn] are specified at the property level and are not -nested within the #[JoinTable] attribute. +A notable difference to the annotation metadata support, ``#[JoinColumn]`` +and ``#[InverseJoinColumn]`` are specified at the property level and are not +nested within the ``#[JoinTable]`` attribute. Required attribute: @@ -662,13 +672,13 @@ Optional attributes: - **inversedBy**: The inversedBy attribute designates the field in the entity that is the inverse side of the relationship. - **cascade**: Cascade Option -- **fetch**: One of LAZY, EXTRA_LAZY or EAGER +- **fetch**: One of ``LAZY``, ``EXTRA_LAZY`` or ``EAGER`` - **indexBy**: Index the collection by a field on the target entity. .. note:: - For ManyToMany bidirectional relationships either side may - be the owning side (the side that defines the @JoinTable and/or + For ``ManyToMany`` bidirectional relationships either side may + be the owning side (the side that defines the ``#[JoinTable]`` and/or does not make use of the mappedBy attribute, thus using a default join table). @@ -703,8 +713,8 @@ persistent entity state and mapping information for its subclasses, but which is not itself an entity. This attribute is specified on the Class level and has no additional settings. -The #[MappedSuperclass] attribute cannot be used in conjunction with -#[Entity]. See the Inheritance Mapping section for +The ``#[MappedSuperclass]`` attribute cannot be used in conjunction with +``#[Entity]``. See the Inheritance Mapping section for :doc:`more details on the restrictions of mapped superclasses `. Optional attributes: @@ -737,7 +747,7 @@ Example: #[OneToOne] ~~~~~~~~~~~ -The #[OneToOne] attribute works almost exactly as the +The ``#[OneToOne]`` attribute works almost exactly as the :ref:`#[ManyToOne] ` with one additional option which can be specified. When no :ref:`#[JoinColumn] ` is specified it defaults to using the target entity table and @@ -825,8 +835,8 @@ Example: #[OrderBy(["name" => "ASC"])] private $groups; -The key in OrderBy is only allowed to consist of -unqualified, unquoted field names and of an optional ASC/DESC +The key in ``OrderBy`` is only allowed to consist of +unqualified, unquoted field names and of an optional ``ASC``/``DESC`` positional statement. Multiple Fields are separated by a comma (,). The referenced field names have to exist on the ``targetEntity`` class of the ``#[ManyToMany]`` or ``#[OneToMany]`` attribute. @@ -1020,4 +1030,3 @@ Example: #[Column(type: "integer")] #[Version] protected $version; - From 1b6d8db45af212f3d31a2f05f83436c4cf865ff3 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Mon, 22 Mar 2021 22:31:30 +0100 Subject: [PATCH 37/37] Rename AttributesDriver to AttributeDriver --- docs/en/reference/advanced-configuration.rst | 3 ++- docs/en/reference/metadata-drivers.rst | 1 + .../Driver/{AttributesDriver.php => AttributeDriver.php} | 2 +- lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php | 5 ++++- tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php | 4 ++-- 5 files changed, 10 insertions(+), 5 deletions(-) rename lib/Doctrine/ORM/Mapping/Driver/{AttributesDriver.php => AttributeDriver.php} (99%) diff --git a/docs/en/reference/advanced-configuration.rst b/docs/en/reference/advanced-configuration.rst index 22464fe8932..ed971669404 100644 --- a/docs/en/reference/advanced-configuration.rst +++ b/docs/en/reference/advanced-configuration.rst @@ -101,10 +101,11 @@ Gets or sets the metadata driver implementation that is used by Doctrine to acquire the object-relational metadata for your classes. -There are currently 4 available implementations: +There are currently 5 available implementations: - ``Doctrine\ORM\Mapping\Driver\AnnotationDriver`` +- ``Doctrine\ORM\Mapping\Driver\AttributeDriver`` - ``Doctrine\ORM\Mapping\Driver\XmlDriver`` - ``Doctrine\ORM\Mapping\Driver\YamlDriver`` - ``Doctrine\ORM\Mapping\Driver\DriverChain`` diff --git a/docs/en/reference/metadata-drivers.rst b/docs/en/reference/metadata-drivers.rst index f28c6fa65ec..6e52506f5f8 100644 --- a/docs/en/reference/metadata-drivers.rst +++ b/docs/en/reference/metadata-drivers.rst @@ -14,6 +14,7 @@ metadata: - **XML files** (XmlDriver) - **Class DocBlock Annotations** (AnnotationDriver) +- **Attributes** (AttributeDriver) - **YAML files** (YamlDriver) - **PHP Code in files or static functions** (PhpDriver) diff --git a/lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php b/lib/Doctrine/ORM/Mapping/Driver/AttributeDriver.php similarity index 99% rename from lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php rename to lib/Doctrine/ORM/Mapping/Driver/AttributeDriver.php index f939bf814e0..5665d618812 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AttributesDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AttributeDriver.php @@ -20,7 +20,7 @@ use function constant; use function defined; -class AttributesDriver extends AnnotationDriver +class AttributeDriver extends AnnotationDriver { /** @var array */ // @phpcs:ignore diff --git a/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php b/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php index 31c107e2bcb..7ed1d3b825f 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php @@ -14,7 +14,10 @@ use function count; use function is_subclass_of; -class AttributeReader +/** + * @internal + */ +final class AttributeReader { /** @var array */ private array $isRepeatableAttribute = []; diff --git a/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php index 22a12355917..b0088a04a90 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/AttributeDriverTest.php @@ -4,7 +4,7 @@ namespace Doctrine\Tests\ORM\Mapping; -use Doctrine\ORM\Mapping\Driver\AttributesDriver; +use Doctrine\ORM\Mapping\Driver\AttributeDriver; use Doctrine\Persistence\Mapping\Driver\MappingDriver; use const PHP_VERSION_ID; @@ -23,7 +23,7 @@ protected function loadDriver(): MappingDriver { $paths = []; - return new AttributesDriver($paths); + return new AttributeDriver($paths); } public function testNamedQuery(): void