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

DocParser can now ignore whole namespaces #45

Closed
wants to merge 3 commits into from
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
22 changes: 22 additions & 0 deletions lib/Doctrine/Common/Annotations/AnnotationReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,15 @@ class AnnotationReader implements Reader
'startuml' => true, 'enduml' => true,
);

/**
* A list with annotations that are not causing exceptions when not resolved to an annotation class.
*
* The names are case sensitive.
*
* @var array
*/
private static $globalIgnoredNamespaces = array();

/**
* Add a new annotation to the globally ignored annotation names with regard to exception handling.
*
Expand All @@ -112,6 +121,16 @@ static public function addGlobalIgnoredName($name)
self::$globalIgnoredNames[$name] = true;
}

/**
* Add a new annotation to the globally ignored annotation namespaces with regard to exception handling.
*
* @param string $namespace
*/
static public function addGlobalIgnoredNamespace($namespace)
{
self::$globalIgnoredNamespaces[$namespace] = true;
}

/**
* Annotations parser.
*
Expand Down Expand Up @@ -190,6 +209,7 @@ public function getClassAnnotations(ReflectionClass $class)
$this->parser->setTarget(Target::TARGET_CLASS);
$this->parser->setImports($this->getClassImports($class));
$this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($class));
$this->parser->setIgnoredAnnotationNamespaces(self::$globalIgnoredNamespaces);

return $this->parser->parse($class->getDocComment(), 'class ' . $class->getName());
}
Expand Down Expand Up @@ -221,6 +241,7 @@ public function getPropertyAnnotations(ReflectionProperty $property)
$this->parser->setTarget(Target::TARGET_PROPERTY);
$this->parser->setImports($this->getPropertyImports($property));
$this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($class));
$this->parser->setIgnoredAnnotationNamespaces(self::$globalIgnoredNamespaces);

return $this->parser->parse($property->getDocComment(), $context);
}
Expand Down Expand Up @@ -252,6 +273,7 @@ public function getMethodAnnotations(ReflectionMethod $method)
$this->parser->setTarget(Target::TARGET_METHOD);
$this->parser->setImports($this->getMethodImports($method));
$this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($class));
$this->parser->setIgnoredAnnotationNamespaces(self::$globalIgnoredNamespaces);

return $this->parser->parse($method->getDocComment(), $context);
}
Expand Down
28 changes: 28 additions & 0 deletions lib/Doctrine/Common/Annotations/DocParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,14 @@ final class DocParser
*/
private $ignoredAnnotationNames = array();

/**
* A list with annotations in namespaced format
* that are not causing exceptions when not resolved to an annotation class.
*
* @var array
*/
private $ignoredAnnotationNamespaces = array();

/**
* @var string
*/
Expand Down Expand Up @@ -251,6 +259,18 @@ public function setIgnoredAnnotationNames(array $names)
$this->ignoredAnnotationNames = $names;
}

/**
* Sets the annotation namespaces that are ignored during the parsing process.
*
* @param array $ignoredAnnotationNamespaces
*
* @return void
*/
public function setIgnoredAnnotationNamespaces($ignoredAnnotationNamespaces)
{
$this->ignoredAnnotationNamespaces = $ignoredAnnotationNamespaces;
}

