diff --git a/lib/Doctrine/ORM/Tools/EntityGenerator.php b/lib/Doctrine/ORM/Tools/EntityGenerator.php index fafa51f3d..9a282fa6b 100644 --- a/lib/Doctrine/ORM/Tools/EntityGenerator.php +++ b/lib/Doctrine/ORM/Tools/EntityGenerator.php @@ -346,7 +346,7 @@ public function __construct() * * @return void */ - public function generate(array $metadatas, $outputDirectory) + public function generate(array $metadatas, $outputDirectory): void { foreach ($metadatas as $metadata) { $this->writeEntityClass($metadata, $outputDirectory); @@ -363,7 +363,7 @@ public function __construct() * * @throws \RuntimeException */ - public function writeEntityClass(ClassMetadataInfo $metadata, $outputDirectory) + public function writeEntityClass(ClassMetadataInfo $metadata, $outputDirectory): void { $path = $outputDirectory . '/' . str_replace('\\', DIRECTORY_SEPARATOR, $metadata->name) . $this->extension; $dir = dirname($path); @@ -404,7 +404,7 @@ public function __construct() * * @return string */ - public function generateEntityClass(ClassMetadataInfo $metadata) + public function generateEntityClass(ClassMetadataInfo $metadata): string { $placeHolders = [ '', @@ -435,7 +435,7 @@ public function __construct() * * @return string */ - public function generateUpdatedEntityClass(ClassMetadataInfo $metadata, $path) + public function generateUpdatedEntityClass(ClassMetadataInfo $metadata, $path): string { $currentCode = file_get_contents($path); @@ -453,7 +453,7 @@ public function __construct() * * @return void */ - public function setNumSpaces($numSpaces) + public function setNumSpaces($numSpaces): void { $this->spaces = str_repeat(' ', $numSpaces); $this->numSpaces = $numSpaces; @@ -466,7 +466,7 @@ public function __construct() * * @return void */ - public function setExtension($extension) + public function setExtension($extension): void { $this->extension = $extension; } @@ -478,7 +478,7 @@ public function __construct() * * @return void */ - public function setClassToExtend($classToExtend) + public function setClassToExtend($classToExtend): void { $this->classToExtend = $classToExtend; } @@ -490,7 +490,7 @@ public function __construct() * * @return void */ - public function setGenerateAnnotations($bool) + public function setGenerateAnnotations($bool): void { $this->generateAnnotations = $bool; } @@ -504,7 +504,7 @@ public function __construct() * * @throws \InvalidArgumentException */ - public function setFieldVisibility($visibility) + public function setFieldVisibility($visibility): void { if ($visibility !== static::FIELD_VISIBLE_PRIVATE && $visibility !== static::FIELD_VISIBLE_PROTECTED) { throw new \InvalidArgumentException('Invalid provided visibility (only private and protected are allowed): ' . $visibility); @@ -518,7 +518,7 @@ public function __construct() * * @param boolean $embeddablesImmutable */ - public function setEmbeddablesImmutable($embeddablesImmutable) + public function setEmbeddablesImmutable($embeddablesImmutable): void { $this->embeddablesImmutable = (boolean) $embeddablesImmutable; } @@ -530,7 +530,7 @@ public function __construct() * * @return void */ - public function setAnnotationPrefix($prefix) + public function setAnnotationPrefix($prefix): void { $this->annotationsPrefix = $prefix; } @@ -542,7 +542,7 @@ public function __construct() * * @return void */ - public function setUpdateEntityIfExists($bool) + public function setUpdateEntityIfExists($bool): void { $this->updateEntityIfExists = $bool; } @@ -554,7 +554,7 @@ public function __construct() * * @return void */ - public function setRegenerateEntityIfExists($bool) + public function setRegenerateEntityIfExists($bool): void { $this->regenerateEntityIfExists = $bool; } @@ -566,7 +566,7 @@ public function __construct() * * @return void */ - public function setGenerateStubMethods($bool) + public function setGenerateStubMethods($bool): void { $this->generateEntityStubMethods = $bool; } @@ -578,7 +578,7 @@ public function __construct() * * @return void */ - public function setBackupExisting($bool) + public function setBackupExisting($bool): void { $this->backupExisting = $bool; } @@ -588,7 +588,7 @@ public function __construct() * * @return string */ - protected function getType($type) + protected function getType($type): string { if (isset($this->typeAlias[$type])) { return $this->typeAlias[$type]; @@ -602,20 +602,22 @@ public function __construct() * * @return string */ - protected function generateEntityNamespace(ClassMetadataInfo $metadata) + protected function generateEntityNamespace(ClassMetadataInfo $metadata): ?string { - if ($this->hasNamespace($metadata)) { - return 'namespace ' . $this->getNamespace($metadata) .';'; + if (!$this->hasNamespace($metadata)) { + return null; } + + return 'namespace ' . $this->getNamespace($metadata) .';'; } - protected function generateEntityUse() + protected function generateEntityUse(): ?string { - if ($this->generateAnnotations) { - return "\n".'use Doctrine\ORM\Mapping as ORM;'."\n"; - } else { - return ""; + if (!$this->generateAnnotations) { + return null; } + + return "\n".'use Doctrine\ORM\Mapping as ORM;'."\n"; } /** @@ -623,7 +625,7 @@ public function __construct() * * @return string */ - protected function generateEntityClassName(ClassMetadataInfo $metadata) + protected function generateEntityClassName(ClassMetadataInfo $metadata): string { return 'class ' . $this->getClassName($metadata) . ($this->extendsClass() ? ' extends ' . $this->getClassToExtendName() : null); @@ -634,7 +636,7 @@ public function __construct() * * @return string */ - protected function generateEntityBody(ClassMetadataInfo $metadata) + protected function generateEntityBody(ClassMetadataInfo $metadata): string { $fieldMappingProperties = $this->generateEntityFieldMappingProperties($metadata); $embeddedProperties = $this->generateEntityEmbeddedProperties($metadata); @@ -674,7 +676,7 @@ public function __construct() * * @return string */ - protected function generateEntityConstructor(ClassMetadataInfo $metadata) + protected function generateEntityConstructor(ClassMetadataInfo $metadata): string { if ($this->hasMethod('__construct', $metadata)) { return ''; @@ -704,7 +706,7 @@ public function __construct() * * @return string */ - private function generateEmbeddableConstructor(ClassMetadataInfo $metadata) + private function generateEmbeddableConstructor(ClassMetadataInfo $metadata): string { $paramTypes = []; $paramVariables = []; @@ -738,9 +740,7 @@ public function __construct() } foreach ($fieldMappings as $fieldMapping) { - if (isset($fieldMapping['declaredField']) && - isset($metadata->embeddedClasses[$fieldMapping['declaredField']]) - ) { + if (isset($fieldMapping['declaredField'], $metadata->embeddedClasses[$fieldMapping['declaredField']])) { continue; } @@ -800,7 +800,7 @@ public function __construct() * * @return void */ - protected function parseTokensInEntityFile($src) + protected function parseTokensInEntityFile($src): void { $tokens = token_get_all($src); $tokensCount = count($tokens); @@ -848,13 +848,7 @@ public function __construct() } } - /** - * @param string $property - * @param ClassMetadataInfo $metadata - * - * @return bool - */ - protected function hasProperty($property, ClassMetadataInfo $metadata) + protected function hasProperty(string $property, ClassMetadataInfo $metadata): bool { if ($this->extendsClass() || (!$this->isNew && class_exists($metadata->name))) { // don't generate property if its already on the base class. @@ -877,13 +871,7 @@ public function __construct() ); } - /** - * @param string $method - * @param ClassMetadataInfo $metadata - * - * @return bool - */ - protected function hasMethod($method, ClassMetadataInfo $metadata) + protected function hasMethod(string $method, ClassMetadataInfo $metadata): bool { if ($this->extendsClass() || (!$this->isNew && class_exists($metadata->name))) { // don't generate method if its already on the base class. @@ -907,20 +895,13 @@ public function __construct() ); } - /** - * @param ClassMetadataInfo $metadata - * - * @return array - */ - protected function getTraits(ClassMetadataInfo $metadata) + protected function getTraits(ClassMetadataInfo $metadata): array { if (! ($metadata->reflClass !== null || class_exists($metadata->name))) { return []; } - $reflClass = $metadata->reflClass === null - ? new \ReflectionClass($metadata->name) - : $metadata->reflClass; + $reflClass = $metadata->reflClass ?? new \ReflectionClass($metadata->name); $traits = []; @@ -933,69 +914,40 @@ public function __construct() return $traits; } - /** - * @param ClassMetadataInfo $metadata - * - * @return bool - */ - protected function hasNamespace(ClassMetadataInfo $metadata) + protected function hasNamespace(ClassMetadataInfo $metadata): bool { return (bool) strpos($metadata->name, '\\'); } - /** - * @return bool - */ - protected function extendsClass() + protected function extendsClass(): bool { return (bool) $this->classToExtend; } - /** - * @return string - */ - protected function getClassToExtend() + protected function getClassToExtend(): ?string { return $this->classToExtend; } - /** - * @return string - */ - protected function getClassToExtendName() + protected function getClassToExtendName(): string { $refl = new \ReflectionClass($this->getClassToExtend()); return '\\' . $refl->getName(); } - /** - * @param ClassMetadataInfo $metadata - * - * @return string - */ - protected function getClassName(ClassMetadataInfo $metadata) + protected function getClassName(ClassMetadataInfo $metadata): string { return ($pos = strrpos($metadata->name, '\\')) ? substr($metadata->name, $pos + 1, strlen($metadata->name)) : $metadata->name; } - /** - * @param ClassMetadataInfo $metadata - * - * @return string - */ - protected function getNamespace(ClassMetadataInfo $metadata) + protected function getNamespace(ClassMetadataInfo $metadata): string { return substr($metadata->name, 0, strrpos($metadata->name, '\\')); } - /** - * @param ClassMetadataInfo $metadata - * - * @return string - */ - protected function generateEntityDocBlock(ClassMetadataInfo $metadata) + protected function generateEntityDocBlock(ClassMetadataInfo $metadata): string { $lines = []; $lines[] = '/**'; @@ -1010,6 +962,7 @@ public function __construct() 'generateDiscriminatorColumnAnnotation', 'generateDiscriminatorMapAnnotation', 'generateEntityAnnotation', + 'generateEntityListenerAnnotation', ]; foreach ($methods as $method) { @@ -1028,12 +981,7 @@ public function __construct() return implode("\n", $lines); } - /** - * @param ClassMetadataInfo $metadata - * - * @return string - */ - protected function generateEntityAnnotation(ClassMetadataInfo $metadata) + protected function generateEntityAnnotation(ClassMetadataInfo $metadata): string { $prefix = '@' . $this->annotationsPrefix; @@ -1048,12 +996,7 @@ public function __construct() return $prefix . ($metadata->isMappedSuperclass ? 'MappedSuperclass' : 'Entity') . $customRepository; } - /** - * @param ClassMetadataInfo $metadata - * - * @return string - */ - protected function generateTableAnnotation(ClassMetadataInfo $metadata) + protected function generateTableAnnotation(ClassMetadataInfo $metadata): string { if ($metadata->isEmbeddedClass) { return ''; @@ -1086,13 +1029,7 @@ public function __construct() return '@' . $this->annotationsPrefix . 'Table(' . implode(', ', $table) . ')'; } - /** - * @param string $constraintName - * @param array $constraints - * - * @return string - */ - protected function generateTableConstraints($constraintName, array $constraints) + protected function generateTableConstraints(string $constraintName, array $constraints): string { $annotations = []; foreach ($constraints as $name => $constraint) { @@ -1106,75 +1043,57 @@ public function __construct() return implode(', ', $annotations); } - /** - * @param ClassMetadataInfo $metadata - * - * @return string - */ - protected function generateInheritanceAnnotation(ClassMetadataInfo $metadata) + protected function generateInheritanceAnnotation(ClassMetadataInfo $metadata): ?string { - if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) { - return '@' . $this->annotationsPrefix . 'InheritanceType("'.$this->getInheritanceTypeString($metadata->inheritanceType).'")'; + if ($metadata->inheritanceType === ClassMetadataInfo::INHERITANCE_TYPE_NONE) { + return null; } + + return '@' . $this->annotationsPrefix . 'InheritanceType("'.$this->getInheritanceTypeString($metadata->inheritanceType).'")'; } - /** - * @param ClassMetadataInfo $metadata - * - * @return string - */ - protected function generateDiscriminatorColumnAnnotation(ClassMetadataInfo $metadata) + protected function generateDiscriminatorColumnAnnotation(ClassMetadataInfo $metadata): ?string { - if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) { - $discrColumn = $metadata->discriminatorColumn; - $columnDefinition = 'name="' . $discrColumn['name'] - . '", type="' . $discrColumn['type'] - . '", length=' . $discrColumn['length']; - - return '@' . $this->annotationsPrefix . 'DiscriminatorColumn(' . $columnDefinition . ')'; + if ($metadata->inheritanceType === ClassMetadataInfo::INHERITANCE_TYPE_NONE) { + return null; } + + $discrColumn = $metadata->discriminatorColumn; + $columnDefinition = 'name="' . $discrColumn['name'] + . '", type="' . $discrColumn['type'] + . '", length=' . $discrColumn['length']; + + return '@' . $this->annotationsPrefix . 'DiscriminatorColumn(' . $columnDefinition . ')'; } - /** - * @param ClassMetadataInfo $metadata - * - * @return string - */ - protected function generateDiscriminatorMapAnnotation(ClassMetadataInfo $metadata) + protected function generateDiscriminatorMapAnnotation(ClassMetadataInfo $metadata): ?string { - if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) { - $inheritanceClassMap = []; - - foreach ($metadata->discriminatorMap as $type => $class) { - $inheritanceClassMap[] .= '"' . $type . '" = "' . $class . '"'; - } - - return '@' . $this->annotationsPrefix . 'DiscriminatorMap({' . implode(', ', $inheritanceClassMap) . '})'; + if ($metadata->inheritanceType === ClassMetadataInfo::INHERITANCE_TYPE_NONE) { + return null; } + + $inheritanceClassMap = []; + + foreach ($metadata->discriminatorMap as $type => $class) { + $inheritanceClassMap[] .= '"' . $type . '" = "' . $class . '"'; + } + + return '@' . $this->annotationsPrefix . 'DiscriminatorMap({' . implode(', ', $inheritanceClassMap) . '})'; } - /** - * @param ClassMetadataInfo $metadata - * - * @return string - */ - protected function generateEntityStubMethods(ClassMetadataInfo $metadata) + protected function generateEntityStubMethods(ClassMetadataInfo $metadata): string { $methods = []; foreach ($metadata->fieldMappings as $fieldMapping) { - if (isset($fieldMapping['declaredField']) && - isset($metadata->embeddedClasses[$fieldMapping['declaredField']]) - ) { + if (isset($fieldMapping['declaredField'], $metadata->embeddedClasses[$fieldMapping['declaredField']])) { continue; } $nullableField = $this->nullableFieldExpression($fieldMapping); - if (( ! isset($fieldMapping['id']) || - ! $fieldMapping['id'] || - $metadata->generatorType == ClassMetadataInfo::GENERATOR_TYPE_NONE - ) && (! $metadata->isEmbeddedClass || ! $this->embeddablesImmutable) + if ((!$metadata->isEmbeddedClass || !$this->embeddablesImmutable) + && (!isset($fieldMapping['id']) || ! $fieldMapping['id'] || $metadata->generatorType === ClassMetadataInfo::GENERATOR_TYPE_NONE) && $code = $this->generateEntityStubMethod($metadata, 'set', $fieldMapping['fieldName'], $fieldMapping['type'], $nullableField) ) { $methods[] = $code; @@ -1226,12 +1145,7 @@ public function __construct() return implode("\n\n", $methods); } - /** - * @param array $associationMapping - * - * @return bool - */ - protected function isAssociationIsNullable(array $associationMapping) + protected function isAssociationIsNullable(array $associationMapping): bool { if (isset($associationMapping['id']) && $associationMapping['id']) { return false; @@ -1253,15 +1167,10 @@ public function __construct() return true; } - /** - * @param ClassMetadataInfo $metadata - * - * @return string - */ - protected function generateEntityLifecycleCallbackMethods(ClassMetadataInfo $metadata) + protected function generateEntityLifecycleCallbackMethods(ClassMetadataInfo $metadata): ?string { if (empty($metadata->lifecycleCallbacks)) { - return ''; + return null; } $methods = []; @@ -1275,12 +1184,7 @@ public function __construct() return implode("\n\n", array_filter($methods)); } - /** - * @param ClassMetadataInfo $metadata - * - * @return string - */ - protected function generateEntityAssociationMappingProperties(ClassMetadataInfo $metadata) + protected function generateEntityAssociationMappingProperties(ClassMetadataInfo $metadata): string { $lines = []; @@ -1297,22 +1201,14 @@ public function __construct() return implode("\n", $lines); } - /** - * @param ClassMetadataInfo $metadata - * - * @return string - */ - protected function generateEntityFieldMappingProperties(ClassMetadataInfo $metadata) + protected function generateEntityFieldMappingProperties(ClassMetadataInfo $metadata): string { $lines = []; foreach ($metadata->fieldMappings as $fieldMapping) { - if ($this->hasProperty($fieldMapping['fieldName'], $metadata) || - $metadata->isInheritedField($fieldMapping['fieldName']) || - ( - isset($fieldMapping['declaredField']) && - isset($metadata->embeddedClasses[$fieldMapping['declaredField']]) - ) + if (isset($fieldMapping['declaredField'], $metadata->embeddedClasses[$fieldMapping['declaredField']]) || + $this->hasProperty($fieldMapping['fieldName'], $metadata) || + $metadata->isInheritedField($fieldMapping['fieldName']) ) { continue; } @@ -1325,12 +1221,7 @@ public function __construct() return implode("\n", $lines); } - /** - * @param ClassMetadataInfo $metadata - * - * @return string - */ - protected function generateEntityEmbeddedProperties(ClassMetadataInfo $metadata) + protected function generateEntityEmbeddedProperties(ClassMetadataInfo $metadata): string { $lines = []; @@ -1346,16 +1237,12 @@ public function __construct() return implode("\n", $lines); } - /** - * @param ClassMetadataInfo $metadata - * @param string $type - * @param string $fieldName - * @param string|null $typeHint - * @param string|null $defaultValue - * - * @return string - */ - protected function generateEntityStubMethod(ClassMetadataInfo $metadata, $type, $fieldName, $typeHint = null, $defaultValue = null) + protected function generateEntityStubMethod( + ClassMetadataInfo $metadata, + string $type, + string $fieldName, + ?string $typeHint = null, + ?string $defaultValue = null): string { $methodName = $type . Inflector::classify($fieldName); $variableName = Inflector::camelize($fieldName); @@ -1401,18 +1288,12 @@ public function __construct() return $this->prefixCodeWithSpaces($method); } - /** - * @param string $name - * @param string $methodName - * @param ClassMetadataInfo $metadata - * - * @return string - */ - protected function generateLifecycleCallbackMethod($name, $methodName, ClassMetadataInfo $metadata) + protected function generateLifecycleCallbackMethod(string $name, string $methodName, ClassMetadataInfo $metadata): ?string { if ($this->hasMethod($methodName, $metadata)) { - return ''; + return null; } + $this->staticReflection[$metadata->name]['methods'][] = $methodName; $replacements = [ @@ -1429,12 +1310,7 @@ public function __construct() return $this->prefixCodeWithSpaces($method); } - /** - * @param array $joinColumn - * - * @return string - */ - protected function generateJoinColumnAnnotation(array $joinColumn) + protected function generateJoinColumnAnnotation(array $joinColumn): string { $joinColumnAnnot = []; @@ -1465,13 +1341,7 @@ public function __construct() return '@' . $this->annotationsPrefix . 'JoinColumn(' . implode(', ', $joinColumnAnnot) . ')'; } - /** - * @param array $associationMapping - * @param ClassMetadataInfo $metadata - * - * @return string - */ - protected function generateAssociationMappingPropertyDocBlock(array $associationMapping, ClassMetadataInfo $metadata) + protected function generateAssociationMappingPropertyDocBlock(array $associationMapping, ClassMetadataInfo $metadata): string { $lines = []; $lines[] = $this->spaces . '/**'; @@ -1617,13 +1487,7 @@ public function __construct() return implode("\n", $lines); } - /** - * @param array $fieldMapping - * @param ClassMetadataInfo $metadata - * - * @return string - */ - protected function generateFieldMappingPropertyDocBlock(array $fieldMapping, ClassMetadataInfo $metadata) + protected function generateFieldMappingPropertyDocBlock(array $fieldMapping, ClassMetadataInfo $metadata): string { $lines = []; $lines[] = $this->spaces . '/**'; @@ -1715,12 +1579,7 @@ public function __construct() return implode("\n", $lines); } - /** - * @param array $embeddedClass - * - * @return string - */ - protected function generateEmbeddedPropertyDocBlock(array $embeddedClass) + protected function generateEmbeddedPropertyDocBlock(array $embeddedClass): string { $lines = []; $lines[] = $this->spaces . '/**'; @@ -1748,13 +1607,28 @@ public function __construct() return implode("\n", $lines); } - /** - * @param string $code - * @param int $num - * - * @return string - */ - protected function prefixCodeWithSpaces($code, $num = 1) + protected function generateEntityListenerAnnotation(ClassMetadataInfo $metadata): ?string + { + if (0 === \count($metadata->entityListeners)) { + return null; + } + + $processedClasses = []; + foreach ($metadata->entityListeners as $event => $eventListeners) { + foreach ($eventListeners as $eventListener) { + $processedClasses[] = '"' . $eventListener['class'] . '"'; + } + } + + return \sprintf( + '%s%s({%s})', + '@' . $this->annotationsPrefix, + 'EntityListeners', + \implode(',', \array_unique($processedClasses)) + ); + } + + protected function prefixCodeWithSpaces($code, $num = 1): string { $lines = explode("\n", $code); @@ -1774,7 +1648,7 @@ public function __construct() * * @throws \InvalidArgumentException When the inheritance type does not exist. */ - protected function getInheritanceTypeString($type) + protected function getInheritanceTypeString($type): string { if ( ! isset(static::$inheritanceTypeMap[$type])) { throw new \InvalidArgumentException(sprintf('Invalid provided InheritanceType: %s', $type)); @@ -1790,7 +1664,7 @@ public function __construct() * * @throws \InvalidArgumentException When the change-tracking type does not exist. */ - protected function getChangeTrackingPolicyString($type) + protected function getChangeTrackingPolicyString($type): string { if ( ! isset(static::$changeTrackingPolicyMap[$type])) { throw new \InvalidArgumentException(sprintf('Invalid provided ChangeTrackingPolicy: %s', $type)); @@ -1806,7 +1680,7 @@ public function __construct() * * @throws \InvalidArgumentException When the generator type does not exist. */ - protected function getIdGeneratorTypeString($type) + protected function getIdGeneratorTypeString($type): string { if ( ! isset(static::$generatorStrategyMap[$type])) { throw new \InvalidArgumentException(sprintf('Invalid provided IdGeneratorType: %s', $type)); @@ -1815,12 +1689,7 @@ public function __construct() return static::$generatorStrategyMap[$type]; } - /** - * @param array $fieldMapping - * - * @return string|null - */ - private function nullableFieldExpression(array $fieldMapping) + private function nullableFieldExpression(array $fieldMapping): ?string { if (isset($fieldMapping['nullable']) && true === $fieldMapping['nullable']) { return 'null'; @@ -1836,7 +1705,7 @@ public function __construct() * * @return string */ - private function exportTableOptions(array $options) + private function exportTableOptions(array $options): string { $optionsStr = []; diff --git a/lib/Doctrine/ORM/Tools/Export/Driver/AnnotationExporter.php b/lib/Doctrine/ORM/Tools/Export/Driver/AnnotationExporter.php index 044a1da53..43d120161 100644 --- a/lib/Doctrine/ORM/Tools/Export/Driver/AnnotationExporter.php +++ b/lib/Doctrine/ORM/Tools/Export/Driver/AnnotationExporter.php @@ -44,7 +44,7 @@ class AnnotationExporter extends AbstractExporter /** * {@inheritdoc} */ - public function exportClassMetadata(ClassMetadataInfo $metadata) + public function exportClassMetadata(ClassMetadataInfo $metadata): string { if ( ! $this->_entityGenerator) { throw new \RuntimeException('For the AnnotationExporter you must set an EntityGenerator instance with the setEntityGenerator() method.'); @@ -63,7 +63,7 @@ class AnnotationExporter extends AbstractExporter * * @return string */ - protected function _generateOutputPath(ClassMetadataInfo $metadata) + protected function _generateOutputPath(ClassMetadataInfo $metadata): string { return $this->_outputDir . '/' . str_replace('\\', '/', $metadata->name) . $this->_extension; } @@ -73,7 +73,7 @@ class AnnotationExporter extends AbstractExporter * * @return void */ - public function setEntityGenerator(EntityGenerator $entityGenerator) + public function setEntityGenerator(EntityGenerator $entityGenerator): void { $this->_entityGenerator = $entityGenerator; } diff --git a/lib/Doctrine/ORM/Tools/Export/Driver/PhpExporter.php b/lib/Doctrine/ORM/Tools/Export/Driver/PhpExporter.php index 69db59f78..5054743aa 100644 --- a/lib/Doctrine/ORM/Tools/Export/Driver/PhpExporter.php +++ b/lib/Doctrine/ORM/Tools/Export/Driver/PhpExporter.php @@ -38,7 +38,7 @@ class PhpExporter extends AbstractExporter /** * {@inheritdoc} */ - public function exportClassMetadata(ClassMetadataInfo $metadata) + public function exportClassMetadata(ClassMetadataInfo $metadata): string { $lines = []; $lines[] = 'processEntityListeners($metadata)); + foreach ($metadata->fieldMappings as $fieldMapping) { $lines[] = '$metadata->mapField(' . $this->_varExport($fieldMapping) . ');'; } @@ -164,7 +166,7 @@ class PhpExporter extends AbstractExporter * * @return string */ - protected function _varExport($var) + protected function _varExport($var): string { $export = var_export($var, true); $export = str_replace("\n", PHP_EOL . str_repeat(' ', 8), $export); @@ -177,4 +179,26 @@ class PhpExporter extends AbstractExporter return $export; } + + private function processEntityListeners(ClassMetadataInfo $metadata): array + { + $lines = []; + + if (0 === \count($metadata->entityListeners)) { + return $lines; + } + + foreach ($metadata->entityListeners as $event => $entityListenerConfig) { + foreach ($entityListenerConfig as $entityListener) { + $lines[] = sprintf( + '$metadata->addEntityListener(%s, %s, %s);', + var_export($event, true), + var_export($entityListener['class'], true), + var_export($entityListener['method'], true) + ); + } + } + + return $lines; + } } diff --git a/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php b/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php index c4eb8f637..fb45516eb 100644 --- a/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php +++ b/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php @@ -20,6 +20,7 @@ namespace Doctrine\ORM\Tools\Export\Driver; use Doctrine\ORM\Mapping\ClassMetadataInfo; +use SimpleXMLElement; /** * ClassMetadata exporter for Doctrine XML mapping files. @@ -38,9 +39,9 @@ class XmlExporter extends AbstractExporter /** * {@inheritdoc} */ - public function exportClassMetadata(ClassMetadataInfo $metadata) + public function exportClassMetadata(ClassMetadataInfo $metadata): string { - $xml = new \SimpleXmlElement(""); @@ -390,16 +391,18 @@ class XmlExporter extends AbstractExporter } } + $this->processEntityListeners($metadata, $root); + return $this->_asXml($xml); } /** * Exports (nested) option elements. * - * @param \SimpleXMLElement $parentXml - * @param array $options + * @param SimpleXMLElement $parentXml + * @param array $options */ - private function exportTableOptions(\SimpleXMLElement $parentXml, array $options) + private function exportTableOptions(SimpleXMLElement $parentXml, array $options): void { foreach ($options as $name => $option) { $isArray = is_array($option); @@ -418,12 +421,12 @@ class XmlExporter extends AbstractExporter /** * Export sequence information (if available/configured) into the current identifier XML node * - * @param \SimpleXMLElement $identifierXmlNode + * @param SimpleXMLElement $identifierXmlNode * @param ClassMetadataInfo $metadata * * @return void */ - private function exportSequenceInformation(\SimpleXMLElement $identifierXmlNode, ClassMetadataInfo $metadata) + private function exportSequenceInformation(SimpleXMLElement $identifierXmlNode, ClassMetadataInfo $metadata): void { $sequenceDefinition = $metadata->sequenceGeneratorDefinition; @@ -438,12 +441,7 @@ class XmlExporter extends AbstractExporter $sequenceGeneratorXml->addAttribute('initial-value', $sequenceDefinition['initialValue']); } - /** - * @param \SimpleXMLElement $simpleXml - * - * @return string $xml - */ - private function _asXml($simpleXml) + private function _asXml(SimpleXMLElement $simpleXml): string { $dom = new \DOMDocument('1.0', 'UTF-8'); $dom->loadXML($simpleXml->asXML()); @@ -451,4 +449,46 @@ class XmlExporter extends AbstractExporter return $dom->saveXML(); } + + private function processEntityListeners(ClassMetadataInfo $metadata, SimpleXMLElement $root): void + { + if (0 === \count($metadata->entityListeners)) { + return; + } + + $entityListenersXml = $root->addChild('entity-listeners'); + $entityListenersXmlMap = []; + + $this->generateEntityListenerXml($metadata, $entityListenersXmlMap, $entityListenersXml); + } + + private function generateEntityListenerXml(ClassMetadataInfo $metadata, array $entityListenersXmlMap, SimpleXMLElement $entityListenersXml): void + { + foreach ($metadata->entityListeners as $event => $entityListenerConfig) { + foreach ($entityListenerConfig as $entityListener) { + $entityListenerXml = $this->addClassToMapIfExists( + $entityListenersXmlMap, + $entityListener, + $entityListenersXml + ); + + $entityListenerCallbackXml = $entityListenerXml->addChild('lifecycle-callback'); + $entityListenerCallbackXml->addAttribute('type', $event); + $entityListenerCallbackXml->addAttribute('method', $entityListener['method']); + } + } + } + + private function addClassToMapIfExists(array $entityListenersXmlMap, array $entityListener, SimpleXMLElement $entityListenersXml): SimpleXMLElement + { + if (isset($entityListenersXmlMap[$entityListener['class']])) { + return $entityListenersXmlMap[$entityListener['class']]; + } + + $entityListenerXml = $entityListenersXml->addChild('entity-listener'); + $entityListenerXml->addAttribute('class', $entityListener['class']); + $entityListenersXmlMap[$entityListener['class']] = $entityListenerXml; + + return $entityListenerXml; + } } diff --git a/lib/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php b/lib/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php index b9a38f904..053ad5897 100644 --- a/lib/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php +++ b/lib/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php @@ -39,7 +39,7 @@ class YamlExporter extends AbstractExporter /** * {@inheritdoc} */ - public function exportClassMetadata(ClassMetadataInfo $metadata) + public function exportClassMetadata(ClassMetadataInfo $metadata): string { $array = []; @@ -214,6 +214,8 @@ class YamlExporter extends AbstractExporter $array['lifecycleCallbacks'] = $metadata->lifecycleCallbacks; } + $array = $this->processEntityListeners($metadata, $array); + return $this->yamlDump([$metadata->name => $array], 10); } @@ -228,8 +230,35 @@ class YamlExporter extends AbstractExporter * * @return string A YAML string representing the original PHP array */ - protected function yamlDump($array, $inline = 2) + protected function yamlDump($array, $inline = 2): string { return Yaml::dump($array, $inline); } + + private function processEntityListeners(ClassMetadataInfo $metadata, array $array): array + { + if (0 === \count($metadata->entityListeners)) { + return $array; + } + + $array['entityListeners'] = []; + + foreach ($metadata->entityListeners as $event => $entityListenerConfig) { + $array = $this->processEntityListenerConfig($array, $entityListenerConfig, $event); + } + + return $array; + } + + private function processEntityListenerConfig(array $array, array $entityListenerConfig, string $event): array + { + foreach ($entityListenerConfig as $entityListener) { + if (!isset($array['entityListeners'][$entityListener['class']])) { + $array['entityListeners'][$entityListener['class']] = []; + } + $array['entityListeners'][$entityListener['class']][$event] = [$entityListener['method']]; + } + + return $array; + } } diff --git a/tests/Doctrine/Tests/ORM/Tools/Export/AbstractClassMetadataExporterTest.php b/tests/Doctrine/Tests/ORM/Tools/Export/AbstractClassMetadataExporterTest.php index e9523b5b1..a74af72a1 100644 --- a/tests/Doctrine/Tests/ORM/Tools/Export/AbstractClassMetadataExporterTest.php +++ b/tests/Doctrine/Tests/ORM/Tools/Export/AbstractClassMetadataExporterTest.php @@ -5,6 +5,8 @@ namespace Doctrine\Tests\ORM\Tools\Export; use Doctrine\Common\EventManager; use Doctrine\Common\Persistence\Mapping\Driver\PHPDriver; use Doctrine\ORM\Configuration; +use Doctrine\ORM\Events; +use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadataFactory; use Doctrine\ORM\Mapping\ClassMetadataInfo; use Doctrine\ORM\Mapping\Driver\AnnotationDriver; @@ -344,7 +346,7 @@ abstract class AbstractClassMetadataExporterTest extends OrmTestCase { $this->assertEquals('user', $class->associationMappings['address']['inversedBy']); } - /** + /** * @depends testExportDirectoryAndFilesAreCreated */ public function testCascadeAllCollapsed() @@ -371,6 +373,26 @@ abstract class AbstractClassMetadataExporterTest extends OrmTestCase } } + /** + * @depends testExportedMetadataCanBeReadBackIn + * + * @param ClassMetadata $class + */ + public function testEntityListenersAreExported($class) + { + $this->assertNotEmpty($class->entityListeners); + $this->assertCount(2, $class->entityListeners[Events::prePersist]); + $this->assertCount(2, $class->entityListeners[Events::postPersist]); + $this->assertEquals(UserListener::class, $class->entityListeners[Events::prePersist][0]['class']); + $this->assertEquals('customPrePersist', $class->entityListeners[Events::prePersist][0]['method']); + $this->assertEquals(GroupListener::class, $class->entityListeners[Events::prePersist][1]['class']); + $this->assertEquals('prePersist', $class->entityListeners[Events::prePersist][1]['method']); + $this->assertEquals(UserListener::class, $class->entityListeners[Events::postPersist][0]['class']); + $this->assertEquals('customPostPersist', $class->entityListeners[Events::postPersist][0]['method']); + $this->assertEquals(AddressListener::class, $class->entityListeners[Events::postPersist][1]['class']); + $this->assertEquals('customPostPersist', $class->entityListeners[Events::postPersist][1]['method']); + } + public function __destruct() { # $this->_deleteDirectory(__DIR__ . '/export/'.$this->_getType()); @@ -406,3 +428,28 @@ class Group { } +class UserListener +{ + /** + * @\Doctrine\ORM\Mapping\PrePersist + */ + public function customPrePersist(): void {} + /** + * @\Doctrine\ORM\Mapping\PostPersist + */ + public function customPostPersist(): void {} +} +class GroupListener +{ + /** + * @\Doctrine\ORM\Mapping\PrePersist + */ + public function prePersist(): void {} +} +class AddressListener +{ + /** + * @\Doctrine\ORM\Mapping\PostPersist + */ + public function customPostPersist(): void {} +} diff --git a/tests/Doctrine/Tests/ORM/Tools/Export/annotation/Doctrine.Tests.ORM.Tools.Export.User.php b/tests/Doctrine/Tests/ORM/Tools/Export/annotation/Doctrine.Tests.ORM.Tools.Export.User.php index 344708059..c6a066258 100644 --- a/tests/Doctrine/Tests/ORM/Tools/Export/annotation/Doctrine.Tests.ORM.Tools.Export.User.php +++ b/tests/Doctrine/Tests/ORM/Tools/Export/annotation/Doctrine.Tests.ORM.Tools.Export.User.php @@ -5,6 +5,11 @@ namespace Doctrine\Tests\ORM\Tools\Export; /** * @Entity * @HasLifecycleCallbacks + * @EntityListeners({ + * Doctrine\Tests\ORM\Tools\Export\UserListener::class, + * Doctrine\Tests\ORM\Tools\Export\GroupListener::class, + * Doctrine\Tests\ORM\Tools\Export\AddressListener::class + * }) * @Table(name="cms_users",options={"engine"="MyISAM","foo"={"bar"="baz"}}) */ class User @@ -57,21 +62,21 @@ class User /** * @PrePersist */ - public function doStuffOnPrePersist() + public function doStuffOnPrePersist(): void { } /** * @PrePersist */ - public function doOtherStuffOnPrePersistToo() + public function doOtherStuffOnPrePersistToo(): void { } /** * @PostPersist */ - public function doStuffOnPostPersist() + public function doStuffOnPostPersist(): void { } } diff --git a/tests/Doctrine/Tests/ORM/Tools/Export/php/Doctrine.Tests.ORM.Tools.Export.User.php b/tests/Doctrine/Tests/ORM/Tools/Export/php/Doctrine.Tests.ORM.Tools.Export.User.php index 5c8a0c013..5e54c0b2e 100644 --- a/tests/Doctrine/Tests/ORM/Tools/Export/php/Doctrine.Tests.ORM.Tools.Export.User.php +++ b/tests/Doctrine/Tests/ORM/Tools/Export/php/Doctrine.Tests.ORM.Tools.Export.User.php @@ -1,7 +1,11 @@ setInheritanceType(ClassMetadataInfo::INHERITANCE_TYPE_NONE); $metadata->setPrimaryTable( @@ -11,9 +15,9 @@ $metadata->setPrimaryTable( ] ); $metadata->setChangeTrackingPolicy(ClassMetadataInfo::CHANGETRACKING_DEFERRED_IMPLICIT); -$metadata->addLifecycleCallback('doStuffOnPrePersist', 'prePersist'); -$metadata->addLifecycleCallback('doOtherStuffOnPrePersistToo', 'prePersist'); -$metadata->addLifecycleCallback('doStuffOnPostPersist', 'postPersist'); +$metadata->addLifecycleCallback('doStuffOnPrePersist', Events::prePersist); +$metadata->addLifecycleCallback('doOtherStuffOnPrePersistToo', Events::prePersist); +$metadata->addLifecycleCallback('doStuffOnPostPersist', Events::postPersist); $metadata->mapField( [ 'id' => true, @@ -149,3 +153,7 @@ $metadata->mapManyToMany( 'orderBy' => NULL, ] ); +$metadata->addEntityListener(Events::prePersist, UserListener::class, 'customPrePersist'); +$metadata->addEntityListener(Events::postPersist, UserListener::class, 'customPostPersist'); +$metadata->addEntityListener(Events::prePersist, GroupListener::class, 'prePersist'); +$metadata->addEntityListener(Events::postPersist, AddressListener::class, 'customPostPersist'); diff --git a/tests/Doctrine/Tests/ORM/Tools/Export/xml/Doctrine.Tests.ORM.Tools.Export.User.dcm.xml b/tests/Doctrine/Tests/ORM/Tools/Export/xml/Doctrine.Tests.ORM.Tools.Export.User.dcm.xml index 8d0c5d217..78bac4f5f 100644 --- a/tests/Doctrine/Tests/ORM/Tools/Export/xml/Doctrine.Tests.ORM.Tools.Export.User.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Tools/Export/xml/Doctrine.Tests.ORM.Tools.Export.User.dcm.xml @@ -77,6 +77,18 @@ + + + + + + + + + + + + diff --git a/tests/Doctrine/Tests/ORM/Tools/Export/yaml/Doctrine.Tests.ORM.Tools.Export.User.dcm.yml b/tests/Doctrine/Tests/ORM/Tools/Export/yaml/Doctrine.Tests.ORM.Tools.Export.User.dcm.yml index d52e94601..df2dae1c5 100644 --- a/tests/Doctrine/Tests/ORM/Tools/Export/yaml/Doctrine.Tests.ORM.Tools.Export.User.dcm.yml +++ b/tests/Doctrine/Tests/ORM/Tools/Export/yaml/Doctrine.Tests.ORM.Tools.Export.User.dcm.yml @@ -75,3 +75,11 @@ Doctrine\Tests\ORM\Tools\Export\User: lifecycleCallbacks: prePersist: [ doStuffOnPrePersist, doOtherStuffOnPrePersistToo ] postPersist: [ doStuffOnPostPersist ] + entityListeners: + Doctrine\Tests\ORM\Tools\Export\UserListener: + prePersist: [customPrePersist] + postPersist: [customPostPersist] + Doctrine\Tests\ORM\Tools\Export\GroupListener: + prePersist: [prePersist] + Doctrine\Tests\ORM\Tools\Export\AddressListener: + postPersist: [customPostPersist]