Skip to content

Commit 0f70c20

Browse files
committed
Require files loaded by the PHPDriver to return a Closure
1 parent 4d266fa commit 0f70c20

File tree

6 files changed

+46
-52
lines changed

6 files changed

+46
-52
lines changed

UPGRADE.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,30 @@ The code base now has constants with type declarations. If you extend types
2121
from the library and override the constants, you will need to add compatible
2222
type declarations.
2323

24+
## BC Break: Require files loaded by the `PHPDriver` to return a `Closure`
25+
26+
If you use the `PHPDriver` for configuring metadata in PHP files, you must wrap
27+
the code in a closure that is returned by the configuration file.
28+
29+
Before:
30+
31+
```php
32+
<?php // mappings/App.Entity.User.php
33+
34+
$metadata->name = \App\Entity\User::class;
35+
```
36+
37+
After:
38+
39+
```php
40+
<?php // mappings/App.Entity.User.php
41+
42+
use Doctrine\Persistence\Mapping\ClassMetadata;
43+
return function (ClassMetadata $metadata): void {
44+
$metadata->name = \App\Entity\User::class;
45+
};
46+
```
47+
2448
# Upgrade to 4.2
2549

2650
## Add `getFieldValue` and `setFieldValue` to `ClassMetadata` implementation

src/Mapping/Driver/PHPDriver.php

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,8 @@
55
namespace Doctrine\Persistence\Mapping\Driver;
66

77
use Closure;
8-
use CompileError;
9-
use Doctrine\Deprecations\Deprecation;
108
use Doctrine\Persistence\Mapping\ClassMetadata;
11-
use Error;
9+
use Doctrine\Persistence\Mapping\MappingException;
1210

1311
/**
1412
* The PHPDriver includes php files which just populate ClassMetadataInfo
@@ -39,36 +37,18 @@ public function loadMetadataForClass(string $className, ClassMetadata $metadata)
3937
*/
4038
protected function loadMappingFile(string $file): array
4139
{
42-
try {
43-
$callback = Closure::bind(static function (string $file): mixed {
44-
$metadata = null;
40+
$callback = Closure::bind(static function (string $file): mixed {
41+
$metadata = null;
4542

46-
return include $file;
47-
}, null, null)($file);
48-
} catch (CompileError $e) {
49-
throw $e;
50-
} catch (Error) {
51-
// Calling any method on $metadata=null will raise an Error
52-
// Falling back to legacy behavior of expecting $metadata to be populated
53-
$callback = null;
54-
}
43+
return include $file;
44+
}, null, null)($file);
5545

5646
if ($callback instanceof Closure) {
5747
$callback($this->metadata);
5848

5949
return [$this->metadata->getName() => $this->metadata];
6050
}
6151

62-
Deprecation::trigger(
63-
'doctrine/persistence',
64-
'https://github.com/doctrine/persistence/pull/450',
65-
'Not returning a Closure from a PHP mapping file is deprecated',
66-
);
67-
68-
unset($callback);
69-
$metadata = $this->metadata;
70-
include $file;
71-
72-
return [$metadata->getName() => $metadata];
52+
throw MappingException::phpFileMustReturnAClosure($file);
7353
}
7454
}

src/Mapping/MappingException.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,12 @@ public static function classIsAnonymous(string $className): self
7777
{
7878
return new self(sprintf('Class "%s" is anonymous', $className));
7979
}
80+
81+
public static function phpFileMustReturnAClosure(string $fileName): self
82+
{
83+
return new self(sprintf(
84+
'The PHP mapping file "%s" must return a Closure that receives the ClassMetadata instance as argument.',
85+
$fileName,
86+
));
87+
}
8088
}

tests/Mapping/PHPDriverTest.php

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,23 @@
77
use Doctrine\Deprecations\PHPUnit\VerifyDeprecations;
88
use Doctrine\Persistence\Mapping\ClassMetadata;
99
use Doctrine\Persistence\Mapping\Driver\PHPDriver;
10+
use Doctrine\Persistence\Mapping\MappingException;
1011
use Error;
11-
use PHPUnit\Framework\Attributes\IgnoreDeprecations;
12-
use PHPUnit\Framework\Attributes\TestWith;
1312
use PHPUnit\Framework\TestCase;
1413

1514
class PHPDriverTest extends TestCase
1615
{
1716
use VerifyDeprecations;
1817

19-
/** @phpstan-param class-string $className */
20-
#[IgnoreDeprecations]
21-
#[TestWith([PHPTestEntity::class])]
22-
#[TestWith([PHPTestEntityAssert::class])]
23-
public function testLoadMetadata(string $className): void
18+
public function testLoadMetadata(): void
2419
{
25-
$metadata = $this->createMock(ClassMetadata::class);
26-
$metadata->expects(self::once())->method('getFieldNames');
27-
$driver = new PHPDriver([__DIR__ . '/_files']);
20+
$metadata = $this->createStub(ClassMetadata::class);
21+
$driver = new PHPDriver([__DIR__ . '/_files']);
2822

29-
$this->expectDeprecationWithIdentifier('https://github.com/doctrine/persistence/pull/450');
30-
$driver->loadMetadataForClass($className, $metadata);
23+
self::expectException(MappingException::class);
24+
self::expectExceptionMessage('The PHP mapping file "' . __DIR__ . '/_files/Doctrine.Tests.Persistence.Mapping.PHPTestEntity.php" must return a Closure that receives the ClassMetadata instance as argument.');
25+
26+
$driver->loadMetadataForClass(PHPTestEntity::class, $metadata);
3127
}
3228

3329
public function testLoadMetadataWithClosure(): void
@@ -66,10 +62,6 @@ class PHPTestEntity
6662
{
6763
}
6864

69-
class PHPTestEntityAssert
70-
{
71-
}
72-
7365
class PHPTestEntityClosure
7466
{
7567
}
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
<?php
22

33
declare(strict_types=1);
4-
5-
$metadata->getFieldNames();

tests/Mapping/_files/Doctrine.Tests.Persistence.Mapping.PHPTestEntityAssert.php

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)