2015-08-17 17:00:26 -07:00
< ? 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 ;
2018-11-23 12:29:20 +00:00
use ReflectionClass ;
2015-08-17 17:00:26 -07:00
/**
* 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 }
*/
2018-11-23 12:29:20 +00:00
public function getClassAnnotations ( ReflectionClass $class )
2015-08-17 17:00:26 -07:00
{
$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 }
*/
2018-11-23 12:29:20 +00:00
public function getClassAnnotation ( ReflectionClass $class , $annotationName )
2015-08-17 17:00:26 -07:00
{
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 .
*
2018-11-23 12:29:20 +00:00
* @ param string $cacheKey The cache key .
* @ param ReflectionClass $class The related class .
2015-08-17 17:00:26 -07:00
*
* @ return mixed The cached value or false when the value is not in cache .
*/
2018-11-23 12:29:20 +00:00
private function fetchFromCache ( $cacheKey , ReflectionClass $class )
2015-08-17 17:00:26 -07:00
{
if (( $data = $this -> cache -> fetch ( $cacheKey )) !== false ) {
if ( ! $this -> debug || $this -> isCacheFresh ( $cacheKey , $class )) {
return $data ;
}
}
return false ;
}
/**
* Saves a value to the cache .
*
2018-11-23 12:29:20 +00:00
* @ param string $cacheKey The cache key .
* @ param mixed $value The value .
2015-08-17 17:00:26 -07:00
*
* @ return void
*/
2018-11-23 12:29:20 +00:00
private function saveToCache ( $cacheKey , $value )
2015-08-17 17:00:26 -07:00
{
$this -> cache -> save ( $cacheKey , $value );
if ( $this -> debug ) {
$this -> cache -> save ( '[C]' . $cacheKey , time ());
}
}
/**
* Checks if the cache is fresh .
*
* @ param string $cacheKey
2018-11-23 12:29:20 +00:00
* @ param ReflectionClass $class
2015-08-17 17:00:26 -07:00
*
* @ return boolean
*/
2018-11-23 12:29:20 +00:00
private function isCacheFresh ( $cacheKey , ReflectionClass $class )
2015-08-17 17:00:26 -07:00
{
2018-11-23 12:29:20 +00:00
if ( null === $lastModification = $this -> getLastModification ( $class )) {
2015-08-17 17:00:26 -07:00
return true ;
}
2018-11-23 12:29:20 +00:00
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 ())
));
2015-08-17 17:00:26 -07:00
}
}