This file was deleted.

@@ -0,0 +1,151 @@
<?php
namespace WhiteBox\Routing\Controllers;


use Doctrine\Common\Annotations\Annotation;
use Doctrine\Common\Annotations\AnnotationException;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\IndexedReader;
use ReflectionClass;
use ReflectionMethod;
use WhiteBox\Helpers\RegexHandler;
use WhiteBox\Routing\Abstractions\A_CisRouter;
use WhiteBox\Routing\Abstractions\T_NamedRedirectionManager;
use WhiteBox\Routing\Controllers\Routing;
use WhiteBox\Routing\Controllers\SubRouting;
use WhiteBox\Routing\Route;

/**
* Class A_ControllerSubRouter
* @package WhiteBox\Routing
*/
abstract class A_ControllerSubRouter extends A_CisRouter{
use T_NamedRedirectionManager;

protected $annotationsReader;

/**
* A_ControllerSubRouter constructor.
* @param callable|null $defaultAuthMW
* @throws AnnotationException
*/
public function __construct(?callable $defaultAuthMW = null) {
$this->annotationsReader = new IndexedReader(new AnnotationReader());
parent::__construct($this->getPrefix(), $defaultAuthMW);
}

/**
* @return string
* @throws AnnotationException
*/
public function getPrefix(): string {
$ThisClass = new ReflectionClass(static::class);
$subRoutingAnnotation = $this->annotationsReader->getClassAnnotation($ThisClass, SubRouting::class);

if(is_null($subRoutingAnnotation))
throw new AnnotationException("There is no SubRouting annotation found for this controller");

return $subRoutingAnnotation->prefix;
}

/**
* @return array
*/
public function getRoutes(): array {
$routeRefMethods = $this->getRouteMethods();
$routings = array_map(function(ReflectionMethod $method){
$annotations = $this->annotationsReader->getMethodAnnotations($method);
foreach($annotations as $annotation){
if($annotation instanceof Routing)
return ["annotation"=>$annotation, "methodName"=>$method->getName()];
}
return null;
}, $routeRefMethods);
$routings = array_filter($routings, function($elem){
return !is_null($elem);
});

return array_map(function(array $routing): Route{
/**
* @var Routing
*/
$annotation = $routing["annotation"];
$methodName = $routing["methodName"];

return (new Route($annotation->method, $annotation->uri, [$this, $methodName], $this->getDefaultAuthMiddleware()))
->name($annotation->name);
}, $routings);
}

/**
* @return ReflectionMethod[]
*/
protected function getRouteMethods(): array{
$ThisClass = new ReflectionClass(static::class);
$publics = $ThisClass->getMethods(ReflectionMethod::IS_PUBLIC);
return array_filter($publics, function(ReflectionMethod $method){
$annotations = $this->annotationsReader->getMethodAnnotations($method);
return array_reduce($annotations, function(bool $acc, $annotation){
return $acc || ($annotation instanceof Routing);
}, false);
});
}

protected function hasRoute(string $method, string $re): bool {
$paramRoute = new Route($method, $re);
foreach($this->getRoutes() as $route){
if($paramRoute->equals($route))
return true;
}
return false;
}

protected function getRoute(string $method, string $re): ?Route {
$paramRoute = new Route($method, $re);
foreach($this->getRoutes() as $route){
if($paramRoute->equals($route))
return $route;
}
return null;
}

protected function addRoute(Route $route) {
$this->routes[] = $route;
}

/**
* @param string $method
* @return array
* @throws AnnotationException
*/
protected function getRoutesForMethod(string $method): array {
return array_filter($this->getRoutes(), function(Route $route) use($method){
return $route->method() === $method;
});
}

protected function setupRoute(string $method, string $re, callable $functor, ?callable $authMiddleware = null): Route {
if ($this->hasRoute($method, $re)) {
$route = $this->getRoute($method, $re);
if (!is_null($route)) {
$route->setHandler($functor);

if (!is_null($authMiddleware))
$route->setAuthMiddleware($authMiddleware);
}

return $route;
//throw new Exception("It is impossible to override/declare twice a single Route");
}
//otherwise
//push it to the arrays
$route = new Route($method, $re);
$this->addRoute($route);
$route->setHandler($functor);

if (!is_null($authMiddleware))
$route->setAuthMiddleware($authMiddleware);

return $route;
}
}
@@ -0,0 +1,39 @@
<?php
namespace WhiteBox\Routing\Controllers;
use Doctrine\Common\Annotations\Annotation;
use Doctrine\Common\Annotations\Annotation\Required;
use Doctrine\Common\Annotations\Annotation\Target;
use Doctrine\Common\Annotations\AnnotationException;
use Doctrine\Common\Annotations\AnnotationRegistry;
use PHPUnit\Runner\Exception;

/**
* Class Routing
* @package WhiteBox\Routing\Controllers
* @Annotation
* @Target("METHOD")
*/
class Routing{
/**
* @var string
* @Required
*/
public $method;

/**
* @var string
* @Required
*/
public $uri;

/**
* @var string
*/
public $name;

public function __construct(array $values) {
$this->method = $values["method"];
$this->uri = $values["uri"];
$this->name = isset($values["name"]) ? $values["name"] : null;
}
}
@@ -0,0 +1,21 @@
<?php
namespace WhiteBox\Routing\Controllers;
use Doctrine\Common\Annotations\Annotation;
use Doctrine\Common\Annotations\Annotation\Required;
use Doctrine\Common\Annotations\Annotation\Target;
use Doctrine\Common\Annotations\AnnotationException;
use Doctrine\Common\Annotations\AnnotationRegistry;

