Skip to content

Commit df8ddf9

Browse files
committed
Feature: add support for $filePaths
In the scope of doctrine/persistence#432 (available from `doctrine/persistence` >= 4.1) there was added `ColocatedMappingDriver::$filePaths` property, which allows passing the iterable of file paths for the mapping driver to use. This commit integrates those changes into `AttributeDriver`. Since `doctrine/orm` maintains the support for `doctrine/persistence` of older versions, `AttributeDriver` ensures that `$filePaths` is actually defined. Tests use `InstalledVersions` to opt into new behaviour if `doctrine/persistence` is version 4.1 or above. The old behaviour can be adapted into the new by using `DirectoryFilesIterator` and `FilePathNameIterator` on directory paths.
1 parent f854529 commit df8ddf9

File tree

16 files changed

+153
-58
lines changed

16 files changed

+153
-58
lines changed

composer.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,19 @@
3131
"doctrine/inflector": "^1.4 || ^2.0",
3232
"doctrine/instantiator": "^1.3 || ^2",
3333
"doctrine/lexer": "^3",
34-
"doctrine/persistence": "^3.3.1 || ^4",
3534
"psr/cache": "^1 || ^2 || ^3",
3635
"symfony/console": "^5.4 || ^6.0 || ^7.0",
3736
"symfony/var-exporter": "^6.3.9 || ^7.0"
3837
},
38+
"repositories": [
39+
{
40+
"type": "vcs",
41+
"url": "https://github.com/rela589n/doctrine-persistence.git"
42+
}
43+
],
3944
"require-dev": {
4045
"doctrine/coding-standard": "^13.0",
46+
"doctrine/persistence": "^3.3.1 || ^4.0@dev",
4147
"phpbench/phpbench": "^1.0",
4248
"phpdocumentor/guides-cli": "^1.4",
4349
"phpstan/extension-installer": "^1.4",

docs/en/reference/advanced-configuration.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ steps of configuration.
2929
3030
$config = new Configuration;
3131
$config->setMetadataCache($metadataCache);
32-
$driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities'], true);
32+
$driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities']);
3333
$config->setMetadataDriverImpl($driverImpl);
3434
$config->setQueryCache($queryCache);
3535
@@ -154,7 +154,7 @@ The attribute driver can be injected in the ``Doctrine\ORM\Configuration``:
154154
<?php
155155
use Doctrine\ORM\Mapping\Driver\AttributeDriver;
156156
157-
$driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities'], true);
157+
$driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities']);
158158
$config->setMetadataDriverImpl($driverImpl);
159159
160160
The path information to the entities is required for the attribute

phpstan-baseline.neon

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,6 +1314,13 @@ parameters:
13141314
count: 1
13151315
path: src/Mapping/DefaultQuoteStrategy.php
13161316

1317+
-
1318+
message: '#^Access to an undefined property Doctrine\\ORM\\Mapping\\Driver\\AttributeDriver\:\:\$filePaths\.$#'
1319+
identifier: property.notFound # property is available starting from doctrine/persistence 4.1
1320+
count: 1
1321+
path: src/Mapping/Driver/AttributeDriver.php
1322+
reportUnmatched: false
1323+
13171324
-
13181325
message: '#^Method Doctrine\\ORM\\Mapping\\Driver\\AttributeDriver\:\:isRepeatedPropertyDeclaration\(\) has parameter \$metadata with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
13191326
identifier: missingType.generics

src/Mapping/Driver/AttributeDriver.php

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,18 @@
1313
use Doctrine\Persistence\Mapping\Driver\ColocatedMappingDriver;
1414
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
1515
use InvalidArgumentException;
16+
use LogicException;
1617
use ReflectionClass;
1718
use ReflectionMethod;
19+
use Traversable;
1820

1921
use function assert;
2022
use function class_exists;
2123
use function constant;
2224
use function defined;
25+
use function is_file;
26+
use function property_exists;
27+
use function reset;
2328
use function sprintf;
2429

2530
class AttributeDriver implements MappingDriver
@@ -35,10 +40,10 @@ class AttributeDriver implements MappingDriver
3540
private readonly AttributeReader $reader;
3641

3742
/**
38-
* @param array<string> $paths
39-
* @param true $reportFieldsWhereDeclared no-op, to be removed in 4.0
43+
* @param iterable<string> $paths iterable of source file paths, or an array of directories.
44+
* @param true $reportFieldsWhereDeclared no-op, to be removed in 4.0
4045
*/
41-
public function __construct(array $paths, bool $reportFieldsWhereDeclared = true)
46+
public function __construct(iterable $paths, bool $reportFieldsWhereDeclared = true)
4247
{
4348
if (! $reportFieldsWhereDeclared) {
4449
throw new InvalidArgumentException(sprintf(
@@ -47,8 +52,19 @@ public function __construct(array $paths, bool $reportFieldsWhereDeclared = true
4752
));
4853
}
4954

55+
$pathsAreFilePaths = $paths instanceof Traversable || ($paths !== [] && is_file(reset($paths)));
56+
57+
if ($pathsAreFilePaths) {
58+
if (! property_exists(self::class, 'filePaths')) {
59+
throw new LogicException('Source file paths support for AttributeDriver is available since doctrine/persistence 4.1.');
60+
}
61+
62+
$this->filePaths = $paths;
63+
} else {
64+
$this->addPaths($paths);
65+
}
66+
5067
$this->reader = new AttributeReader();
51-
$this->addPaths($paths);
5268
}
5369

5470
public function isTransient(string $className): bool

src/ORMSetup.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ final class ORMSetup
2828
/**
2929
* Creates a configuration with an attribute metadata driver.
3030
*
31-
* @param string[] $paths
31+
* @param iterable<string> $paths
3232
*/
3333
public static function createAttributeMetadataConfiguration(
34-
array $paths,
34+
iterable $paths,
3535
bool $isDevMode = false,
3636
string|null $proxyDir = null,
3737
CacheItemPoolInterface|null $cache = null,
@@ -47,24 +47,24 @@ public static function createAttributeMetadataConfiguration(
4747
}
4848

4949
$config = self::createConfiguration($isDevMode, $proxyDir, $cache);
50-
$config->setMetadataDriverImpl(new AttributeDriver($paths));
50+
$config->setMetadataDriverImpl(new AttributeDriver($paths, true));
5151

5252
return $config;
5353
}
5454

5555
/**
5656
* Creates a configuration with an attribute metadata driver.
5757
*
58-
* @param string[] $paths
58+
* @param iterable<string> $paths
5959
*/
6060
public static function createAttributeMetadataConfig(
61-
array $paths,
61+
iterable $paths,
6262
bool $isDevMode = false,
6363
string|null $cacheNamespaceSeed = null,
6464
CacheItemPoolInterface|null $cache = null,
6565
): Configuration {
6666
$config = self::createConfig($isDevMode, $cacheNamespaceSeed, $cache);
67-
$config->setMetadataDriverImpl(new AttributeDriver($paths));
67+
$config->setMetadataDriverImpl(new AttributeDriver($paths, true));
6868

6969
return $config;
7070
}

tests/Performance/EntityManagerFactory.php

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,13 @@
1313
use Doctrine\ORM\Configuration;
1414
use Doctrine\ORM\EntityManager;
1515
use Doctrine\ORM\EntityManagerInterface;
16-
use Doctrine\ORM\Mapping\Driver\AttributeDriver;
1716
use Doctrine\ORM\Proxy\ProxyFactory;
1817
use Doctrine\ORM\Tools\SchemaTool;
1918
use Doctrine\Tests\Mocks\ArrayResultFactory;
19+
use Doctrine\Tests\Mocks\AttributeDriverFactory;
2020
use Doctrine\Tests\TestUtil;
2121

2222
use function array_map;
23-
use function realpath;
2423

2524
final class EntityManagerFactory
2625
{
@@ -30,10 +29,7 @@ public static function getEntityManager(array $schemaClassNames): EntityManagerI
3029

3130
TestUtil::configureProxies($config);
3231
$config->setAutoGenerateProxyClasses(ProxyFactory::AUTOGENERATE_EVAL);
33-
$config->setMetadataDriverImpl(new AttributeDriver([
34-
realpath(__DIR__ . '/Models/Cache'),
35-
realpath(__DIR__ . '/Models/GeoNames'),
36-
]));
32+
$config->setMetadataDriverImpl(AttributeDriverFactory::createAttributeDriver([__DIR__ . '/../Tests/Models/Cache', __DIR__ . '/../Tests/Models/GeoNames']));
3733

3834
$entityManager = new EntityManager(
3935
DriverManager::getConnection([
@@ -55,11 +51,7 @@ public static function makeEntityManagerWithNoResultsConnection(): EntityManager
5551

5652
TestUtil::configureProxies($config);
5753
$config->setAutoGenerateProxyClasses(ProxyFactory::AUTOGENERATE_EVAL);
58-
$config->setMetadataDriverImpl(new AttributeDriver([
59-
realpath(__DIR__ . '/Models/Cache'),
60-
realpath(__DIR__ . '/Models/Generic'),
61-
realpath(__DIR__ . '/Models/GeoNames'),
62-
]));
54+
$config->setMetadataDriverImpl(AttributeDriverFactory::createAttributeDriver([__DIR__ . '/../Tests/Models/Cache', __DIR__ . '/../Tests/Models/Generic', __DIR__ . '/../Tests/Models/GeoNames']));
6355

6456
// A connection that doesn't really do anything
6557
$connection = new class ([], new Driver(), null, new EventManager()) extends Connection
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\Mocks;
6+
7+
use Composer\InstalledVersions;
8+
use Doctrine\ORM\Mapping\Driver\AttributeDriver;
9+
use Doctrine\Persistence\Mapping\Driver\DirectoryFilesIterator;
10+
use Doctrine\Persistence\Mapping\Driver\FilePathNameIterator;
11+
12+
use function version_compare;
13+
14+
final class AttributeDriverFactory
15+
{
16+
/** @param list<string> $paths */
17+
public static function createAttributeDriver(array $paths = []): AttributeDriver
18+
{
19+
if (! self::isFilePathsSupported()) {
20+
return new AttributeDriver($paths, true);
21+
}
22+
23+
$filePaths = new FilePathNameIterator(new DirectoryFilesIterator($paths));
24+
25+
return new AttributeDriver($filePaths, true);
26+
}
27+
28+
public static function isFilePathsSupported(): bool
29+
{
30+
return version_compare(InstalledVersions::getVersion('doctrine/persistence'), '4.1', '>=');
31+
}
32+
33+
public static function pathFiles(string $path): FilePathNameIterator
34+
{
35+
return new FilePathNameIterator(new DirectoryFilesIterator([$path]));
36+
}
37+
}

tests/Tests/Mocks/EntityManagerMock.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
use Doctrine\DBAL\Connection;
99
use Doctrine\ORM\Configuration;
1010
use Doctrine\ORM\EntityManager;
11-
use Doctrine\ORM\Mapping\Driver\AttributeDriver;
1211
use Doctrine\ORM\Proxy\ProxyFactory;
1312
use Doctrine\ORM\UnitOfWork;
1413
use Doctrine\Tests\TestUtil;
@@ -26,7 +25,8 @@ public function __construct(Connection $conn, Configuration|null $config = null,
2625
if ($config === null) {
2726
$config = new Configuration();
2827
TestUtil::configureProxies($config);
29-
$config->setMetadataDriverImpl(new AttributeDriver([]));
28+
$attributeDriver = AttributeDriverFactory::createAttributeDriver();
29+
$config->setMetadataDriverImpl($attributeDriver);
3030
}
3131

3232
parent::__construct($conn, $config, $eventManager);

tests/Tests/ORM/Functional/EnumTest.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
use Doctrine\DBAL\Types\EnumType;
88
use Doctrine\ORM\AbstractQuery;
99
use Doctrine\ORM\Mapping\Column;
10-
use Doctrine\ORM\Mapping\Driver\AttributeDriver;
1110
use Doctrine\ORM\Mapping\MappingException;
1211
use Doctrine\ORM\Query\Expr\Func;
1312
use Doctrine\ORM\Tools\SchemaTool;
13+
use Doctrine\Tests\Mocks\AttributeDriverFactory;
1414
use Doctrine\Tests\Models\DataTransferObjects\DtoWithArrayOfEnums;
1515
use Doctrine\Tests\Models\DataTransferObjects\DtoWithEnum;
1616
use Doctrine\Tests\Models\Enums\Card;
@@ -28,7 +28,6 @@
2828
use PHPUnit\Framework\Attributes\DataProvider;
2929

3030
use function class_exists;
31-
use function dirname;
3231
use function sprintf;
3332
use function uniqid;
3433

@@ -38,7 +37,9 @@ public function setUp(): void
3837
{
3938
parent::setUp();
4039

41-
$this->_em = $this->getEntityManager(null, new AttributeDriver([dirname(__DIR__, 2) . '/Models/Enums'], true));
40+
$mappingDriver = AttributeDriverFactory::createAttributeDriver([__DIR__ . '/../../Models/Enums']);
41+
42+
$this->_em = $this->getEntityManager(null, $mappingDriver);
4243
$this->_schemaTool = new SchemaTool($this->_em);
4344

4445
if ($this->isSecondLevelCacheEnabled) {

tests/Tests/ORM/Functional/Locking/LockAgentWorker.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Doctrine\ORM\Configuration;
1010
use Doctrine\ORM\EntityManager;
1111
use Doctrine\ORM\EntityManagerInterface;
12+
use Doctrine\Tests\Mocks\AttributeDriverFactory;
1213
use Doctrine\Tests\ORM\Functional\Locking\Doctrine\ORM\Query;
1314
use Doctrine\Tests\TestUtil;
1415
use GearmanWorker;
@@ -116,8 +117,8 @@ protected function createEntityManager(Connection $conn): EntityManagerInterface
116117
TestUtil::configureProxies($config);
117118
$config->setAutoGenerateProxyClasses(true);
118119

119-
$annotDriver = new AttributeDriver([__DIR__ . '/../../../Models/']);
120-
$config->setMetadataDriverImpl($annotDriver);
120+
$attributeDriver = AttributeDriverFactory::createAttributeDriver([__DIR__ . '/../../../Models']);
121+
$config->setMetadataDriverImpl($attributeDriver);
121122
$config->setMetadataCache(new ArrayAdapter());
122123

123124
$config->setQueryCache(new ArrayAdapter());

0 commit comments

Comments
 (0)