Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,6 @@ parameters:
count: 1
path: tests/Mapping/ClassMetadataFactoryTest.php

-
message: '#^Parameter \#1 \$directories of static method Doctrine\\Persistence\\Mapping\\Driver\\FileClassLocator\:\:createFromDirectories\(\) expects list\<string\>, non\-empty\-array\<int, string\> given\.$#'
identifier: argument.type
count: 1
path: tests/Mapping/ColocatedMappingDriverTest.php

-
message: '#^Parameter \#2 \$excludedDirectories of static method Doctrine\\Persistence\\Mapping\\Driver\\FileClassLocator\:\:createFromDirectories\(\) expects list\<string\>, array\<int, string\> given\.$#'
identifier: argument.type
count: 1
path: tests/Mapping/ColocatedMappingDriverTest.php

-
message: '#^Call to static method PHPUnit\\Framework\\Assert\:\:assertSame\(\) with array\{''Doctrine\\\\Tests…'', ''Doctrine\\\\Tests\\\\ORM…'', ''Doctrine\\\\Tests\\\\ORM…''\} and list\<class\-string\> will always evaluate to false\.$#'
identifier: staticMethod.impossibleType
Expand Down
2 changes: 1 addition & 1 deletion src/Mapping/Driver/ColocatedMappingDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ trait ColocatedMappingDriver
*/
public function addPaths(array $paths): void
{
$this->paths = array_unique(array_merge($this->paths, $paths));
$this->paths = array_unique([...$this->paths, ...$paths]);
}

/**
Expand Down
6 changes: 3 additions & 3 deletions src/Mapping/Driver/FileClassLocator.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ public function getClassNames(): array
/**
* Creates a FileClassLocator from an array of directories.
*
* @param list<string> $directories
* @param list<string> $excludedDirectories Directories to exclude from the search.
* @param string $fileExtension The file extension to look for (default is '.php').
* @param string[] $directories
* @param string[] $excludedDirectories Directories to exclude from the search.
Comment on lines +84 to +85
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't use the key of the array when iterating. Relaxing this type si that array<int, string> is accepted, which is the result of array_unique.

* @param string $fileExtension The file extension to look for (default is '.php').
*
* @throws MappingException if any of the directories are not valid.
*/
Expand Down
99 changes: 8 additions & 91 deletions src/Mapping/Driver/StaticPHPDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,115 +5,32 @@
namespace Doctrine\Persistence\Mapping\Driver;

use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\Mapping\MappingException;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use ReflectionClass;

use function array_unique;
use function get_declared_classes;
use function in_array;
use function is_dir;
use function method_exists;
use function realpath;

/**
* The StaticPHPDriver calls a static loadMetadata() method on your entity
* classes where you can manually populate the ClassMetadata instance.
*/
class StaticPHPDriver implements MappingDriver
{
/**
* Paths of entity directories.
*
* @var array<int, string>
*/
private array $paths = [];
use ColocatedMappingDriver;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This introduces more public methods to the class. Maybe it needs to be documented in UPGRADE.md


/**
* Map of all class names.
*
* @var array<int, string>
* @phpstan-var list<class-string>
*/
private array|null $classNames = null;

/** @param array<int, string>|string $paths */
public function __construct(array|string $paths)
{
$this->addPaths((array) $paths);
}

/** @param array<int, string> $paths */
public function addPaths(array $paths): void
/** @param array<int, string>|string|ClassLocator $paths */
public function __construct(array|string|ClassLocator $paths)
{
$this->paths = array_unique([...$this->paths, ...$paths]);
if ($paths instanceof ClassLocator) {
$this->classLocator = $paths;
} else {
$this->addPaths((array) $paths);
}
}

public function loadMetadataForClass(string $className, ClassMetadata $metadata): void
{
$className::loadMetadata($metadata);
}

/**
* {@inheritDoc}
*
* @todo Same code exists in ColocatedMappingDriver, should we re-use it
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This deleted code is duplicate of FileClassLocator.

* somehow or not worry about it?
*/
public function getAllClassNames(): array
{
if ($this->classNames !== null) {
return $this->classNames;
}

if ($this->paths === []) {
throw MappingException::pathRequiredForDriver(static::class);
}

$classes = [];
$includedFiles = [];

foreach ($this->paths as $path) {
if (! is_dir($path)) {
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path);
}

$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path),
RecursiveIteratorIterator::LEAVES_ONLY,
);

