1
0
mirror of synced 2025-02-02 21:41:45 +03:00

Merge branch 'feature/#6593-#5864-export-metadata-should-contain-entity-listeners'

Close #6593
Close #5864
ge aborts
This commit is contained in:
Marco Pivetta 2017-08-16 19:58:23 +02:00
commit 76e2155fb3
No known key found for this signature in database
GPG Key ID: 4167D3337FD9D629
10 changed files with 261 additions and 66 deletions

View File

@ -604,18 +604,23 @@ public function __construct(<params>)
*/
protected function generateEntityNamespace(ClassMetadataInfo $metadata)
{
if ($this->hasNamespace($metadata)) {
return 'namespace ' . $this->getNamespace($metadata) .';';
if (! $this->hasNamespace($metadata)) {
return '';
}
return 'namespace ' . $this->getNamespace($metadata) .';';
}
/**
* @return string
*/
protected function generateEntityUse()
{
if ($this->generateAnnotations) {
return "\n".'use Doctrine\ORM\Mapping as ORM;'."\n";
} else {
return "";
if (! $this->generateAnnotations) {
return '';
}
return "\n".'use Doctrine\ORM\Mapping as ORM;'."\n";
}
/**
@ -738,9 +743,7 @@ public function __construct(<params>)
}
foreach ($fieldMappings as $fieldMapping) {
if (isset($fieldMapping['declaredField']) &&
isset($metadata->embeddedClasses[$fieldMapping['declaredField']])
) {
if (isset($fieldMapping['declaredField'], $metadata->embeddedClasses[$fieldMapping['declaredField']])) {
continue;
}
@ -911,6 +914,8 @@ public function __construct(<params>)
* @param ClassMetadataInfo $metadata
*
* @return array
*
* @throws \ReflectionException
*/
protected function getTraits(ClassMetadataInfo $metadata)
{
@ -918,9 +923,7 @@ public function __construct(<params>)
return [];
}
$reflClass = $metadata->reflClass === null
? new \ReflectionClass($metadata->name)
: $metadata->reflClass;
$reflClass = $metadata->reflClass ?? new \ReflectionClass($metadata->name);
$traits = [];
@ -1010,6 +1013,7 @@ public function __construct(<params>)
'generateDiscriminatorColumnAnnotation',
'generateDiscriminatorMapAnnotation',
'generateEntityAnnotation',
'generateEntityListenerAnnotation',
];
foreach ($methods as $method) {
@ -1113,9 +1117,11 @@ public function __construct(<params>)
*/
protected function generateInheritanceAnnotation(ClassMetadataInfo $metadata)
{
if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) {
return '@' . $this->annotationsPrefix . 'InheritanceType("'.$this->getInheritanceTypeString($metadata->inheritanceType).'")';
if ($metadata->inheritanceType === ClassMetadataInfo::INHERITANCE_TYPE_NONE) {
return '';
}
return '@' . $this->annotationsPrefix . 'InheritanceType("'.$this->getInheritanceTypeString($metadata->inheritanceType).'")';
}
/**
@ -1125,14 +1131,16 @@ public function __construct(<params>)
*/
protected function generateDiscriminatorColumnAnnotation(ClassMetadataInfo $metadata)
{
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 '';
}
$discrColumn = $metadata->discriminatorColumn;
$columnDefinition = 'name="' . $discrColumn['name']
. '", type="' . $discrColumn['type']
. '", length=' . $discrColumn['length'];
return '@' . $this->annotationsPrefix . 'DiscriminatorColumn(' . $columnDefinition . ')';
}
/**
@ -1142,15 +1150,17 @@ public function __construct(<params>)
*/
protected function generateDiscriminatorMapAnnotation(ClassMetadataInfo $metadata)
{
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) . '})';
}
/**
@ -1163,18 +1173,14 @@ public function __construct(<params>)
$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;
@ -1307,12 +1313,9 @@ public function __construct(<params>)
$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;
}
@ -1413,6 +1416,7 @@ public function __construct(<params>)
if ($this->hasMethod($methodName, $metadata)) {
return '';
}
$this->staticReflection[$metadata->name]['methods'][] = $methodName;
$replacements = [
@ -1748,6 +1752,27 @@ public function __construct(<params>)
return implode("\n", $lines);
}
private function generateEntityListenerAnnotation(ClassMetadataInfo $metadata): string
{
if (0 === \count($metadata->entityListeners)) {
return '';
}
$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))
);
}
/**
* @param string $code
* @param int $num

View File

@ -59,7 +59,7 @@ class AnnotationExporter extends AbstractExporter
}
/**
* @param \Doctrine\ORM\Mapping\ClassMetadataInfo $metadata
* @param ClassMetadataInfo $metadata
*
* @return string
*/
@ -69,7 +69,7 @@ class AnnotationExporter extends AbstractExporter
}
/**
* @param \Doctrine\ORM\Tools\EntityGenerator $entityGenerator
* @param EntityGenerator $entityGenerator
*
* @return void
*/

