Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decouple AnnotationDriver from doctrine/annotations #217

Closed
Closed
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
2 changes: 2 additions & 0 deletions UPGRADE-2.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ UPGRADE FROM 2.2 to 2.3
=======================

* Deprecated using short namespace alias syntax in favor of ::class syntax.
* Deprecated passing an annotation reader to `AnnotationDriver::__construct()`.
* Deprecated not overriding `AnnotationDriver::isTransient()` in a child class.
57 changes: 52 additions & 5 deletions lib/Doctrine/Persistence/Mapping/Driver/AnnotationDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
namespace Doctrine\Persistence\Mapping\Driver;

use Doctrine\Common\Annotations\Reader;
use Doctrine\Deprecations\Deprecation;
use Doctrine\Persistence\Mapping\MappingException;
use FilesystemIterator;
use LogicException;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use RecursiveRegexIterator;
Expand All @@ -14,13 +16,17 @@
use function array_merge;
use function array_unique;
use function assert;
use function func_get_arg;
use function func_num_args;
use function get_class;
use function get_declared_classes;
use function in_array;
use function is_dir;
use function is_object;
use function preg_match;
use function preg_quote;
use function realpath;
use function sprintf;
use function str_replace;
use function strpos;

Expand All @@ -32,7 +38,9 @@ abstract class AnnotationDriver implements MappingDriver
/**
* The annotation reader.
*
* @var Reader
* @deprecated Store the reader inside the child class instead.
*
* @var Reader|null
*/
protected $reader;

Expand Down Expand Up @@ -68,6 +76,8 @@ abstract class AnnotationDriver implements MappingDriver
/**
* Name of the entity annotations as keys.
*
* @deprecated
*
* @var array<class-string, bool|int>
*/
protected $entityAnnotationClasses = [];
Expand All @@ -76,12 +86,21 @@ abstract class AnnotationDriver implements MappingDriver
* Initializes a new AnnotationDriver that uses the given AnnotationReader for reading
* docblock annotations.
*
* @param Reader $reader The AnnotationReader to use, duck-typed.
* @param string|string[]|null $paths One or multiple paths where mapping classes can be found.
* @param string|string[]|null $paths One or multiple paths where mapping classes can be found.
*/
public function __construct($reader, $paths = null)
public function __construct($paths = null)
{
$this->reader = $reader;
if (is_object($paths)) {
Deprecation::trigger(
'doctrine/persistence',
'https://github.com/doctrine/persistence/pull/217',
'Passing an annotation reader to %s is deprecated. Store the reader in the child class instead and override isTransient().',
__METHOD__
);
$this->reader = $paths;
$paths = func_num_args() > 1 ? func_get_arg(1) : null;
}

if (! $paths) {
return;
}
Expand Down Expand Up @@ -136,10 +155,23 @@ public function getExcludePaths()
/**
* Retrieve the current annotation reader
*
* @deprecated
*
* @return Reader
*/
public function getReader()
{
Deprecation::trigger(
'doctrine/persistence',
'https://github.com/doctrine/persistence/pull/217',
'%s is deprecated without replacement.',
__METHOD__
);

if ($this->reader === null) {
throw new LogicException('The reader has not been initialized.');
}

return $this->reader;
}

Expand Down Expand Up @@ -176,6 +208,21 @@ public function setFileExtension($fileExtension)
*/
public function isTransient($className)
{
Deprecation::trigger(
'doctrine/persistence',
'https://github.com/doctrine/persistence/pull/217',
'Not overriding %s in %s is deprecated.',
__METHOD__,
static::class
);

if (! $this->reader) {
throw new LogicException(sprintf(
'The annotation reader has not been set. Override isTransient() in %s instead.',
static::class
));
}

$classAnnotations = $this->reader->getClassAnnotations(new ReflectionClass($className));

foreach ($classAnnotations as $annot) {
Expand Down
2 changes: 2 additions & 0 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
<!-- Ignore warnings and show progress of the run -->
<arg value="nps"/>

<config name="php_version" value="70100"/>

<file>lib</file>
<file>tests</file>

Expand Down
9 changes: 9 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,12 @@ parameters:

excludePaths:
- tests/Doctrine/Tests/Persistence/Mapping/_files/Doctrine.Tests.Persistence.Mapping.PHPTestEntity.php

ignoreErrors:
# TODO: Remove in 3.0
-
message: "#^Call to function is_object\\(\\) with array\\<string\\>\\|string\\|null will always evaluate to false\\.$#"
Copy link
Member

Choose a reason for hiding this comment

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

could be avoided by adding treatPhpDocTypesAsCertain: false in the phpstan parameters, which makes phpstan accept cases where a type check is done in the code that validates a type defined only in phpdoc (because phpdoc types are not enforced) while type checks done on a value that passed through a native type are still reported.

path: lib/Doctrine/Persistence/Mapping/Driver/AnnotationDriver.php
-
message: "#^Parameter \\#1 \\$paths of class Doctrine\\\\Tests\\\\Persistence\\\\Mapping\\\\SimpleAnnotationDriver constructor expects array\\<string\\>\\|string\\|null, Doctrine\\\\Common\\\\Annotations\\\\AnnotationReader given\\.$#"
path: tests/Doctrine/Tests/Persistence/Mapping/AnnotationDriverTest.php
6 changes: 6 additions & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
<file name="lib/Doctrine/Persistence/Reflection/TypedNoDefaultReflectionProperty.php"/>
</errorLevel>
</RedundantCondition>
<InvalidArgument>
<errorLevel type="suppress">
<!-- TODO: Remove in 3.0 -->
<file name="tests/Doctrine/Tests/Persistence/Mapping/AnnotationDriverTest.php" />
</errorLevel>
</InvalidArgument>
<InvalidNullableReturnType>
<errorLevel type="suppress">
<!-- see https://github.com/vimeo/psalm/issues/5193 -->
Expand Down
35 changes: 31 additions & 4 deletions tests/Doctrine/Tests/Persistence/Mapping/AnnotationDriverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Doctrine\Tests\Persistence\Mapping;

use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Deprecations\PHPUnit\VerifyDeprecations;
use Doctrine\Entity;
use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\Mapping\Driver\AnnotationDriver;
Expand All @@ -11,18 +12,44 @@

class AnnotationDriverTest extends TestCase
{
use VerifyDeprecations;

public function testGetAllClassNames(): void
{
$reader = new AnnotationReader();
$driver = new SimpleAnnotationDriver($reader, [__DIR__ . '/_files/annotation']);
$driver = new SimpleAnnotationDriver([__DIR__ . '/_files/annotation']);

self::assertSame([TestClass::class], $driver->getAllClassNames());
}

public function testGetAllClassNamesLegacy(): void
{
$this->expectDeprecationWithIdentifier('https://github.com/doctrine/persistence/pull/217');

$classes = $driver->getAllClassNames();
$driver = new SimpleAnnotationDriver(new AnnotationReader(), [__DIR__ . '/_files/annotation']);

self::assertSame([TestClass::class], $classes);
self::assertSame([TestClass::class], $driver->getAllClassNames());
}
}

class SimpleAnnotationDriver extends AnnotationDriver
{
/**
* {@inheritDoc}
*/
public function loadMetadataForClass($className, ClassMetadata $metadata): void
{
}

/**
* {@inheritdoc}
*/
public function isTransient($className): bool
{
return $className === Entity::class;
}
}

class LegacyAnnotationDriver extends AnnotationDriver
{
/** @var array<class-string, bool|int> */
protected $entityAnnotationClasses = [Entity::class => true];
Expand Down