Skip to content

Commit

Permalink
Refactoring of container for #65, fixed tests
Browse files Browse the repository at this point in the history
  • Loading branch information
lisachenko committed Jul 23, 2013
1 parent 1e3495b commit 0a133be
Show file tree
Hide file tree
Showing 8 changed files with 224 additions and 257 deletions.
24 changes: 17 additions & 7 deletions src/Go/Core/AspectWeaver.php → src/Go/Core/AdviceMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,14 @@
use ReflectionProperty;

use Go\Aop;
use Go\Aop\Pointcut\PointcutLexer;
use Go\Aop\Pointcut\PointcutGrammar;
use Go\Instrument\RawAnnotationReader;

use Dissect\Parser\LALR1\Parser;
use Doctrine\Common\Annotations\AnnotationReader;
use TokenReflection\ReflectionClass as ParsedReflectionClass;

/**
* Aspect container contains list of all pointcuts and advisors
*/
class AspectWeaver
class AdviceMatcher
{
/**
* Loader of aspects
Expand All @@ -33,8 +29,20 @@ class AspectWeaver
*/
protected $loader;

/**
* Instance of container for aspect
*
* @var AspectContainer
*/
protected $container;

/**
* List of resources that was loaded
*
* @var array
*/
protected $loadedResources = array();

public function __construct(AspectLoader $loader, AspectContainer $container)
{
$this->loader = $loader;
Expand All @@ -50,9 +58,9 @@ public function __construct(AspectLoader $loader, AspectContainer $container)
*/
public function getAdvicesForClass($class)
{
// if ($this->loadedResources != $this->resources) {
if ($this->loadedResources != $this->container->getResources()) {
$this->loadAdvisorsAndPointcuts();
// }
}

$classAdvices = array();
if (!$class instanceof ReflectionClass && !$class instanceof ParsedReflectionClass) {
Expand Down Expand Up @@ -163,8 +171,10 @@ private function getIntroductionFromAdvisor($class, $advisor)
private function loadAdvisorsAndPointcuts()
{
// TODO: use a difference with $this->resources to load only missed aspects
// TODO: maybe this is a task for the AspectLoader?
foreach ($this->container->getByTag('aspect') as $aspect) {
$this->loader->load($aspect);
}
$this->loadedResources = $this->container->getResources();
}
}
24 changes: 24 additions & 0 deletions src/Go/Core/AspectContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,28 @@ public function registerAspect(Aop\Aspect $aspect);
* @return Aop\Aspect
*/
public function getAspect($aspectName);

/**
* Add an AOP resource to the container
*
* @param string $resource Path to the resource
* Resources is used to check the freshness of AOP cache
*/
public function addResource($resource);

/**
* Returns the list of AOP resources
*
* @return array
*/
public function getResources();

/**
* Checks the freshness of AOP cache
*
* @param integer $timestamp
*
* @return bool Whether or not concrete file is fresh
*/
public function isFresh($timestamp);
}
3 changes: 2 additions & 1 deletion src/Go/Core/AspectKernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,8 @@ protected function registerTransformers(SourceTransformingLoader $sourceLoader)
$this,
new TokenReflection\Broker(
new TokenReflection\Broker\Backend\Memory()
)
),
$this->container->get('aspect.advice_matcher')
)
);

Expand Down
156 changes: 14 additions & 142 deletions src/Go/Core/GoAspectContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,6 @@ class GoAspectContainer extends Container implements AspectContainer
*/
protected $maxTimestamp = 0;

/**
* List of loaded resources (it is used for comparison with $this->resources)
*
* @see AspectContainer::resources
* @var array
*/
private $loadedResources = array();

/**
* Constructor for container
*/
Expand All @@ -64,8 +56,8 @@ public function __construct()
return $aspectLoader;
});