/**
* Class SubRouting
* @package WhiteBox\Routing\Controllers
* @Annotation
* @Target("CLASS")
*/
class SubRouting extends Annotation{
/**
* @var string
* @Required
*/
public $prefix;
}
@@ -1,6 +1,7 @@
<?php
use PHPUnit\Framework\TestCase as PHPUnit;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use WhiteBox\App;
use WhiteBox\Middlewares\A_Middleware;
@@ -41,8 +42,8 @@ protected function getLength(MiddlewareHub $hub=null) : int{
*/
public function canAddMiddlewareIfNone(){
$this->hub->pipe(new class extends A_Middleware{
public function process(ServerRequestInterface $rq, ?A_Middleware $next, App $app) {
return "true";
public function process(ServerRequestInterface $rq, ResponseInterface $res, callable $next): ResponseInterface {
return $res;
}
});

@@ -89,20 +90,20 @@ public function cantAddTwiceFromSameMiddlewareClass(){

class MiddlewareA extends A_Middleware{

public function process(ServerRequestInterface $rq, ?A_Middleware $next) {
return $this;
public function process(ServerRequestInterface $rq, ResponseInterface $res, callable $next): ResponseInterface {
return $res;
}
}

class MiddlewareB extends A_Middleware{

public function process(ServerRequestInterface $rq, ?A_Middleware $next) {
return $this;
public function process(ServerRequestInterface $rq, ResponseInterface $res, callable $next): ResponseInterface {
return $res;
}
}

class MiddlewareC extends MiddlewareB{
public function process(ServerRequestInterface $rq, ?A_Middleware $next) {
return $this;
public function process(ServerRequestInterface $rq, ResponseInterface $res, callable $next): ResponseInterface {
return $res;
}
}
@@ -1,6 +1,7 @@
<?php
namespace Test\Routing;

use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Psr7\Uri;
use phpmock\MockBuilder;
use PHPUnit\Framework\TestCase as PHPUnit;
@@ -106,24 +107,13 @@ public function urlWithParamsForExistingRoute(){
* @covers Router::redirect
*/
public function redirectRedirects(){
$mock = self::mock(
"header",
function(string $str){
//return "{$str}";
self::$location = $str;
},
self::$NAMESPACE
);

$mock->enable();
$app = new Router();
$app->redirect("/");
self::assertEquals(
"Location: /",
self::$location,
$res = $app->redirect("/", new Response());
self::assertContains(
"/",
$res->getHeader("Location"),
"The redirection fails : wrong url assigned"
);
$mock->disable();
}

/**
@@ -133,27 +123,15 @@ function(string $str){
* @covers Router::redirectTo
*/
public function redirectsToWorksProperly(){
$mock = self::mock(
"header",
function(string $str){
//return "{$str}";
self::$location = $str;
},
self::$NAMESPACE
);
$mock->enable();

$app = new Router();
$app->get("/", function(){})->name("unit.test");

$app->redirectTo("unit.test");
self::assertEquals(
"Location: /",
self::$location,
$res = $app->redirectTo("unit.test", new Response());
self::assertContains(
"/",
$res->getHeader("Location"),
"Something wrong happens while redirecting from a route's name"
);

$mock->disable();
}

/**
@@ -372,7 +350,7 @@ public function handleRequestDispatchesTo404IfNoMatch(){
return $errMsg;
});

self::assertEquals($errMsg, $handleRequest->invoke($app, new FakeRequest()));
self::assertStringStartsWith($errMsg, $handleRequest->invoke($app, new FakeRequest(), new Response())->getBody()->__toString());
}
}

@@ -7,4 +7,5 @@

return array(
'Prophecy\\' => array($vendorDir . '/phpspec/prophecy/src'),
'Doctrine\\Common\\Lexer\\' => array($vendorDir . '/doctrine/lexer/lib'),
);
@@ -14,5 +14,6 @@
'MyCLabs\\Enum\\' => array($vendorDir . '/myclabs/php-enum/src'),
'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
'Doctrine\\Instantiator\\' => array($vendorDir . '/doctrine/instantiator/src/Doctrine/Instantiator'),
'Doctrine\\Common\\Annotations\\' => array($vendorDir . '/doctrine/annotations/lib/Doctrine/Common/Annotations'),
'DeepCopy\\' => array($vendorDir . '/myclabs/deep-copy/src/DeepCopy'),
);
@@ -38,6 +38,7 @@ class ComposerStaticInit6b024b2187000fc3792cb82eb9ea7951
'D' =>
array (
'Doctrine\\Instantiator\\' => 22,
'Doctrine\\Common\\Annotations\\' => 28,
'DeepCopy\\' => 9,
),
);
@@ -78,6 +79,10 @@ class ComposerStaticInit6b024b2187000fc3792cb82eb9ea7951
array (
0 => __DIR__ . '/..' . '/doctrine/instantiator/src/Doctrine/Instantiator',
),
'Doctrine\\Common\\Annotations\\' =>
array (
0 => __DIR__ . '/..' . '/doctrine/annotations/lib/Doctrine/Common/Annotations',
),
'DeepCopy\\' =>
array (
0 => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy',
@@ -92,6 +97,13 @@ class ComposerStaticInit6b024b2187000fc3792cb82eb9ea7951
0 => __DIR__ . '/..' . '/phpspec/prophecy/src',
),
),
'D' =>
array (
'Doctrine\\Common\\Lexer\\' =>
array (
0 => __DIR__ . '/..' . '/doctrine/lexer/lib',
),
),
);

public static $classMap = array (
@@ -1777,5 +1777,131 @@
}
],
"description": "A function to convert PSR-7 Response to HTTP output"
},
{
"name": "doctrine/lexer",
"version": "v1.0.1",
"version_normalized": "1.0.1.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/lexer.git",
"reference": "83893c552fd2045dd78aef794c31e694c37c0b8c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c",
"reference": "83893c552fd2045dd78aef794c31e694c37c0b8c",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"time": "2014-09-09T13:34:57+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-0": {
"Doctrine\\Common\\Lexer\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"lexer",
"parser"
]
},
{
"name": "doctrine/annotations",
"version": "v1.6.0",
"version_normalized": "1.6.0.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/annotations.git",
"reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5",
"reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5",
"shasum": ""
},
"require": {
"doctrine/lexer": "1.*",
"php": "^7.1"
},
"require-dev": {
"doctrine/cache": "1.*",
"phpunit/phpunit": "^6.4"
},
"time": "2017-12-06T07:11:42+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.6.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Docblock Annotations Parser",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"annotations",
"docblock",
"parser"
]
}
]
@@ -0,0 +1,130 @@
## Changelog

### 1.5.0

This release increments the minimum supported PHP version to 7.1.0.

Also, HHVM official support has been dropped.

Some noticeable performance improvements to annotation autoloading
have been applied, making failed annotation autoloading less heavy
on the filesystem access.

- [133: Add @throws annotation in AnnotationReader#__construct()](https://github.com/doctrine/annotations/issues/133) thanks to @SenseException
- [134: Require PHP 7.1, drop HHVM support](https://github.com/doctrine/annotations/issues/134) thanks to @lcobucci
- [135: Prevent the same loader from being registered twice](https://github.com/doctrine/annotations/issues/135) thanks to @jrjohnson
- [137: #135 optimise multiple class load attempts in AnnotationRegistry](https://github.com/doctrine/annotations/issues/137) thanks to @Ocramius


### 1.4.0

This release fix an issue were some annotations could be not loaded if the namespace in the use statement started with a backslash.
It also update the tests and drop the support for php 5.X

- [115: Missing annotations with the latest composer version](https://github.com/doctrine/annotations/issues/115) thanks to @pascalporedda
- [120: Missing annotations with the latest composer version](https://github.com/doctrine/annotations/pull/120) thanks to @gnat42
- [121: Adding a more detailed explanation of the test](https://github.com/doctrine/annotations/pull/121) thanks to @mikeSimonson
- [101: Test annotation parameters containing space](https://github.com/doctrine/annotations/pull/101) thanks to @mikeSimonson
- [111: Cleanup: move to correct phpunit assertions](https://github.com/doctrine/annotations/pull/111) thanks to @Ocramius
- [112: Removes support for PHP 5.x](https://github.com/doctrine/annotations/pull/112) thanks to @railto
- [113: bumped phpunit version to 5.7](https://github.com/doctrine/annotations/pull/113) thanks to @gabbydgab
- [114: Enhancement: Use SVG Travis build badge](https://github.com/doctrine/annotations/pull/114) thanks to @localheinz
- [118: Integrating PHPStan](https://github.com/doctrine/annotations/pull/118) thanks to @ondrejmirtes

### 1.3.1 - 2016-12-30

This release fixes an issue with ignored annotations that were already
autoloaded, causing the `SimpleAnnotationReader` to pick them up
anyway. [#110](https://github.com/doctrine/annotations/pull/110)

Additionally, an issue was fixed in the `CachedReader`, which was
not correctly checking the freshness of cached annotations when
traits were defined on a class. [#105](https://github.com/doctrine/annotations/pull/105)

Total issues resolved: **2**

- [105: Return single max timestamp](https://github.com/doctrine/annotations/pull/105)
- [110: setIgnoreNotImportedAnnotations(true) didn&rsquo;t work for existing classes](https://github.com/doctrine/annotations/pull/110)

### 1.3.0

This release introduces a PHP version bump. `doctrine/annotations` now requires PHP
5.6 or later to be installed.

A series of additional improvements have been introduced:

* support for PHP 7 "grouped use statements"
* support for ignoring entire namespace names
via `Doctrine\Common\Annotations\AnnotationReader::addGlobalIgnoredNamespace()` and
`Doctrine\Common\Annotations\DocParser::setIgnoredAnnotationNamespaces()`. This will
allow you to ignore annotations from namespaces that you cannot autoload
* testing all parent classes and interfaces when checking if the annotation cache
in the `CachedReader` is fresh
* simplifying the cache keys used by the `CachedReader`: keys are no longer artificially
namespaced, since `Doctrine\Common\Cache` already supports that
* corrected parsing of multibyte strings when `mbstring.func_overload` is enabled
* corrected parsing of annotations when `"\t"` is put before the first annotation
in a docblock
* allow skipping non-imported annotations when a custom `DocParser` is passed to
the `AnnotationReader` constructor

Total issues resolved: **15**

- [45: DocParser can now ignore whole namespaces](https://github.com/doctrine/annotations/pull/45)
- [57: Switch to the docker-based infrastructure on Travis](https://github.com/doctrine/annotations/pull/57)
- [59: opcache.load&#95;comments has been removed from PHP 7](https://github.com/doctrine/annotations/pull/59)
- [62: &#91;CachedReader&#92; Test traits and parent class to see if cache is fresh](https://github.com/doctrine/annotations/pull/62)
- [65: Remove cache salt making key unnecessarily long](https://github.com/doctrine/annotations/pull/65)
- [66: Fix of incorrect parsing multibyte strings](https://github.com/doctrine/annotations/pull/66)
- [68: Annotations that are indented by tab are not processed.](https://github.com/doctrine/annotations/issues/68)
- [69: Support for Group Use Statements](https://github.com/doctrine/annotations/pull/69)
- [70: Allow tab character before first annotation in DocBlock](https://github.com/doctrine/annotations/pull/70)
- [74: Ignore not registered annotations fix](https://github.com/doctrine/annotations/pull/74)
- [92: Added tests for AnnotationRegistry class.](https://github.com/doctrine/annotations/pull/92)
- [96: Fix/#62 check trait and parent class ttl in annotations](https://github.com/doctrine/annotations/pull/96)
- [97: Feature - #45 - allow ignoring entire namespaces](https://github.com/doctrine/annotations/pull/97)
- [98: Enhancement/#65 remove cache salt from cached reader](https://github.com/doctrine/annotations/pull/98)
- [99: Fix - #70 - allow tab character before first annotation in docblock](https://github.com/doctrine/annotations/pull/99)

### 1.2.4

Total issues resolved: **1**

- [51: FileCacheReader::saveCacheFile::unlink fix](https://github.com/doctrine/annotations/pull/51)

### 1.2.3

Total issues resolved: [**2**](https://github.com/doctrine/annotations/milestones/v1.2.3)

- [49: #46 - applying correct `chmod()` to generated cache file](https://github.com/doctrine/annotations/pull/49)
- [50: Hotfix: match escaped quotes (revert #44)](https://github.com/doctrine/annotations/pull/50)

### 1.2.2

Total issues resolved: **4**

- [43: Exclude files from distribution with .gitattributes](https://github.com/doctrine/annotations/pull/43)
- [44: Update DocLexer.php](https://github.com/doctrine/annotations/pull/44)
- [46: A plain &quot;file&#95;put&#95;contents&quot; can cause havoc](https://github.com/doctrine/annotations/pull/46)
- [48: Deprecating the `FileCacheReader` in 1.2.2: will be removed in 2.0.0](https://github.com/doctrine/annotations/pull/48)

### 1.2.1

Total issues resolved: **4**

- [38: fixes doctrine/common#326](https://github.com/doctrine/annotations/pull/38)
- [39: Remove superfluous NS](https://github.com/doctrine/annotations/pull/39)
- [41: Warn if load_comments is not enabled.](https://github.com/doctrine/annotations/pull/41)
- [42: Clean up unused uses](https://github.com/doctrine/annotations/pull/42)

### 1.2.0

* HHVM support
* Allowing dangling comma in annotations
* Excluded annotations are no longer autoloaded
* Importing namespaces also in traits
* Added support for `::class` 5.5-style constant, works also in 5.3 and 5.4

### 1.1.0

* Add Exception when ZendOptimizer+ or Opcache is configured to drop comments
@@ -0,0 +1,19 @@
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.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,17 @@
# Doctrine Annotations

[![Build Status](https://travis-ci.org/doctrine/annotations.svg?branch=master)](https://travis-ci.org/doctrine/annotations)
[![Dependency Status](https://www.versioneye.com/package/php--doctrine--annotations/badge.png)](https://www.versioneye.com/package/php--doctrine--annotations)
[![Reference Status](https://www.versioneye.com/php/doctrine:annotations/reference_badge.svg)](https://www.versioneye.com/php/doctrine:annotations/references)
[![Total Downloads](https://poser.pugx.org/doctrine/annotations/downloads.png)](https://packagist.org/packages/doctrine/annotations)
[![Latest Stable Version](https://poser.pugx.org/doctrine/annotations/v/stable.png)](https://packagist.org/packages/doctrine/annotations)

Docblock Annotations Parser library (extracted from [Doctrine Common](https://github.com/doctrine/common)).

## Documentation

See the [doctrine-project website](http://docs.doctrine-project.org/projects/doctrine-common/en/latest/reference/annotations.html).

## Changelog

See [CHANGELOG.md](CHANGELOG.md).
@@ -0,0 +1,34 @@
{
"name": "doctrine/annotations",
"type": "library",
"description": "Docblock Annotations Parser",
"keywords": ["annotations", "docblock", "parser"],
"homepage": "http://www.doctrine-project.org",
"license": "MIT",
"authors": [
{"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"},
{"name": "Roman Borschel", "email": "roman@code-factory.org"},
{"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"},
{"name": "Jonathan Wage", "email": "jonwage@gmail.com"},
{"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"}
],
"require": {
"php": "^7.1",
"doctrine/lexer": "1.*"
},
"require-dev": {
"doctrine/cache": "1.*",
"phpunit/phpunit": "^6.4"
},
"autoload": {
"psr-4": { "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" }
},
"autoload-dev": {
"psr-4": { "Doctrine\\Tests\\Common\\Annotations\\": "tests/Doctrine/Tests/Common/Annotations" }
},
"extra": {
"branch-alias": {
"dev-master": "1.6.x-dev"
}
}
}
@@ -0,0 +1,79 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\Common\Annotations;

/**
* Annotations class.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
*/
class Annotation
{
/**
* Value property. Common among all derived classes.
*
* @var string
*/
public $value;

/**
* Constructor.
*
* @param array $data Key-value for properties to be defined in this class.
*/
public final function __construct(array $data)
{
foreach ($data as $key => $value) {
$this->$key = $value;
}
}

/**
* Error handler for unknown property accessor in Annotation class.
*
* @param string $name Unknown property name.
*
* @throws \BadMethodCallException
*/
public function __get($name)
{
throw new \BadMethodCallException(
sprintf("Unknown property '%s' on annotation '%s'.", $name, get_class($this))
);
}

/**
* Error handler for unknown property mutator in Annotation class.
*
* @param string $name Unknown property name.
* @param mixed $value Property value.
*
* @throws \BadMethodCallException
*/
public function __set($name, $value)
{
throw new \BadMethodCallException(
sprintf("Unknown property '%s' on annotation '%s'.", $name, get_class($this))
);
}
}
@@ -0,0 +1,47 @@
<?php

/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\Common\Annotations\Annotation;

/**
* Annotation that can be used to signal to the parser
* to check the attribute type during the parsing process.
*
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*
* @Annotation
*/
final class Attribute
{
/**
* @var string
*/
public $name;

/**
* @var string
*/
public $type;

/**
* @var boolean
*/
public $required = false;
}
@@ -0,0 +1,37 @@
<?php

/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\Common\Annotations\Annotation;

/**
* Annotation that can be used to signal to the parser
* to check the types of all declared attributes during the parsing process.
*
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*
* @Annotation
*/
final class Attributes
{
/**
* @var array<Doctrine\Common\Annotations\Annotation\Attribute>
*/
public $value;
}
@@ -0,0 +1,84 @@
<?php

/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\Common\Annotations\Annotation;

/**
* Annotation that can be used to signal to the parser
* to check the available values during the parsing process.
*
* @since 2.4
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*
* @Annotation
* @Attributes({
* @Attribute("value", required = true, type = "array"),
* @Attribute("literal", required = false, type = "array")
* })
*/
final class Enum
{
/**
* @var array
*/
public $value;

/**
* Literal target declaration.
*
* @var array
*/
public $literal;

/**
* Annotation constructor.
*
* @param array $values
*
* @throws \InvalidArgumentException
*/
public function __construct(array $values)
{
if ( ! isset($values['literal'])) {
$values['literal'] = array();
}

foreach ($values['value'] as $var) {
if( ! is_scalar($var)) {
throw new \InvalidArgumentException(sprintf(
'@Enum supports only scalar values "%s" given.',
is_object($var) ? get_class($var) : gettype($var)
));
}
}

foreach ($values['literal'] as $key => $var) {
if( ! in_array($key, $values['value'])) {
throw new \InvalidArgumentException(sprintf(
'Undefined enumerator value "%s" for literal "%s".',
$key , $var
));
}
}

$this->value = $values['value'];
$this->literal = $values['literal'];
}
}
@@ -0,0 +1,54 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\Common\Annotations\Annotation;

/**
* Annotation that can be used to signal to the parser to ignore specific
* annotations during the parsing process.
*
* @Annotation
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
final class IgnoreAnnotation
{
/**
* @var array
*/
public $names;

/**
* Constructor.
*
* @param array $values
*
* @throws \RuntimeException
*/
public function __construct(array $values)
{
if (is_string($values['value'])) {
$values['value'] = array($values['value']);
}
if (!is_array($values['value'])) {
throw new \RuntimeException(sprintf('@IgnoreAnnotation expects either a string name, or an array of strings, but got %s.', json_encode($values['value'])));
}

$this->names = $values['value'];
}
}
@@ -0,0 +1,33 @@
<?php

/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\Common\Annotations\Annotation;

/**
* Annotation that can be used to signal to the parser
* to check if that attribute is required during the parsing process.
*
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*
* @Annotation
*/
final class Required
{
}
@@ -0,0 +1,107 @@
<?php

/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\Common\Annotations\Annotation;

/**
* Annotation that can be used to signal to the parser
* to check the annotation target during the parsing process.
*
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*
* @Annotation
*/
final class Target
{
const TARGET_CLASS = 1;
const TARGET_METHOD = 2;
const TARGET_PROPERTY = 4;
const TARGET_ANNOTATION = 8;
const TARGET_ALL = 15;

/**
* @var array
*/
private static $map = array(
'ALL' => self::TARGET_ALL,
'CLASS' => self::TARGET_CLASS,
'METHOD' => self::TARGET_METHOD,
'PROPERTY' => self::TARGET_PROPERTY,
'ANNOTATION' => self::TARGET_ANNOTATION,
);

/**
* @var array
*/
public $value;

/**
* Targets as bitmask.
*
* @var integer
*/
public $targets;

/**
* Literal target declaration.
*
* @var integer
*/
public $literal;

/**
* Annotation constructor.
*
* @param array $values
*
* @throws \InvalidArgumentException
*/
public function __construct(array $values)
{
if (!isset($values['value'])){
$values['value'] = null;
}
if (is_string($values['value'])){
$values['value'] = array($values['value']);
}
if (!is_array($values['value'])){
throw new \InvalidArgumentException(
sprintf('@Target expects either a string value, or an array of strings, "%s" given.',
is_object($values['value']) ? get_class($values['value']) : gettype($values['value'])
)
);
}

$bitmask = 0;
foreach ($values['value'] as $literal) {
if(!isset(self::$map[$literal])){
throw new \InvalidArgumentException(
sprintf('Invalid Target "%s". Available targets: [%s]',
$literal, implode(', ', array_keys(self::$map)))
);
}
$bitmask |= self::$map[$literal];
}

$this->targets = $bitmask;
$this->value = $values['value'];
$this->literal = implode(', ', $this->value);
}
}
@@ -0,0 +1,197 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\Common\Annotations;

/**
* Description of AnnotationException
*
* @since 2.0
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
*/
class AnnotationException extends \Exception
{
/**
* Creates a new AnnotationException describing a Syntax error.
*
* @param string $message Exception message
*
* @return AnnotationException
*/
public static function syntaxError($message)
{
return new self('[Syntax Error] ' . $message);
}

/**
* Creates a new AnnotationException describing a Semantical error.
*
* @param string $message Exception message
*
* @return AnnotationException
*/
public static function semanticalError($message)
{
return new self('[Semantical Error] ' . $message);
}

/**
* Creates a new AnnotationException describing an error which occurred during
* the creation of the annotation.
*
* @since 2.2
*
* @param string $message
*
* @return AnnotationException
*/
public static function creationError($message)
{
return new self('[Creation Error] ' . $message);
}

/**
* Creates a new AnnotationException describing a type error.
*
* @since 1.1
*
* @param string $message
*
* @return AnnotationException
*/
public static function typeError($message)
{
return new self('[Type Error] ' . $message);
}

/**
* Creates a new AnnotationException describing a constant semantical error.
*
* @since 2.3
*
* @param string $identifier
* @param string $context
*
* @return AnnotationException
*/
public static function semanticalErrorConstants($identifier, $context = null)
{
return self::semanticalError(sprintf(
"Couldn't find constant %s%s.",
$identifier,
$context ? ', ' . $context : ''
));
}

/**
* Creates a new AnnotationException describing an type error of an attribute.
*
* @since 2.2
*
* @param string $attributeName
* @param string $annotationName
* @param string $context
* @param string $expected
* @param mixed $actual
*
* @return AnnotationException
*/
public static function attributeTypeError($attributeName, $annotationName, $context, $expected, $actual)
{
return self::typeError(sprintf(
'Attribute "%s" of @%s declared on %s expects %s, but got %s.',
$attributeName,
$annotationName,
$context,
$expected,
is_object($actual) ? 'an instance of ' . get_class($actual) : gettype($actual)
));
}

/**
* Creates a new AnnotationException describing an required error of an attribute.
*
* @since 2.2
*
* @param string $attributeName
* @param string $annotationName
* @param string $context
* @param string $expected
*
* @return AnnotationException
*/
public static function requiredError($attributeName, $annotationName, $context, $expected)
{
return self::typeError(sprintf(
'Attribute "%s" of @%s declared on %s expects %s. This value should not be null.',
$attributeName,
$annotationName,
$context,
$expected
));
}

/**
* Creates a new AnnotationException describing a invalid enummerator.
*
* @since 2.4
*
* @param string $attributeName
* @param string $annotationName
* @param string $context
* @param array $available
* @param mixed $given
*
* @return AnnotationException
*/
public static function enumeratorError($attributeName, $annotationName, $context, $available, $given)
{
return new self(sprintf(
'[Enum Error] Attribute "%s" of @%s declared on %s accept only [%s], but got %s.',
$attributeName,
$annotationName,
$context,
implode(', ', $available),
is_object($given) ? get_class($given) : $given
));
}

/**
* @return AnnotationException
*/
public static function optimizerPlusSaveComments()
{
return new self(
"You have to enable opcache.save_comments=1 or zend_optimizerplus.save_comments=1."
);
}

/**
* @return AnnotationException
*/
public static function optimizerPlusLoadComments()
{
return new self(
"You have to enable opcache.load_comments=1 or zend_optimizerplus.load_comments=1."
);
}
}

Large diffs are not rendered by default.

@@ -0,0 +1,174 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\Common\Annotations;

final class AnnotationRegistry
{
/**
* A map of namespaces to use for autoloading purposes based on a PSR-0 convention.
*
* Contains the namespace as key and an array of directories as value. If the value is NULL
* the include path is used for checking for the corresponding file.
*
* This autoloading mechanism does not utilize the PHP autoloading but implements autoloading on its own.
*
* @var string[][]|string[]|null[]
*/
static private $autoloadNamespaces = [];

/**
* A map of autoloader callables.
*
* @var callable[]
*/
static private $loaders = [];

/**
* An array of classes which cannot be found
*
* @var null[] indexed by class name
*/
static private $failedToAutoload = [];

public static function reset() : void
{
self::$autoloadNamespaces = [];
self::$loaders = [];
self::$failedToAutoload = [];
}

/**
* Registers file.
*
* @deprecated this method is deprecated and will be removed in doctrine/annotations 2.0
* autoloading should be deferred to the globally registered autoloader by then. For now,
* use @example AnnotationRegistry::registerLoader('class_exists')
*/
public static function registerFile(string $file) : void
{
require_once $file;
}

/**
* Adds a namespace with one or many directories to look for files or null for the include path.
*
* Loading of this namespaces will be done with a PSR-0 namespace loading algorithm.
*
* @param string $namespace
* @param string|array|null $dirs
*
* @deprecated this method is deprecated and will be removed in doctrine/annotations 2.0
* autoloading should be deferred to the globally registered autoloader by then. For now,
* use @example AnnotationRegistry::registerLoader('class_exists')
*/
public static function registerAutoloadNamespace(string $namespace, $dirs = null) : void
{
self::$autoloadNamespaces[$namespace] = $dirs;
}

/**
* Registers multiple namespaces.
*
* Loading of this namespaces will be done with a PSR-0 namespace loading algorithm.
*
* @param string[][]|string[]|null[] $namespaces indexed by namespace name
*
* @deprecated this method is deprecated and will be removed in doctrine/annotations 2.0
* autoloading should be deferred to the globally registered autoloader by then. For now,
* use @example AnnotationRegistry::registerLoader('class_exists')
*/
public static function registerAutoloadNamespaces(array $namespaces) : void
{
self::$autoloadNamespaces = \array_merge(self::$autoloadNamespaces, $namespaces);
}

/**
* Registers an autoloading callable for annotations, much like spl_autoload_register().
*
* NOTE: These class loaders HAVE to be silent when a class was not found!
* IMPORTANT: Loaders have to return true if they loaded a class that could contain the searched annotation class.
*
* @deprecated this method is deprecated and will be removed in doctrine/annotations 2.0
* autoloading should be deferred to the globally registered autoloader by then. For now,
* use @example AnnotationRegistry::registerLoader('class_exists')
*/
public static function registerLoader(callable $callable) : void
{
// Reset our static cache now that we have a new loader to work with
self::$failedToAutoload = [];
self::$loaders[] = $callable;
}

/**
* Registers an autoloading callable for annotations, if it is not already registered
*
* @deprecated this method is deprecated and will be removed in doctrine/annotations 2.0
*/
public static function registerUniqueLoader(callable $callable) : void
{
if ( ! in_array($callable, self::$loaders, true) ) {
self::registerLoader($callable);
}
}

/**
* Autoloads an annotation class silently.
*/
public static function loadAnnotationClass(string $class) : bool
{
if (\class_exists($class, false)) {
return true;
}

if (\array_key_exists($class, self::$failedToAutoload)) {
return false;
}

foreach (self::$autoloadNamespaces AS $namespace => $dirs) {
if (\strpos($class, $namespace) === 0) {
$file = \str_replace('\\', \DIRECTORY_SEPARATOR, $class) . '.php';

if ($dirs === null) {
if ($path = stream_resolve_include_path($file)) {
require $path;
return true;
}
} else {
foreach((array) $dirs AS $dir) {
if (is_file($dir . \DIRECTORY_SEPARATOR . $file)) {
require $dir . \DIRECTORY_SEPARATOR . $file;
return true;
}
}
}
}
}

foreach (self::$loaders AS $loader) {
if ($loader($class) === true) {
return true;
}
}

self::$failedToAutoload[$class] = null;

return false;
}
}
@@ -0,0 +1,262 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\Common\Annotations;

use Doctrine\Common\Cache\Cache;
use ReflectionClass;

/**
* A cache aware annotation reader.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
final class CachedReader implements Reader
{
/**
* @var Reader
*/
private $delegate;

/**
* @var Cache
*/
private $cache;

/**
* @var boolean
*/
private $debug;

/**
* @var array
*/
private $loadedAnnotations = array();

/**
* Constructor.
*
* @param Reader $reader
* @param Cache $cache
* @param bool $debug
*/
public function __construct(Reader $reader, Cache $cache, $debug = false)
{
$this->delegate = $reader;
$this->cache = $cache;
$this->debug = (boolean) $debug;
}

/**
* {@inheritDoc}
*/
public function getClassAnnotations(ReflectionClass $class)
{
$cacheKey = $class->getName();

if (isset($this->loadedAnnotations[$cacheKey])) {
return $this->loadedAnnotations[$cacheKey];
}

if (false === ($annots = $this->fetchFromCache($cacheKey, $class))) {
$annots = $this->delegate->getClassAnnotations($class);
$this->saveToCache($cacheKey, $annots);
}

return $this->loadedAnnotations[$cacheKey] = $annots;
}

/**
* {@inheritDoc}
*/
public function getClassAnnotation(ReflectionClass $class, $annotationName)
{
foreach ($this->getClassAnnotations($class) as $annot) {
if ($annot instanceof $annotationName) {
return $annot;
}
}

return null;
}

/**
* {@inheritDoc}
*/
public function getPropertyAnnotations(\ReflectionProperty $property)
{
$class = $property->getDeclaringClass();
$cacheKey = $class->getName().'$'.$property->getName();

if (isset($this->loadedAnnotations[$cacheKey])) {
return $this->loadedAnnotations[$cacheKey];
}

if (false === ($annots = $this->fetchFromCache($cacheKey, $class))) {
$annots = $this->delegate->getPropertyAnnotations($property);
$this->saveToCache($cacheKey, $annots);
}

return $this->loadedAnnotations[$cacheKey] = $annots;
}

/**
* {@inheritDoc}
*/
public function getPropertyAnnotation(\ReflectionProperty $property, $annotationName)
{
foreach ($this->getPropertyAnnotations($property) as $annot) {
if ($annot instanceof $annotationName) {
return $annot;
}
}

return null;
}

/**
* {@inheritDoc}
*/
public function getMethodAnnotations(\ReflectionMethod $method)
{
$class = $method->getDeclaringClass();
$cacheKey = $class->getName().'#'.$method->getName();

if (isset($this->loadedAnnotations[$cacheKey])) {
return $this->loadedAnnotations[$cacheKey];
}

if (false === ($annots = $this->fetchFromCache($cacheKey, $class))) {
$annots = $this->delegate->getMethodAnnotations($method);
$this->saveToCache($cacheKey, $annots);
}

return $this->loadedAnnotations[$cacheKey] = $annots;
}

/**
* {@inheritDoc}
*/
public function getMethodAnnotation(\ReflectionMethod $method, $annotationName)
{
foreach ($this->getMethodAnnotations($method) as $annot) {
if ($annot instanceof $annotationName) {
return $annot;
}
}

return null;
}

/**
* Clears loaded annotations.
*
* @return void
*/
public function clearLoadedAnnotations()
{
$this->loadedAnnotations = array();
}

/**
* Fetches a value from the cache.
*
* @param string $cacheKey The cache key.
* @param ReflectionClass $class The related class.
*
* @return mixed The cached value or false when the value is not in cache.
*/
private function fetchFromCache($cacheKey, ReflectionClass $class)
{
if (($data = $this->cache->fetch($cacheKey)) !== false) {
if (!$this->debug || $this->isCacheFresh($cacheKey, $class)) {
return $data;
}
}

return false;
}

/**
* Saves a value to the cache.
*
* @param string $cacheKey The cache key.
* @param mixed $value The value.
*
* @return void
*/
private function saveToCache($cacheKey, $value)
{
$this->cache->save($cacheKey, $value);
if ($this->debug) {
$this->cache->save('[C]'.$cacheKey, time());
}
}

/**
* Checks if the cache is fresh.
*
* @param string $cacheKey
* @param ReflectionClass $class
*
* @return boolean
*/
private function isCacheFresh($cacheKey, ReflectionClass $class)
{
if (null === $lastModification = $this->getLastModification($class)) {
return true;
}

return $this->cache->fetch('[C]'.$cacheKey) >= $lastModification;
}

/**
* Returns the time the class was last modified, testing traits and parents
*
* @param ReflectionClass $class
* @return int
*/
private function getLastModification(ReflectionClass $class)
{
$filename = $class->getFileName();
$parent = $class->getParentClass();

return max(array_merge(
[$filename ? filemtime($filename) : 0],
array_map([$this, 'getTraitLastModificationTime'], $class->getTraits()),
array_map([$this, 'getLastModification'], $class->getInterfaces()),
$parent ? [$this->getLastModification($parent)] : []
));
}

/**
* @param ReflectionClass $reflectionTrait
* @return int
*/
private function getTraitLastModificationTime(ReflectionClass $reflectionTrait)
{
$fileName = $reflectionTrait->getFileName();

return max(array_merge(
[$fileName ? filemtime($fileName) : 0],
array_map([$this, 'getTraitLastModificationTime'], $reflectionTrait->getTraits())
));
}
}
@@ -0,0 +1,134 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\Common\Annotations;

use Doctrine\Common\Lexer\AbstractLexer;

/**
* Simple lexer for docblock annotations.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
final class DocLexer extends AbstractLexer
{
const T_NONE = 1;
const T_INTEGER = 2;
const T_STRING = 3;
const T_FLOAT = 4;

// All tokens that are also identifiers should be >= 100
const T_IDENTIFIER = 100;
const T_AT = 101;
const T_CLOSE_CURLY_BRACES = 102;
const T_CLOSE_PARENTHESIS = 103;
const T_COMMA = 104;
const T_EQUALS = 105;
const T_FALSE = 106;
const T_NAMESPACE_SEPARATOR = 107;
const T_OPEN_CURLY_BRACES = 108;
const T_OPEN_PARENTHESIS = 109;
const T_TRUE = 110;
const T_NULL = 111;
const T_COLON = 112;

/**
* @var array
*/
protected $noCase = array(
'@' => self::T_AT,
',' => self::T_COMMA,
'(' => self::T_OPEN_PARENTHESIS,
')' => self::T_CLOSE_PARENTHESIS,
'{' => self::T_OPEN_CURLY_BRACES,
'}' => self::T_CLOSE_CURLY_BRACES,
'=' => self::T_EQUALS,
':' => self::T_COLON,
'\\' => self::T_NAMESPACE_SEPARATOR
);

/**
* @var array
*/
protected $withCase = array(
'true' => self::T_TRUE,
'false' => self::T_FALSE,
'null' => self::T_NULL
);

/**
* {@inheritdoc}
*/
protected function getCatchablePatterns()
{
return array(
'[a-z_\\\][a-z0-9_\:\\\]*[a-z_][a-z0-9_]*',
'(?:[+-]?[0-9]+(?:[\.][0-9]+)*)(?:[eE][+-]?[0-9]+)?',
'"(?:""|[^"])*+"',
);
}

/**
* {@inheritdoc}
*/
protected function getNonCatchablePatterns()
{
return array('\s+', '\*+', '(.)');
}

/**
* {@inheritdoc}
*/
protected function getType(&$value)
{
$type = self::T_NONE;

if ($value[0] === '"') {
$value = str_replace('""', '"', substr($value, 1, strlen($value) - 2));

return self::T_STRING;
}

if (isset($this->noCase[$value])) {
return $this->noCase[$value];
}

if ($value[0] === '_' || $value[0] === '\\' || ctype_alpha($value[0])) {
return self::T_IDENTIFIER;
}

$lowerValue = strtolower($value);

if (isset($this->withCase[$lowerValue])) {
return $this->withCase[$lowerValue];
}

// Checking numeric value
if (is_numeric($value)) {
return (strpos($value, '.') !== false || stripos($value, 'e') !== false)
? self::T_FLOAT : self::T_INTEGER;
}

return $type;
}
}

Large diffs are not rendered by default.

@@ -0,0 +1,290 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\Common\Annotations;

/**
* File cache reader for annotations.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
* @author Benjamin Eberlei <kontakt@beberlei.de>
*
* @deprecated the FileCacheReader is deprecated and will be removed
* in version 2.0.0 of doctrine/annotations. Please use the
* {@see \Doctrine\Common\Annotations\CachedReader} instead.
*/
class FileCacheReader implements Reader
{
/**
* @var Reader
*/
private $reader;

/**
* @var string
*/
private $dir;

/**
* @var bool
*/
private $debug;

/**
* @var array
*/
private $loadedAnnotations = array();

/**
* @var array
*/
private $classNameHashes = array();

/**
* @var int
*/
private $umask;

/**
* Constructor.
*
* @param Reader $reader
* @param string $cacheDir
* @param boolean $debug
*
* @throws \InvalidArgumentException
*/
public function __construct(Reader $reader, $cacheDir, $debug = false, $umask = 0002)
{
if ( ! is_int($umask)) {
throw new \InvalidArgumentException(sprintf(
'The parameter umask must be an integer, was: %s',
gettype($umask)
));
}

$this->reader = $reader;
$this->umask = $umask;

if (!is_dir($cacheDir) && !@mkdir($cacheDir, 0777 & (~$this->umask), true)) {
throw new \InvalidArgumentException(sprintf('The directory "%s" does not exist and could not be created.', $cacheDir));
}

$this->dir = rtrim($cacheDir, '\\/');
$this->debug = $debug;
}

/**
* {@inheritDoc}
*/
public function getClassAnnotations(\ReflectionClass $class)
{
if ( ! isset($this->classNameHashes[$class->name])) {
$this->classNameHashes[$class->name] = sha1($class->name);
}
$key = $this->classNameHashes[$class->name];

if (isset($this->loadedAnnotations[$key])) {
return $this->loadedAnnotations[$key];
}

$path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php';
if (!is_file($path)) {
$annot = $this->reader->getClassAnnotations($class);
$this->saveCacheFile($path, $annot);
return $this->loadedAnnotations[$key] = $annot;
}

if ($this->debug
&& (false !== $filename = $class->getFileName())
&& filemtime($path) < filemtime($filename)) {
@unlink($path);

$annot = $this->reader->getClassAnnotations($class);
$this->saveCacheFile($path, $annot);
return $this->loadedAnnotations[$key] = $annot;
}

return $this->loadedAnnotations[$key] = include $path;
}

/**
* {@inheritDoc}
*/
public function getPropertyAnnotations(\ReflectionProperty $property)
{
$class = $property->getDeclaringClass();
if ( ! isset($this->classNameHashes[$class->name])) {
$this->classNameHashes[$class->name] = sha1($class->name);
}
$key = $this->classNameHashes[$class->name].'$'.$property->getName();

if (isset($this->loadedAnnotations[$key])) {
return $this->loadedAnnotations[$key];
}

$path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php';
if (!is_file($path)) {
$annot = $this->reader->getPropertyAnnotations($property);
$this->saveCacheFile($path, $annot);
return $this->loadedAnnotations[$key] = $annot;
}

if ($this->debug
&& (false !== $filename = $class->getFilename())
&& filemtime($path) < filemtime($filename)) {
@unlink($path);

$annot = $this->reader->getPropertyAnnotations($property);
$this->saveCacheFile($path, $annot);
return $this->loadedAnnotations[$key] = $annot;
}

return $this->loadedAnnotations[$key] = include $path;
}

/**
* {@inheritDoc}
*/
public function getMethodAnnotations(\ReflectionMethod $method)
{
$class = $method->getDeclaringClass();
if ( ! isset($this->classNameHashes[$class->name])) {
$this->classNameHashes[$class->name] = sha1($class->name);
}
$key = $this->classNameHashes[$class->name].'#'.$method->getName();

if (isset($this->loadedAnnotations[$key])) {
return $this->loadedAnnotations[$key];
}

$path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php';
if (!is_file($path)) {
$annot = $this->reader->getMethodAnnotations($method);
$this->saveCacheFile($path, $annot);
return $this->loadedAnnotations[$key] = $annot;
}

if ($this->debug
&& (false !== $filename = $class->getFilename())
&& filemtime($path) < filemtime($filename)) {
@unlink($path);

$annot = $this->reader->getMethodAnnotations($method);
$this->saveCacheFile($path, $annot);
return $this->loadedAnnotations[$key] = $annot;
}

return $this->loadedAnnotations[$key] = include $path;
}

/**
* Saves the cache file.
*
* @param string $path
* @param mixed $data
*
* @return void
*/
private function saveCacheFile($path, $data)
{
if (!is_writable($this->dir)) {
throw new \InvalidArgumentException(sprintf('The directory "%s" is not writable. Both, the webserver and the console user need access. You can manage access rights for multiple users with "chmod +a". If your system does not support this, check out the acl package.', $this->dir));
}

$tempfile = tempnam($this->dir, uniqid('', true));

if (false === $tempfile) {
throw new \RuntimeException(sprintf('Unable to create tempfile in directory: %s', $this->dir));
}

@chmod($tempfile, 0666 & (~$this->umask));

$written = file_put_contents($tempfile, '<?php return unserialize('.var_export(serialize($data), true).');');

if (false === $written) {
throw new \RuntimeException(sprintf('Unable to write cached file to: %s', $tempfile));
}

@chmod($tempfile, 0666 & (~$this->umask));

if (false === rename($tempfile, $path)) {
@unlink($tempfile);
throw new \RuntimeException(sprintf('Unable to rename %s to %s', $tempfile, $path));
}
}

/**
* {@inheritDoc}
*/
public function getClassAnnotation(\ReflectionClass $class, $annotationName)
{
$annotations = $this->getClassAnnotations($class);

foreach ($annotations as $annotation) {
if ($annotation instanceof $annotationName) {
return $annotation;
}
}

return null;
}

/**
* {@inheritDoc}
*/
public function getMethodAnnotation(\ReflectionMethod $method, $annotationName)
{
$annotations = $this->getMethodAnnotations($method);

foreach ($annotations as $annotation) {
if ($annotation instanceof $annotationName) {
return $annotation;
}
}

return null;
}

/**
* {@inheritDoc}
*/
public function getPropertyAnnotation(\ReflectionProperty $property, $annotationName)
{
$annotations = $this->getPropertyAnnotations($property);

foreach ($annotations as $annotation) {
if ($annotation instanceof $annotationName) {
return $annotation;
}
}

return null;
}

/**
* Clears loaded annotations.
*
* @return void
*/
public function clearLoadedAnnotations()
{
$this->loadedAnnotations = array();
}
}
@@ -0,0 +1,119 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\Common\Annotations;

/**
* Allows the reader to be used in-place of Doctrine's reader.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class IndexedReader implements Reader
{
/**
* @var Reader
*/
private $delegate;

/**
* Constructor.
*
* @param Reader $reader
*/
public function __construct(Reader $reader)
{
$this->delegate = $reader;
}

/**
* {@inheritDoc}
*/
public function getClassAnnotations(\ReflectionClass $class)
{
$annotations = array();
foreach ($this->delegate->getClassAnnotations($class) as $annot) {
$annotations[get_class($annot)] = $annot;
}

return $annotations;
}

/**
* {@inheritDoc}
*/
public function getClassAnnotation(\ReflectionClass $class, $annotation)
{
return $this->delegate->getClassAnnotation($class, $annotation);
}

/**
* {@inheritDoc}
*/
public function getMethodAnnotations(\ReflectionMethod $method)
{
$annotations = array();
foreach ($this->delegate->getMethodAnnotations($method) as $annot) {
$annotations[get_class($annot)] = $annot;
}

return $annotations;
}

/**
* {@inheritDoc}
*/
public function getMethodAnnotation(\ReflectionMethod $method, $annotation)
{
return $this->delegate->getMethodAnnotation($method, $annotation);
}

/**
* {@inheritDoc}
*/
public function getPropertyAnnotations(\ReflectionProperty $property)
{
$annotations = array();
foreach ($this->delegate->getPropertyAnnotations($property) as $annot) {
$annotations[get_class($annot)] = $annot;
}

return $annotations;
}

/**
* {@inheritDoc}
*/
public function getPropertyAnnotation(\ReflectionProperty $property, $annotation)
{
return $this->delegate->getPropertyAnnotation($property, $annotation);
}

/**
* Proxies all methods to the delegate.
*
* @param string $method
* @param array $args
*
* @return mixed
*/
public function __call($method, $args)
{
return call_user_func_array(array($this->delegate, $method), $args);
}
}
@@ -0,0 +1,91 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\Common\Annotations;

use SplFileObject;

/**
* Parses a file for namespaces/use/class declarations.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Christian Kaps <christian.kaps@mohiva.com>
*/
final class PhpParser
{
/**
* Parses a class.
*
* @param \ReflectionClass $class A <code>ReflectionClass</code> object.
*
* @return array A list with use statements in the form (Alias => FQN).
*/
public function parseClass(\ReflectionClass $class)
{
if (method_exists($class, 'getUseStatements')) {
return $class->getUseStatements();
}

if (false === $filename = $class->getFileName()) {
return array();
}

$content = $this->getFileContent($filename, $class->getStartLine());

if (null === $content) {
return array();
}

$namespace = preg_quote($class->getNamespaceName());
$content = preg_replace('/^.*?(\bnamespace\s+' . $namespace . '\s*[;{].*)$/s', '\\1', $content);
$tokenizer = new TokenParser('<?php ' . $content);

$statements = $tokenizer->parseUseStatements($class->getNamespaceName());

return $statements;
}

/**
* Gets the content of the file right up to the given line number.
*
* @param string $filename The name of the file to load.
* @param integer $lineNumber The number of lines to read from file.
*
* @return string|null The content of the file or null if the file does not exist.
*/
private function getFileContent($filename, $lineNumber)
{
if ( ! is_file($filename)) {
return null;
}

$content = '';
$lineCnt = 0;
$file = new SplFileObject($filename);
while (!$file->eof()) {
if ($lineCnt++ == $lineNumber) {
break;
}

$content .= $file->fgets();
}

return $content;
}
}
@@ -0,0 +1,89 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\Common\Annotations;

/**
* Interface for annotation readers.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
interface Reader
{
/**
* Gets the annotations applied to a class.
*
* @param \ReflectionClass $class The ReflectionClass of the class from which
* the class annotations should be read.
*
* @return array An array of Annotations.
*/
function getClassAnnotations(\ReflectionClass $class);

/**
* Gets a class annotation.
*
* @param \ReflectionClass $class The ReflectionClass of the class from which
* the class annotations should be read.
* @param string $annotationName The name of the annotation.
*
* @return object|null The Annotation or NULL, if the requested annotation does not exist.
*/
function getClassAnnotation(\ReflectionClass $class, $annotationName);

/**
* Gets the annotations applied to a method.
*
* @param \ReflectionMethod $method The ReflectionMethod of the method from which
* the annotations should be read.
*
* @return array An array of Annotations.
*/
function getMethodAnnotations(\ReflectionMethod $method);

/**
* Gets a method annotation.
*
* @param \ReflectionMethod $method The ReflectionMethod to read the annotations from.
* @param string $annotationName The name of the annotation.
*
* @return object|null The Annotation or NULL, if the requested annotation does not exist.
*/
function getMethodAnnotation(\ReflectionMethod $method, $annotationName);

/**
* Gets the annotations applied to a property.
*
* @param \ReflectionProperty $property The ReflectionProperty of the property
* from which the annotations should be read.
*
* @return array An array of Annotations.
*/
function getPropertyAnnotations(\ReflectionProperty $property);

/**
* Gets a property annotation.
*
* @param \ReflectionProperty $property The ReflectionProperty to read the annotations from.
* @param string $annotationName The name of the annotation.
*
* @return object|null The Annotation or NULL, if the requested annotation does not exist.
*/
function getPropertyAnnotation(\ReflectionProperty $property, $annotationName);
}
@@ -0,0 +1,127 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\Common\Annotations;

/**
* Simple Annotation Reader.
*
* This annotation reader is intended to be used in projects where you have
* full-control over all annotations that are available.
*
* @since 2.2
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
class SimpleAnnotationReader implements Reader
{
/**
* @var DocParser
*/
private $parser;

/**
* Constructor.
*
* Initializes a new SimpleAnnotationReader.
*/
public function __construct()
{
$this->parser = new DocParser();
$this->parser->setIgnoreNotImportedAnnotations(true);
}

/**
* 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;
}
}