Skip to content
Merged
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
6 changes: 0 additions & 6 deletions UPGRADE-1.2.md

This file was deleted.

11 changes: 0 additions & 11 deletions UPGRADE-2.2.md

This file was deleted.

4 changes: 0 additions & 4 deletions UPGRADE-2.3.md

This file was deleted.

59 changes: 59 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
Note about upgrading: Doctrine uses static and runtime mechanisms to raise
awareness about deprecated code.

- Use of `@deprecated` docblock that is detected by IDEs (like PHPStorm) or
Static Analysis tools (like Psalm, phpstan)
- Use of our low-overhead runtime deprecation API, details:
https://github.com/doctrine/deprecations/

# Upgrade to 2.4

## Deprecated `AnnotationDriver`

Since attributes were introduced in PHP 8.0, annotations are deprecated. Use
`ColocatedMappingDriver` instead. This will involve implementing
`isTransient()` as well as `__construct()` and `getReader()` to
retain backward compatibility.

# Upgrade to 2.3

## Deprecated using short namespace alias syntax in favor of `::class` syntax.

Before:

```php
$objectManager->find('MyPackage:MyClass', $id);
$objectManager->createQuery('SELECT u FROM MyPackage:MyClass');
```

After:

```php
$objectManager->find(MyClass::class, $id);
$objectManager->createQuery('SELECT u FROM '. MyClass::class);
```

# Upgrade to 2.2

## Deprecated `doctrine/cache` usage for metadata caching

The `setCacheDriver` and `getCacheDriver` methods in
`Doctrine\Persistence\Mapping\AbstractMetadata` have been deprecated. Please
use `getCache` and `setCache` with a PSR-6 implementation instead. Note that
even after switching to PSR-6, `getCacheDriver` will return a cache instance
that wraps the PSR-6 cache. Note that if you use a custom implementation of
doctrine/cache, the library may not be able to provide a forward compatibility
layer. The cache implementation MUST extend the
`Doctrine\Common\Cache\CacheProvider` class.

# Upgrade to 1.2

## Deprecated `ObjectManager::merge()` and `ObjectManager::detach()`

Please handle merge operations in your application, and use
`ObjectManager::clear()` instead.

## Deprecated `PersistentObject`

Please implement this functionality directly in your application if you want
ActiveRecord style functionality.
46 changes: 5 additions & 41 deletions docs/en/reference/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ Mapping Driver

In order to load ``ClassMetadata`` instances you can use the ``Doctrine\Persistence\Mapping\Driver\MappingDriver``
interface. This is the interface that does the core loading of mapping information from wherever they are stored.
That may be in files, annotations, yaml, xml, etc.
That may be in files, attributes, yaml, xml, etc.

.. code-block:: php

Expand All @@ -174,8 +174,8 @@ That may be in files, annotations, yaml, xml, etc.
public function isTransient($className);
}

The Doctrine Persistence project offers a few base implementations that make it easy to implement your own XML,
Annotations or YAML drivers.
The Doctrine Persistence project offers a few base implementations that
make it easy to implement your own XML, Attributes or YAML drivers.
Copy link
Member

Choose a reason for hiding this comment

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

Attributes, or YAML


FileDriver
----------
Expand Down Expand Up @@ -233,45 +233,9 @@ AnnotationDriver

.. note::

This driver requires the ``doctrine/annotations`` project. You can install it with composer.
This driver requires the ``doctrine/annotations`` project and is
deprecated because of that.
Copy link
Member

Choose a reason for hiding this comment

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

I'd add a note about attributes superseding annotations

Copy link
Member

Choose a reason for hiding this comment

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

Also why removing the docs below? The feature is deprecated but documentation is still valuable :)

Copy link
Member Author

Choose a reason for hiding this comment

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

I think it feels weird to deprecate a feature yet help people build on it. I thought I would make it harder for people to shoot themselves in the foot.


.. code-block:: php

composer require doctrine/annotations

The AnnotationDriver reads the mapping metadata from docblock annotations.

.. code-block:: php

final class MyAnnotationDriver extends AnnotationDriver
{
public function loadMetadataForClass($className, ClassMetadata $metadata)
{
/** @var ClassMetadata $class */
$reflClass = $class->getReflectionClass();

$classAnnotations = $this->reader->getClassAnnotations($reflClass);

// Use the reader to read annotations from your classes to then populate the $metadata instance.
}
}

Now you can use it like the following:

.. code-block:: php

use App\Model\User;
use Doctrine\Annotations\AnnotationReader;
use Doctrine\Persistence\Mapping\ClassMetadata;

$annotationReader = new AnnotationReader();

$annotationDriver = new AnnotationDriver($annotationReader, '/path/to/classes/with/annotations');

$classMetadata = new ClassMetadata();