View File

@ -82,6 +82,8 @@ class PhpExporter extends AbstractExporter
}
}
$lines = array_merge($lines, $this->processEntityListeners($metadata));
foreach ($metadata->fieldMappings as $fieldMapping) {
$lines[] = '$metadata->mapField(' . $this->_varExport($fieldMapping) . ');';
}
@ -177,4 +179,22 @@ class PhpExporter extends AbstractExporter
return $export;
}
private function processEntityListeners(ClassMetadataInfo $metadata) : array
{
$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;
}
}

View File

@ -20,6 +20,7 @@
namespace Doctrine\ORM\Tools\Export\Driver;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use SimpleXMLElement;
/**
* ClassMetadata exporter for Doctrine XML mapping files.
@ -40,10 +41,10 @@ class XmlExporter extends AbstractExporter
*/
public function exportClassMetadata(ClassMetadataInfo $metadata)
{
$xml = new \SimpleXmlElement("<?xml version=\"1.0\" encoding=\"utf-8\"?><doctrine-mapping ".
"xmlns=\"http://doctrine-project.org/schemas/orm/doctrine-mapping\" " .
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ".
"xsi:schemaLocation=\"http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd\" />");
$xml = new SimpleXmlElement('<?xml version="1.0" encoding="utf-8"?><doctrine-mapping ' .
'xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" ' .
'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' .
'xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd" />');
if ($metadata->isMappedSuperclass) {
$root = $xml->addChild('mapped-superclass');
@ -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;
}
}

View File

@ -214,6 +214,8 @@ class YamlExporter extends AbstractExporter
$array['lifecycleCallbacks'] = $metadata->lifecycleCallbacks;
}
$array = $this->processEntityListeners($metadata, $array);
return $this->yamlDump([$metadata->name => $array], 10);
}
@ -232,4 +234,32 @@ class YamlExporter extends AbstractExporter
{
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;
}
}

View File

@ -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 {}
}

View File

@ -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
{
}
}

View File

@ -1,7 +1,11 @@
<?php
use Doctrine\ORM\Events;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\Tests\ORM\Tools\Export;
use Doctrine\Tests\ORM\Tools\Export\AddressListener;
use Doctrine\Tests\ORM\Tools\Export\GroupListener;
use Doctrine\Tests\ORM\Tools\Export\UserListener;
$metadata->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');

View File

@ -77,6 +77,18 @@
</join-table>
</many-to-many>
<entity-listeners>
<entity-listener class="Doctrine\Tests\ORM\Tools\Export\UserListener">
<lifecycle-callback type="prePersist" method="customPrePersist" />
<lifecycle-callback type="postPersist" method="customPostPersist" />
</entity-listener>
<entity-listener class="Doctrine\Tests\ORM\Tools\Export\GroupListener">
<lifecycle-callback type="prePersist" method="prePersist" />
</entity-listener>
<entity-listener class="Doctrine\Tests\ORM\Tools\Export\AddressListener">
<lifecycle-callback type="postPersist" method="customPostPersist" />
</entity-listener>
</entity-listeners>
</entity>
</doctrine-mapping>

View File

@ -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]