$this->share('aspect.weaver', function ($container) {
return new AspectWeaver(
$this->share('aspect.advice_matcher', function ($container) {
return new AdviceMatcher(
$container->get('aspect.loader'),
$container
);
Expand Down Expand Up @@ -151,11 +143,11 @@ public function registerAspect(Aop\Aspect $aspect)
}

/**
* Add an resource for container
* Add an AOP resource to the container
*
* TODO: use symfony/config component for creating the cache
*
* Resources is used to check the freshness of cache
* Resources is used to check the freshness of AOP cache
*/
public function addResource($resource)
{
Expand All @@ -164,147 +156,27 @@ public function addResource($resource)
}

/**
* Checks the freshness of container
*
* @param integer $timestamp
*
* @return bool Whether or not container is fresh
*/
public function isFresh($timestamp)
{
if (!$this->maxTimestamp && $this->resources) {
$this->maxTimestamp = max(array_map('filemtime', $this->resources));
}
return $this->maxTimestamp < $timestamp;
}

/**
* Return list of advices for class
*
* @param string|ReflectionClass|ParsedReflectionClass $class Class to advise
*
* @return array|Aop\Advice[] List of advices for class
*/
public function getAdvicesForClass($class)
{
if ($this->loadedResources != $this->resources) {
$this->loadAdvisorsAndPointcuts();
}

$classAdvices = array();
if (!$class instanceof ReflectionClass && !$class instanceof ParsedReflectionClass) {
$class = new ReflectionClass($class);
}

$parentClass = $class->getParentClass();

if ($parentClass && preg_match('/' . self::AOP_PROXIED_SUFFIX . '$/', $parentClass->name)) {
$originalClass = $parentClass;
} else {
$originalClass = $class;
}

foreach ($this->getByTag('advisor') as $advisor) {

if ($advisor instanceof Aop\PointcutAdvisor) {

$pointcut = $advisor->getPointcut();
if ($pointcut->getClassFilter()->matches($class)) {
$classAdvices = array_merge_recursive(
$classAdvices,
$this->getAdvicesFromAdvisor($originalClass, $advisor, $pointcut)
);
}
}

if ($advisor instanceof Aop\IntroductionAdvisor) {
if ($advisor->getClassFilter()->matches($class)) {
$classAdvices = array_merge_recursive(
$classAdvices,
$this->getIntroductionFromAdvisor($originalClass, $advisor)
);
}
}
}
return $classAdvices;
}

/**
* Returns list of advices from advisor and point filter
*
* @param ReflectionClass|ParsedReflectionClass $class Class to inject advices
* @param Aop\PointcutAdvisor $advisor Advisor for class
* @param Aop\PointFilter $filter Filter for points
* Returns list of AOP resources
*
* @return array
*/
private function getAdvicesFromAdvisor($class, Aop\PointcutAdvisor $advisor, Aop\PointFilter $filter)
public function getResources()
{
$classAdvices = array();

// Check methods in class only for method filters
if ($filter->getKind() & Aop\PointFilter::KIND_METHOD) {

$mask = ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED;
foreach ($class->getMethods($mask) as $method) {
/** @var $method ReflectionMethod| */
if ($method->getDeclaringClass()->name == $class->name && $filter->matches($method)) {
$prefix = $method->isStatic() ? self::STATIC_METHOD_PREFIX : self::METHOD_PREFIX;
$classAdvices[$prefix . ':'. $method->name][] = $advisor->getAdvice();
}
}
}

// Check properties in class only for property filters
if ($filter->getKind() & Aop\PointFilter::KIND_PROPERTY) {
$mask = ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED;
foreach ($class->getProperties($mask) as $property) {
/** @var $property ReflectionProperty */
if ($filter->matches($property)) {
$classAdvices[self::PROPERTY_PREFIX.':'.$property->name][] = $advisor->getAdvice();
}
}
}

return $classAdvices;
return $this->resources;
}

/**
* Returns list of introduction advices from advisor
*
* @param ReflectionClass|ParsedReflectionClass $class Class to inject advices
* @param Aop\IntroductionAdvisor $advisor Advisor for class
* Checks the freshness of AOP cache
*
* @return array
*/
private function getIntroductionFromAdvisor($class, $advisor)
{
// Do not make introduction for traits
if ($class->isTrait()) {
return array();
}

/** @var $advice Aop\IntroductionInfo */
$advice = $advisor->getAdvice();

return array(
self::INTRODUCTION_TRAIT_PREFIX.':'.join(':', $advice->getInterfaces()) => $advice
);
}

/**
* Load pointcuts into container
* @param integer $timestamp
*
* There is no need to always load pointcuts, so we delay loading
* @return bool Whether or not concrete file is fresh
*/
private function loadAdvisorsAndPointcuts()
public function isFresh($timestamp)
{
// TODO: use a difference with $this->resources to load only missed aspects
/** @var $loader AspectLoader */
$loader = $this->get('aspect.loader');
foreach ($this->getByTag('aspect') as $aspect) {
$loader->load($aspect);
if (!$this->maxTimestamp && $this->resources) {
$this->maxTimestamp = max(array_map('filemtime', $this->resources));
}
$this->loadedResources = $this->resources;
return $this->maxTimestamp < $timestamp;
}
}
15 changes: 8 additions & 7 deletions src/Go/Instrument/Transformer/WeavingTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
namespace Go\Instrument\Transformer;

use Go\Core\AspectContainer;
use Go\Core\AspectWeaver;
use Go\Core\AdviceMatcher;
use Go\Core\AspectKernel;
use Go\Proxy\ClassProxy;
use Go\Proxy\TraitProxy;
Expand All @@ -33,9 +33,9 @@ class WeavingTransformer extends BaseSourceTransformer
protected $broker;

/**
* @var AspectWeaver
* @var AdviceMatcher
*/
protected $weaver;
protected $adviceMatcher;

/**
* List of include paths to process
Expand All @@ -56,12 +56,13 @@ class WeavingTransformer extends BaseSourceTransformer
*
* @param AspectKernel $kernel Instance of aspect kernel
* @param Broker $broker Instance of reflection broker to use
* @param AdviceMatcher $adviceMatcher Advice matcher for class
*/
public function __construct(AspectKernel $kernel, Broker $broker)
public function __construct(AspectKernel $kernel, Broker $broker, AdviceMatcher $adviceMatcher)
{
parent::__construct($kernel);
$this->broker = $broker;
$this->weaver = $this->container->get('aspect.weaver');
$this->broker = $broker;
$this->adviceMatcher = $adviceMatcher;

$this->includePaths = array_map('realpath', $this->options['includePaths']);
$this->excludePaths = array_map('realpath', $this->options['excludePaths']);
Expand Down Expand Up @@ -123,7 +124,7 @@ public function transform(StreamMetaData $metadata)
continue;
}

$advices = $this->weaver->getAdvicesForClass($class);
$advices = $this->adviceMatcher->getAdvicesForClass($class);

if ($advices) {

Expand Down
Loading

0 comments on commit 0a133be

Please sign in to comment.