// looks for a PHP file at /path/to/classes/with/annotations/App/Model/User.php
$annotationDriver->loadMetadataForClass(User::class, $classMetadata);

PHPDriver
---------
Expand Down
196 changes: 4 additions & 192 deletions lib/Doctrine/Persistence/Mapping/Driver/AnnotationDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,68 +3,26 @@
namespace Doctrine\Persistence\Mapping\Driver;

use Doctrine\Common\Annotations\Reader;
use Doctrine\Persistence\Mapping\MappingException;
use FilesystemIterator;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use RecursiveRegexIterator;
use ReflectionClass;
use RegexIterator;

use function array_merge;
use function array_unique;
use function assert;
use function get_class;
use function get_declared_classes;
use function in_array;
use function is_dir;
use function preg_match;
use function preg_quote;
use function realpath;
use function str_replace;
use function strpos;

/**
* The AnnotationDriver reads the mapping metadata from docblock annotations.
*
* @deprecated extend ColocatedMappingDriver directly instead.
*/
abstract class AnnotationDriver implements MappingDriver
{
use ColocatedMappingDriver;

/**
* The annotation reader.
*
* @var Reader
*/
protected $reader;

/**
* The paths where to look for mapping files.
*
* @var string[]
*/
protected $paths = [];

/**
* The paths excluded from path where to look for mapping files.
*
* @var string[]
*/
protected $excludePaths = [];

/**
* The file extension of mapping documents.
*
* @var string
*/
protected $fileExtension = '.php';

/**
* Cache for AnnotationDriver#getAllClassNames().
*
* @var string[]|null
* @psalm-var list<class-string>|null
*/
protected $classNames;

/**
* Name of the entity annotations as keys.
*
Expand All @@ -82,57 +40,10 @@ abstract class AnnotationDriver implements MappingDriver
public function __construct($reader, $paths = null)
Copy link
Member

Choose a reason for hiding this comment

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

Should the constructor trigger a runtime deprecation?

{
$this->reader = $reader;
if (! $paths) {
return;
}

$this->addPaths((array) $paths);
}

/**
* Appends lookup paths to metadata driver.
*
* @param string[] $paths
*
* @return void
*/
public function addPaths(array $paths)
{
$this->paths = array_unique(array_merge($this->paths, $paths));
}

/**
* Retrieves the defined metadata lookup paths.
*
* @return string[]
*/
public function getPaths()
{
return $this->paths;
}

/**
* Append exclude lookup paths to metadata driver.
*
* @param string[] $paths
*
* @return void
*/
public function addExcludePaths(array $paths)
{
$this->excludePaths = array_unique(array_merge($this->excludePaths, $paths));
}

/**
* Retrieve the defined metadata lookup exclude paths.
*
* @return string[]
*/
public function getExcludePaths()
{
return $this->excludePaths;
}

/**
* Retrieve the current annotation reader
*
Expand All @@ -144,34 +55,6 @@ public function getReader()
}

/**
* Gets the file extension used to look for mapping files under.
*
* @return string
*/
public function getFileExtension()
{
return $this->fileExtension;
}

/**
* Sets the file extension used to look for mapping files under.
*
* @param string $fileExtension The file extension to set.
*
* @return void
*/
public function setFileExtension($fileExtension)
{
$this->fileExtension = $fileExtension;
}

/**
* Returns whether the class with the specified name is transient. Only non-transient
* classes, that is entities and mapped superclasses, should have their metadata loaded.
*
* A class is non-transient if it is annotated with an annotation
* from the {@see AnnotationDriver::entityAnnotationClasses}.
*
* {@inheritDoc}
*/
public function isTransient($className)
Expand All @@ -186,75 +69,4 @@ public function isTransient($className)

return true;
}

/**
* {@inheritDoc}
*/
public function getAllClassNames()
{
if ($this->classNames !== null) {
return $this->classNames;
}

if (! $this->paths) {
throw MappingException::pathRequired();
}

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

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

$iterator = new RegexIterator(
new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS),
RecursiveIteratorIterator::LEAVES_ONLY
),
'/^.+' . preg_quote($this->fileExtension) . '$/i',
RecursiveRegexIterator::GET_MATCH
);

foreach ($iterator as $file) {
$sourceFile = $file[0];

if (preg_match('(^phar:)i', $sourceFile) === 0) {
$sourceFile = realpath($sourceFile);
}

foreach ($this->excludePaths as $excludePath) {
$realExcludePath = realpath($excludePath);
assert($realExcludePath !== false);
$exclude = str_replace('\\', '/', $realExcludePath);
$current = str_replace('\\', '/', $sourceFile);

if (strpos($current, $exclude) !== false) {
continue 2;
}
}

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) || $this->isTransient($className)) {
continue;
}

$classes[] = $className;
}

$this->classNames = $classes;

return $classes;
}
}
Loading