Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 5cad3b6

Browse filesBrowse files
bug #44987 [DoctrineBridge] [5.4] Fix automapping (mbabker)
This PR was merged into the 5.4 branch. Discussion ---------- [DoctrineBridge] [5.4] Fix automapping | Q | A | ------------- | --- | Branch? | 5.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Tickets | Fix #44355 | License | MIT | Doc PR | N/A This should fix the broken automapping configuration for bundles that use annotations and attributes, see #44355 for additional details. When using the newer bundle directory structure conventions, especially with the `Bundle::getPath()` method overridden to point the bundle root path to the Bundle class' parent directory, the issue comes up because the bundle filesystem root path does not match the root path for the actual bundle code (effectively the PSR-4 root path). To fix automapping, the `AbstractDoctrineExtension::detectMetadataDriver()` method will be called a second time with the Bundle classpath if the first call (which is effectively the same as `Bundle::getPath()`) can't resolve the appropriate mapping type. This will also update setting `$bundleConfig['dir']` for drivers that are based on PHP classes so that the root path is based on the bundle classpath (AKA the PSR-4 root path) instead of the bundle path. The bulk of this patch is mainly from adding test fixture bundles to be able to test the `AbstractDoctrineExtension::getMappingDriverBundleConfigDefaults()` method in this repo and ensuring that the metadata driver detection works right for all of the supported drivers. Commits ------- 0aaa2fd Fix bundle automapping detection for annotations and attributes
2 parents 06ada78 + 0aaa2fd commit 5cad3b6
Copy full SHA for 5cad3b6

File tree

23 files changed

+500
-4
lines changed
Filter options

23 files changed

+500
-4
lines changed

‎src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php
+7-2Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,15 @@ protected function getMappingDriverBundleConfigDefaults(array $bundleConfig, \Re
148148
$bundleDir = func_get_arg(3);
149149
}
150150

151-
$bundleDir ?? $bundleDir = \dirname($bundle->getFileName());
151+
$bundleClassDir = \dirname($bundle->getFileName());
152+
$bundleDir ?? $bundleDir = $bundleClassDir;
152153

153154
if (!$bundleConfig['type']) {
154155
$bundleConfig['type'] = $this->detectMetadataDriver($bundleDir, $container);
156+
157+
if (!$bundleConfig['type'] && $bundleDir !== $bundleClassDir) {
158+
$bundleConfig['type'] = $this->detectMetadataDriver($bundleClassDir, $container);
159+
}
155160
}
156161