foreach ($iterator as $file) {
if ($file->getBasename('.php') === $file->getBasename()) {
continue;
}

$sourceFile = realpath($file->getPathName());
require_once $sourceFile;
$includedFiles[] = $sourceFile;
}
}

$declared = get_declared_classes();

foreach ($declared as $className) {
$rc = new ReflectionClass($className);

$sourceFile = $rc->getFileName();

if (! in_array($sourceFile, $includedFiles, true) || $this->isTransient($className)) {
continue;
}

$classes[] = $className;
}

$this->classNames = $classes;

return $classes;
}

public function isTransient(string $className): bool
{
return ! method_exists($className, 'loadMetadata');
Expand Down
2 changes: 1 addition & 1 deletion tests/Mapping/ColocatedMappingDriverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ public function __construct(array|ClassLocator $paths)
if ($paths instanceof ClassLocator) {
$this->classLocator = $paths;
} else {
$this->paths = $paths;
$this->addPaths($paths);
}
}

Expand Down
21 changes: 11 additions & 10 deletions tests/Mapping/StaticPHPDriverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
namespace Doctrine\Tests\Persistence\Mapping;

use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\Mapping\Driver\ClassNames;
use Doctrine\Persistence\Mapping\Driver\StaticPHPDriver;
use Doctrine\Tests\Persistence\Mapping\_files\colocated\Entity;
use PHPUnit\Framework\TestCase;

class StaticPHPDriverTest extends TestCase
Expand All @@ -15,24 +17,23 @@ public function testLoadMetadata(): void
$metadata = $this->createMock(ClassMetadata::class);
$metadata->expects(self::once())->method('getFieldNames');

$driver = new StaticPHPDriver([__DIR__]);
$driver->loadMetadataForClass(TestEntity::class, $metadata);
$driver = new StaticPHPDriver([]);
$driver->loadMetadataForClass(Entity::class, $metadata);
}

public function testGetAllClassNames(): void
{
$driver = new StaticPHPDriver([__DIR__]);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This directory contains Doctrine.Tests.Persistence.Mapping.PHPTestEntityAssert.php that cannot be includes without setting the $metadata variable. Not supported by the StaticPHPDriver.

$driver = new StaticPHPDriver([__DIR__ . '/_files/colocated/']);
$classNames = $driver->getAllClassNames();

self::assertContains(TestEntity::class, $classNames);
self::assertContains(Entity::class, $classNames);
}
}

class TestEntity
{
/** @phpstan-param ClassMetadata<object> $metadata */
public static function loadMetadata(ClassMetadata $metadata): void
public function testGetAllClassesNamesWithClassLocator(): void
{
$metadata->getFieldNames();
$driver = new StaticPHPDriver(new ClassNames([Entity::class]));
$classNames = $driver->getAllClassNames();

self::assertSame([Entity::class], $classNames);
}
}
7 changes: 7 additions & 0 deletions tests/Mapping/_files/colocated/Entity.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,17 @@

namespace Doctrine\Tests\Persistence\Mapping\_files\colocated;

use Doctrine\Persistence\Mapping\ClassMetadata;

/**
* The driver should include this file and return its class name
* from {@see \Doctrine\Persistence\Mapping\Driver\ColocatedMappingDriver::getAllClassNames()} method.
*/
class Entity
{
/** @phpstan-param ClassMetadata<object> $metadata */
public static function loadMetadata(ClassMetadata $metadata): void
{
$metadata->getFieldNames();
}
}