/**
* Sets ignore on not-imported annotations.
*
Expand Down Expand Up @@ -700,6 +720,14 @@ private function Annotation()
return false;
}

foreach (array_keys($this->ignoredAnnotationNamespaces) as $ignoredAnnotationNamespace) {
$ignoredAnnotationNamespace = rtrim($ignoredAnnotationNamespace, '\\') . '\\';

if (0 === stripos($name, $ignoredAnnotationNamespace) || 0 === stripos($name . '\\', $ignoredAnnotationNamespace)) {
return false;
}
}

throw AnnotationException::semanticalError(sprintf('The annotation "@%s" in %s was never imported. Did you maybe forget to add a "use" statement for this annotation?', $name, $this->context));
}
}
Expand Down
56 changes: 55 additions & 1 deletion tests/Doctrine/Tests/Common/Annotations/AnnotationReaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,58 @@ public function testPropertyAnnotationFromTrait()
$this->assertInstanceOf('Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Autoload', $annotations[0]);
}

}
public function testClassAnnotationIsIgnored()
{
$reader = $this->getReader();
$ref = new \ReflectionClass('Doctrine\Tests\Common\Annotations\TestInvalidClassAnnotationClass');

$reader::addGlobalIgnoredNamespace('SomeClassAnnotationNamespace');

$annotations = $reader->getClassAnnotations($ref);

$this->assertEquals(0, count($annotations));
}

public function testMethodAnnotationIsIgnored()
{
$reader = $this->getReader();
$ref = new \ReflectionClass('Doctrine\Tests\Common\Annotations\TestInvalidMethodAnnotationClass');

$reader::addGlobalIgnoredNamespace('SomeMethodAnnotationNamespace');

$annotations = $reader->getMethodAnnotations($ref->getMethod('test'));

$this->assertEquals(0, count($annotations));
}

public function testPropertyAnnotationIsIgnored()
{
$reader = $this->getReader();
$ref = new \ReflectionClass('Doctrine\Tests\Common\Annotations\TestInvalidPropertyAnnotationClass');

$reader::addGlobalIgnoredNamespace('SomePropertyAnnotationNamespace');

$annotations = $reader->getPropertyAnnotations($ref->getProperty('field'));

$this->assertEquals(0, count($annotations));
}
}

/**
* @SomeClassAnnotationNamespace\Subnamespace\Name
*/
class TestInvalidClassAnnotationClass {}

class TestInvalidMethodAnnotationClass {
/**
* @SomeMethodAnnotationNamespace\Subnamespace\Name
*/
public function test() {}
}

class TestInvalidPropertyAnnotationClass {
/**
* @SomePropertyAnnotationNamespace\Subnamespace\Name
*/
private $field;
}
42 changes: 42 additions & 0 deletions tests/Doctrine/Tests/Common/Annotations/DocParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -993,6 +993,48 @@ public function testAnnotationWithoutClassIsIgnoredWithoutWarning()
$this->assertEquals(0, count($result));
}

/**
* Tests if it's possible to ignore whole namespaces
*
* @param $ignoreAnnotationName annotation/namespace to ignore
* @param $input annotation/namespace from the docblock
*
* @return void
*
* @dataProvider provideTestIgnoreWholeNamespaces
*/
public function testIgnoreWholeNamespaces($ignoreAnnotationName, $input)
{
$parser = new DocParser();
$parser->setIgnoredAnnotationNamespaces(array($ignoreAnnotationName => true));
$result = $parser->parse($input);

$this->assertEquals(0, count($result));
}

public function provideTestIgnoreWholeNamespaces()
{
return array(
array('Namespace', '@Namespace'),
array('Namespace\\', '@Namespace'),

array('Namespace', '@Namespace\Subnamespace'),
array('Namespace\\', '@Namespace\Subnamespace'),

array('Namespace', '@Namespace\Subnamespace\SubSubNamespace'),
array('Namespace\\', '@Namespace\Subnamespace\SubSubNamespace'),

array('Namespace\Subnamespace', '@Namespace\Subnamespace'),
array('Namespace\Subnamespace\\', '@Namespace\Subnamespace'),

array('Namespace\Subnamespace', '@Namespace\Subnamespace\SubSubNamespace'),
array('Namespace\Subnamespace\\', '@Namespace\Subnamespace\SubSubNamespace'),

array('Namespace\Subnamespace\SubSubNamespace', '@Namespace\Subnamespace\SubSubNamespace'),
array('Namespace\Subnamespace\SubSubNamespace\\', '@Namespace\Subnamespace\SubSubNamespace'),
);
}

/**
* @group DCOM-168
*/
Expand Down