157162
if (!$bundleConfig['type']) {
@@ -161,7 +166,7 @@ protected function getMappingDriverBundleConfigDefaults(array $bundleConfig, \Re
161166

162167
if (!$bundleConfig['dir']) {
163168
if (\in_array($bundleConfig['type'], ['annotation', 'staticphp', 'attribute'])) {
164-
$bundleConfig['dir'] = $bundleDir.'/'.$this->getMappingObjectDefaultName();
169+
$bundleConfig['dir'] = $bundleClassDir.'/'.$this->getMappingObjectDefaultName();
165170
} else {
166171
$bundleConfig['dir'] = $bundleDir.'/'.$this->getMappingResourceConfigDirectory($bundleDir);
167172
}

‎src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/DoctrineExtensionTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/DoctrineExtensionTest.php
+76-2Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Symfony\Component\DependencyInjection\ContainerBuilder;
1717
use Symfony\Component\DependencyInjection\Definition;
1818
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
19+
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
1920

2021
/**
2122
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
@@ -53,6 +54,10 @@ protected function setUp(): void
5354
$this->extension
5455
->method('getMappingObjectDefaultName')
5556
->willReturn('Entity');
57+
58+
$this->extension
59+
->method('getMappingResourceExtension')
60+
->willReturn('orm');
5661
}
5762

5863
public function testFixManagersAutoMappingsWithTwoAutomappings()
@@ -271,6 +276,75 @@ public function testUnrecognizedCacheDriverException()
271276
$this->invokeLoadCacheDriver($objectManager, $container, $cacheName);
272277
}
273278

279+
public function providerBundles()
280+
{
281+
yield ['AnnotationsBundle', 'annotation', '/Entity'];
282+
if (\PHP_VERSION_ID >= 80000) {
283+
yield ['AttributesBundle', 'attribute', '/Entity'];
284+
}
285+
yield ['XmlBundle', 'xml', '/Resources/config/doctrine'];
286+
yield ['PhpBundle', 'php', '/Resources/config/doctrine'];
287+
yield ['YamlBundle', 'yml', '/Resources/config/doctrine'];
288+
289+
yield ['SrcXmlBundle', 'xml', '/Resources/config/doctrine'];
290+
291+
yield ['NewAnnotationsBundle', 'annotation', '/src/Entity'];
292+
yield ['NewXmlBundle', 'xml', '/config/doctrine'];
293+
}
294+
295+
/**
296+
* @dataProvider providerBundles
297+
*/
298+
public function testBundleAutoMapping(string $bundle, string $expectedType, string $dirSuffix)
299+
{
300+
$bundleDir = __DIR__.'/../Fixtures/Bundles/'.$bundle;
301+
$bundleClassName = 'Fixtures\\Bundles\\'.$bundle.'\\'.$bundle;
302+
303+
if (is_dir($bundleDir.'/src')) {
304+
require_once $bundleDir.'/src/'.$bundle.'.php';
305+
} else {
306+
require_once $bundleDir.'/'.$bundle.'.php';
307+
}
308+
309+
/** @var BundleInterface $bundleClass */
310+
$bundleClass = new $bundleClassName();
311+
312+
$mappingConfig = [
313+
'dir' => false,
314+
'type' => false,
315+
'prefix' => false,
316+
'mapping' => true,
317+
'is_bundle' => true,
318+
];
319+
320+
$this->extension
321+
->method('getMappingResourceConfigDirectory')
322+
->willReturnCallback(function ($bundleDir) {
323+
if (null !== $bundleDir && is_dir($bundleDir.'/config/doctrine')) {
324+
return 'config/doctrine';
325+
}
326+
327+
return 'Resources/config/doctrine';
328+
});
329+
330+
$container = $this->createContainer([], [$bundle => $bundleClassName]);
331+
332+
$reflection = new \ReflectionClass(\get_class($this->extension));
333+
$method = $reflection->getMethod('getMappingDriverBundleConfigDefaults');
334+
$method->setAccessible(true);
335+
336+
$this->assertSame(
337+
[
338+
'dir' => $bundleClass->getPath().$dirSuffix,
339+
'type' => $expectedType,
340+
'prefix' => $bundleClass->getNamespace().'\\Entity',
341+
'mapping' => true,
342+
'is_bundle' => true,
343+
],
344+
$method->invoke($this->extension, $mappingConfig, new \ReflectionClass($bundleClass), $container, $bundleClass->getPath())
345+
);
346+
}
347+
274348
protected function invokeLoadCacheDriver(array $objectManager, ContainerBuilder $container, $cacheName)
275349
{
276350
$method = new \ReflectionMethod($this->extension, 'loadObjectManagerCacheDriver');
@@ -280,10 +354,10 @@ protected function invokeLoadCacheDriver(array $objectManager, ContainerBuilder
280354
$method->invokeArgs($this->extension, [$objectManager, $container, $cacheName]);
281355
}
282356

283-
protected function createContainer(array $data = []): ContainerBuilder
357+
protected function createContainer(array $data = [], array $extraBundles = []): ContainerBuilder
284358
{
285359
return new ContainerBuilder(new ParameterBag(array_merge([
286-
'kernel.bundles' => ['FrameworkBundle' => 'Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle'],
360+
'kernel.bundles' => array_merge(['FrameworkBundle' => 'Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle'], $extraBundles),
287361
'kernel.cache_dir' => __DIR__,
288362
'kernel.build_dir' => __DIR__,
289363
'kernel.container_class' => 'kernel',
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Fixtures\Bundles\AnnotationsBundle;
13+
14+
use Symfony\Component\HttpKernel\Bundle\Bundle;
15+
16+
class AnnotationsBundle extends Bundle
17+
{
18+
}
+39Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Fixtures\Bundles\AnnotationsBundle\Entity;
13+
14+
use Doctrine\ORM\Mapping\Column;
15+
use Doctrine\ORM\Mapping\Entity;
16+
use Doctrine\ORM\Mapping\Id;
17+
18+
/**
19+
* @Entity
20+
*/
21+
class Person
22+
{
23+
/** @Id @Column(type="integer") */
24+
protected $id;
25+
26+
/** @Column(type="string") */
27+
public $name;
28+
29+
public function __construct($id, $name)
30+
{
31+
$this->id = $id;
32+
$this->name = $name;
33+
}
34+
35+
public function __toString(): string
36+
{
37+
return (string) $this->name;
38+
}
39+
}
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Fixtures\Bundles\AttributesBundle;
13+
14+
use Symfony\Component\HttpKernel\Bundle\Bundle;
15+
16+
class AttributesBundle extends Bundle
17+
{
18+
}
+37Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Fixtures\Bundles\AttributesBundle\Entity;
13+
14+
use Doctrine\ORM\Mapping\Column;
15+
use Doctrine\ORM\Mapping\Entity;
16+
use Doctrine\ORM\Mapping\Id;
17+
18+
#[Entity]
19+
class Person
20+
{
21+
#[Id, Column(type: 'integer')]
22+
protected $id;
23+
24+
#[Column(type: 'string')]
25+
public $name;
26+
27+
public function __construct($id, $name)
28+
{
29+
$this->id = $id;
30+
$this->name = $name;
31+
}
32+
33+
public function __toString(): string
34+
{
35+
return (string) $this->name;
36+
}
37+
}
+39Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Fixtures\Bundles\NewAnnotationsBundle\Entity;
13+
14+
use Doctrine\ORM\Mapping\Column;
15+
use Doctrine\ORM\Mapping\Entity;
16+
use Doctrine\ORM\Mapping\Id;
17+
18+
/**
19+
* @Entity
20+
*/
21+
class Person
22+
{
23+
/** @Id @Column(type="integer") */
24+
protected $id;
25+
26+
/** @Column(type="string") */
27+
public $name;
28+
29+
public function __construct($id, $name)
30+
{
31+
$this->id = $id;
32+
$this->name = $name;
33+
}
34+
35+
public function __toString(): string
36+
{
37+
return (string) $this->name;
38+
}
39+
}
+22Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Fixtures\Bundles\NewAnnotationsBundle;
13+
14+
use Symfony\Component\HttpKernel\Bundle\Bundle;
15+
16+
class NewAnnotationsBundle extends Bundle
17+
{
18+
public function getPath(): string
19+
{
20+
return \dirname(__DIR__);
21+
}
22+
}

‎src/Symfony/Bridge/Doctrine/Tests/Fixtures/Bundles/NewXmlBundle/config/doctrine/Person.orm.xml

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Doctrine/Tests/Fixtures/Bundles/NewXmlBundle/config/doctrine/Person.orm.xml
Whitespace-only changes.
+30Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Fixtures\Bundles\NewXmlBundle\Entity;
13+
14+
class Person
15+
{
16+
protected $id;
17+
18+
public $name;
19+
20+
public function __construct($id, $name)
21+
{
22+
$this->id = $id;
23+
$this->name = $name;
24+
}
25+
26+
public function __toString(): string
27+
{
28+
return (string) $this->name;
29+
}
30+
}
+22Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Fixtures\Bundles\NewXmlBundle;
13+
14+
use Symfony\Component\HttpKernel\Bundle\Bundle;
15+
16+
class NewXmlBundle extends Bundle
17+
{
18+
public function getPath(): string
19+
{
20+
return \dirname(__DIR__);
21+
}
22+
}
+30Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Fixtures\Bundles\PhpBundle\Entity;
13+
14+
class Person
15+
{
16+
protected $id;
17+
18+
public $name;
19+
20+
public function __construct($id, $name)
21+
{
22+
$this->id = $id;
23+
$this->name = $name;
24+
}
25+
26+
public function __toString(): string
27+
{
28+
return (string) $this->name;
29+
}
30+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.