Commit 40a7bb08 authored by catch's avatar catch
Browse files

Issue #2631202 by tedbow, Mile23, EclipseGc, dawehner, larowlan, tim.plunkett,...

Issue #2631202 by tedbow, Mile23, EclipseGc, dawehner, larowlan, tim.plunkett, catch, alexpott, xjm, neclimdul, cilefen, kreynen, StephanieFuda: Doctrine no longer supports SimpleAnnotationReader, incorporate a solution into core
parent 1a44baba
This diff is collapsed.
<?php
// @codingStandardsIgnoreFile
/**
* @file
*
* This class is a near-copy of
* Doctrine\Common\Annotations\SimpleAnnotationReader, which is part of the
* Doctrine project: <http://www.doctrine-project.org>. It was copied from
* version 1.2.7.
*
* Original copyright:
*
* Copyright (c) 2006-2013 Doctrine Project
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*/
namespace Drupal\Component\Annotation\Doctrine;
use Doctrine\Common\Annotations\Reader;
/**
* Simple Annotation Reader.
*
* Drupal adds its own version of DocParser and allows for ignoring common
* annotations.
*
* @internal
*/
final class SimpleAnnotationReader implements Reader
{
protected $ignoredAnnotations = [
'addtogroup' => TRUE,
'code' => TRUE,
'defgroup' => TRUE,
'deprecated' => TRUE,
'endcode' => TRUE,
'endlink' => TRUE,
'file' => TRUE,
'ingroup' => TRUE,
'group' => TRUE,
'link' => TRUE,
'mainpage' => TRUE,
'param' => TRUE,
'ref' => TRUE,
'return' => TRUE,
'section' => TRUE,
'see' => TRUE,
'subsection' => TRUE,
'throws' => TRUE,
'todo' => TRUE,
'var' => TRUE,
'{' => TRUE,
'}' => TRUE,
];
/**
* @var DocParser
*/
private $parser;
/**
* Constructor.
*
* Initializes a new SimpleAnnotationReader.
*/
public function __construct()
{
$this->parser = new DocParser();
$this->parser->setIgnoreNotImportedAnnotations(true);
$this->parser->setIgnoredAnnotationNames($this->ignoredAnnotations);
}
/**
* Adds a namespace in which we will look for annotations.
*
* @param string $namespace
*
* @return void
*/
public function addNamespace($namespace)
{
$this->parser->addNamespace($namespace);
}
/**
* {@inheritDoc}
*/
public function getClassAnnotations(\ReflectionClass $class)
{
return $this->parser->parse($class->getDocComment(), 'class '.$class->getName());
}
/**
* {@inheritDoc}
*/
public function getMethodAnnotations(\ReflectionMethod $method)
{
return $this->parser->parse($method->getDocComment(), 'method '.$method->getDeclaringClass()->name.'::'.$method->getName().'()');
}
/**
* {@inheritDoc}
*/
public function getPropertyAnnotations(\ReflectionProperty $property)
{
return $this->parser->parse($property->getDocComment(), 'property '.$property->getDeclaringClass()->name.'::$'.$property->getName());
}
/**
* {@inheritDoc}
*/
public function getClassAnnotation(\ReflectionClass $class, $annotationName)
{
foreach ($this->getClassAnnotations($class) as $annot) {
if ($annot instanceof $annotationName) {
return $annot;
}
}
return null;
}
/**
* {@inheritDoc}
*/
public function getMethodAnnotation(\ReflectionMethod $method, $annotationName)
{
foreach ($this->getMethodAnnotations($method) as $annot) {
if ($annot instanceof $annotationName) {
return $annot;
}
}
return null;
}
/**
* {@inheritDoc}
*/
public function getPropertyAnnotation(\ReflectionProperty $property, $annotationName)
{
foreach ($this->getPropertyAnnotations($property) as $annot) {
if ($annot instanceof $annotationName) {
return $annot;
}
}
return null;
}
}
......@@ -5,8 +5,8 @@
use Drupal\Component\Annotation\AnnotationInterface;
use Drupal\Component\FileCache\FileCacheFactory;
use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
use Drupal\Component\Annotation\Doctrine\SimpleAnnotationReader;
use Drupal\Component\Annotation\Reflection\MockFileFinder;
use Doctrine\Common\Annotations\SimpleAnnotationReader;
use Doctrine\Common\Annotations\AnnotationRegistry;
use Doctrine\Common\Reflection\StaticReflectionParser;
use Drupal\Component\Plugin\Discovery\DiscoveryTrait;
......
<?php
namespace Drupal\Tests\Component\Annotation;
use Drupal\Component\Annotation\Doctrine\DocParser;
use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass \Drupal\Component\Annotation\Doctrine\DocParser
*
* @group Annotation
*/
class DocParserIgnoredClassesTest extends TestCase {
/**
* Ensure annotations can be ignored when namespaces are present.
*
* Drupal's DocParser should never use class_exists() on an ignored
* annotation, including cases where namespaces are set.
*/
public function testIgnoredAnnotationSkippedBeforeReflection() {
$annotation = 'neverReflectThis';
$parser = new DocParser();
$parser->setIgnoredAnnotationNames([$annotation => TRUE]);
$parser->addNamespace('\\Arbitrary\\Namespace');
// Register our class loader which will fail if the parser tries to
// autoload disallowed annotations.
$autoloader = function ($class_name) use ($annotation) {
$name_array = explode('\\', $class_name);
$name = array_pop($name_array);
if ($name == $annotation) {
$this->fail('Attempted to autoload an ignored annotation: ' . $name);
}
};
spl_autoload_register($autoloader, TRUE, TRUE);
// Perform the parse.
$this->assertEmpty($parser->parse('@neverReflectThis'));
// Clean up after ourselves.
spl_autoload_unregister($autoloader);
}
}
<?php
// @codingStandardsIgnoreFile
namespace Drupal\Tests\Component\Annotation\Doctrine\Fixtures\Annotation;
/** @Annotation */
class AnnotWithDefaultValue
{
/** @var string */
public $foo = 'bar';
}
<?php
// @codingStandardsIgnoreFile
namespace Drupal\Tests\Component\Annotation\Doctrine\Fixtures\Annotation;
/**
* @Annotation
*/
class Autoload
{
}
<?php
// @codingStandardsIgnoreFile
namespace Drupal\Tests\Component\Annotation\Doctrine\Fixtures\Annotation;
/** @Annotation */
class Route
{
/** @var string @Required */
public $pattern;
public $name;
}
<?php
// @codingStandardsIgnoreFile
namespace Drupal\Tests\Component\Annotation\Doctrine\Fixtures\Annotation;
/** @Annotation */
class Secure
{
private $roles;
public function __construct(array $values)
{
if (is_string($values['value'])) {
$values['value'] = array($values['value']);
}
$this->roles = $values['value'];
}
}
<?php
// @codingStandardsIgnoreFile
namespace Drupal\Tests\Component\Annotation\Doctrine\Fixtures\Annotation;
/** @Annotation */
class Template
{
private $name;
public function __construct(array $values)
{
$this->name = isset($values['value']) ? $values['value'] : null;
}
}
<?php
// @codingStandardsIgnoreFile
namespace Drupal\Tests\Component\Annotation\Doctrine\Fixtures\Annotation;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class Version
{
}
<?php
// @codingStandardsIgnoreFile
namespace Drupal\Tests\Component\Annotation\Doctrine\Fixtures;
/**
* @Annotation
* @Target("ALL")
*/
final class AnnotationEnum
{
const ONE = 'ONE';
const TWO = 'TWO';
const THREE = 'THREE';
/**
* @var mixed
*
* @Enum({"ONE","TWO","THREE"})
*/
public $value;
}
<?php
// @codingStandardsIgnoreFile
namespace Drupal\Tests\Component\Annotation\Doctrine\Fixtures;
/**
* @Annotation
* @Target("ALL")
*/
final class AnnotationEnumInvalid
{
/**
* @var mixed
*
* @Enum({1, 2, "foo", "bar", {"foo":"bar"}})
*/
public $value;
}
<?php
// @codingStandardsIgnoreFile
namespace Drupal\Tests\Component\Annotation\Doctrine\Fixtures;
use Drupal\Tests\Component\Annotation\Doctrine\Fixtures\AnnotationEnumLiteral as SelfEnum;
/**
* @Annotation
* @Target("ALL")
*/
final class AnnotationEnumLiteral
{
const ONE = 1;
const TWO = 2;
const THREE = 3;
/**
* @var mixed
*
* @Enum(
* value = {
* 1,
* 2,
* 3,
* },
* literal = {
* 1 : "AnnotationEnumLiteral::ONE",
* 2 : "AnnotationEnumLiteral::TWO",
* 3 : "AnnotationEnumLiteral::THREE",
* }
* )
*/
public $value;
}
<?php
// @codingStandardsIgnoreFile
namespace Drupal\Tests\Component\Annotation\Doctrine\Fixtures;
/**
* @Annotation
* @Target("ALL")
*/
final class AnnotationEnumLiteralInvalid
{
const ONE = 1;
const TWO = 2;
const THREE = 3;
/**
* @var mixed
*
* @Enum(
* value = {
* 1,
* 2
* },
* literal = {
* 1 : "AnnotationEnumLiteral::ONE",
* 2 : "AnnotationEnumLiteral::TWO",
* 3 : "AnnotationEnumLiteral::THREE"
* }
* )
*/
public $value;
}
<?php
// @codingStandardsIgnoreFile
namespace Drupal\Tests\Component\Annotation\Doctrine\Fixtures;
/**
* @Annotation
* @Target("ALL")
*/
class AnnotationTargetAll
{
public $data;
public $name;
public $target;
}
<?php
// @codingStandardsIgnoreFile
namespace Drupal\Tests\Component\Annotation\Doctrine\Fixtures;
/**
* @Annotation
* @Target({ "ANNOTATION" })
*/
final class AnnotationTargetAnnotation
{
public $data;
public $name;
public $target;
}
<?php
// @codingStandardsIgnoreFile
namespace Drupal\Tests\Component\Annotation\Doctrine\Fixtures;
/**
* @Annotation
* @Target("CLASS")
*/
final class AnnotationTargetClass
{
public $data;
public $name;
public $target;
}
<?php
// @codingStandardsIgnoreFile
namespace Drupal\Tests\Component\Annotation\Doctrine\Fixtures;
/**
* @Annotation
* @Target({ "METHOD", "PROPERTY" })
*/
final class AnnotationTargetPropertyMethod
{
public $data;
public $name;
public $target;
}
<?php
// @codingStandardsIgnoreFile
namespace Drupal\Tests\Component\Annotation\Doctrine\Fixtures;
/**
* @Annotation
* @Target("ALL")
* @Attributes({
@Attribute("mixed", type = "mixed"),
@Attribute("boolean", type = "boolean"),
@Attribute("bool", type = "bool"),
@Attribute("float", type = "float"),
@Attribute("string", type = "string"),
@Attribute("integer", type = "integer"),
@Attribute("array", type = "array"),
@Attribute("arrayOfIntegers", type = "array<integer>"),
@Attribute("arrayOfStrings", type = "string[]"),
@Attribute("annotation", type = "Drupal\Tests\Component\Annotation\Doctrine\Fixtures\AnnotationTargetAll"),
@Attribute("arrayOfAnnotations", type = "array<Drupal\Tests\Component\Annotation\Doctrine\Fixtures\AnnotationTargetAll>"),
})
*/
final class AnnotationWithAttributes
{
public final function __construct(array $data)
{
foreach ($data as $key => $value) {
$this->$key = $value;
}
}
private $mixed;
private $boolean;
private $bool;
private $float;
private $string;
private $integer;
private $array;
private $annotation;
private $arrayOfIntegers;
private $arrayOfStrings;
private $arrayOfAnnotations;
/**
* @return mixed
*/
public function getMixed()
{
return $this->mixed;
}
/**
* @return boolean
*/
public function getBoolean()
{
return $this->boolean;
}
/**
* @return bool
*/
public function getBool()
{
return $this->bool;
}
/**
* @return float
*/
public function getFloat()
{
return $this->float;
}
/**
* @return string
*/
public function getString()
{
return $this->string;
}
public function getInteger()
{
return $this->integer;
}
/**
* @return array
*/
public function getArray()