Skip to content

Commit

Permalink
Merge pull request #501 from goaop/feature/container-refactoring
Browse files Browse the repository at this point in the history
[BC Break] Internal container refactoring.
  • Loading branch information
lisachenko committed Apr 14, 2024
2 parents ce9fe05 + f5e90ff commit 5d7e1ad
Show file tree
Hide file tree
Showing 28 changed files with 463 additions and 524 deletions.
5 changes: 3 additions & 2 deletions src/Aop/Framework/AbstractInterceptor.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
namespace Go\Aop\Framework;

use Closure;
use Go\Aop\Aspect;
use Go\Aop\AspectException;
use Go\Aop\Intercept\Interceptor;
use Go\Aop\OrderedAdvice;
Expand Down Expand Up @@ -89,15 +90,15 @@ public static function serializeAdvice(Closure $adviceMethod): array
public static function unserializeAdvice(array $adviceData): Closure
{
// General unpacking supports only aspect's advices
if (!isset($adviceData['class'])) {
if (!isset($adviceData['class']) || !is_subclass_of($adviceData['class'], Aspect::class)) {
throw new AspectException('Could not unpack an interceptor without aspect name');
}
$aspectName = $adviceData['class'];
$methodName = $adviceData['name'];

// With aspect name and method name, we can restore back a closure for it
if (!isset(self::$localAdvicesCache["$aspectName->$methodName"])) {
$aspect = AspectKernel::getInstance()->getContainer()->getAspect($aspectName);
$aspect = AspectKernel::getInstance()->getContainer()->getService($aspectName);
$advice = (new ReflectionMethod($aspectName, $methodName))->getClosure($aspect);

assert(isset($advice), 'getClosure() can not be null on modern PHP versions');
Expand Down
7 changes: 6 additions & 1 deletion src/Aop/Pointcut/PointcutReference.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

namespace Go\Aop\Pointcut;

use Go\Aop\AspectException;
use Go\Aop\Pointcut;
use Go\Core\AspectContainer;
use Go\Core\AspectKernel;
Expand Down Expand Up @@ -68,7 +69,11 @@ public function __wakeup(): void
private function getPointcut(): Pointcut
{
if (!isset($this->pointcut)) {
$this->pointcut = $this->container->getPointcut($this->pointcutId);
$pointcutValue = $this->container->getValue($this->pointcutId);
if (!$pointcutValue instanceof Pointcut) {
throw new AspectException("Reference {$this->pointcutId} points not to a Pointcut.");
}
$this->pointcut = $pointcutValue;
}

return $this->pointcut;
Expand Down
10 changes: 4 additions & 6 deletions src/Aop/Support/LazyPointcutAdvisor.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

use Go\Aop\Advice;
use Go\Aop\Pointcut;
use Go\Aop\Pointcut\PointcutLexer;
use Go\Aop\Pointcut\PointcutParser;
use Go\Aop\PointcutAdvisor;
use Go\Core\AspectContainer;

Expand Down Expand Up @@ -42,12 +44,8 @@ public function getPointcut(): Pointcut
{
if (!isset($this->pointcut)) {
// Inject these dependencies and make them lazy!

/** @var Pointcut\PointcutLexer $lexer */
$lexer = $this->container->get('aspect.pointcut.lexer');

/** @var Pointcut\PointcutParser $parser */
$parser = $this->container->get('aspect.pointcut.parser');
$lexer = $this->container->getService(PointcutLexer::class);
$parser = $this->container->getService(PointcutParser::class);

$tokenStream = $lexer->lex($this->pointcutExpression);
$this->pointcut = $parser->parse($tokenStream);
Expand Down
6 changes: 3 additions & 3 deletions src/Aop/Support/PointcutBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ public function declareError(string $pointcutExpression, string $message, int $e
*/
private function registerAdviceInContainer(string $pointcutExpression, Advice $adviceToInvoke): void
{
$this->container->registerAdvisor(
new LazyPointcutAdvisor($this->container, $pointcutExpression, $adviceToInvoke),
$this->getPointcutId($pointcutExpression)
$this->container->add(
$this->getPointcutId($pointcutExpression),
new LazyPointcutAdvisor($this->container, $pointcutExpression, $adviceToInvoke)
);
}

Expand Down
2 changes: 1 addition & 1 deletion src/Console/Command/BaseAspectCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class BaseAspectCommand extends Command
/**
* Stores an instance of aspect kernel
*/
protected ?AspectKernel $aspectKernel = null;
protected AspectKernel $aspectKernel;

/**
* {@inheritDoc}
Expand Down
22 changes: 10 additions & 12 deletions src/Console/Command/DebugAdvisorCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@

use Go\Aop\Advisor;
use Go\Core\AdviceMatcher;
use Go\Core\AdviceMatcherInterface;
use Go\Core\AspectContainer;
use Go\Core\AspectLoader;
use Go\Core\CachedAspectLoader;
use Go\Instrument\FileSystem\Enumerator;
use Go\ParserReflection\ReflectionFile;
use ReflectionClass;
Expand Down Expand Up @@ -63,9 +62,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$io->title('Advisor debug information');

$advisorId = $input->getOption('advisor');
if (!$advisorId) {
if (empty($advisorId)) {
$this->showAdvisorsList($io);
} else {
assert(is_string($advisorId), "Option 'advisor' must be a string, " . gettype($advisorId) . " given");
$this->showAdvisorInformation($io, $advisorId);
}

Expand All @@ -81,7 +81,6 @@ private function showAdvisorsList(SymfonyStyle $io): void

$tableRows = [];
foreach ($advisors as $id => $advisor) {
[, $id] = explode('.', $id, 2);
$advice = $advisor->getAdvice();
$expression = '';
try {
Expand All @@ -106,11 +105,13 @@ private function showAdvisorInformation(SymfonyStyle $io, string $advisorId): vo
{
$aspectContainer = $this->aspectKernel->getContainer();

/** @var AdviceMatcherInterface $adviceMatcher */
$adviceMatcher = $aspectContainer->get('aspect.advice_matcher');
$adviceMatcher = $aspectContainer->getService(AdviceMatcher::class);
$this->loadAdvisorsList($aspectContainer);

$advisor = $aspectContainer->getAdvisor($advisorId);
$advisor = $aspectContainer->getValue($advisorId);
if (!$advisor instanceof Advisor) {
throw new \InvalidArgumentException("Invalid advisor {$advisorId} given");
}
$options = $this->aspectKernel->getOptions();

$enumerator = new Enumerator($options['appDir'], $options['includePaths'], $options['excludePaths']);
Expand Down Expand Up @@ -151,14 +152,11 @@ private function writeInfoAboutAdvices(SymfonyStyle $io, ReflectionClass $reflec
*/
private function loadAdvisorsList(AspectContainer $aspectContainer): array
{
/** @var AspectLoader $aspectLoader */
$aspectLoader = $aspectContainer->get('aspect.cached.loader');
$aspectLoader = $aspectContainer->getService(CachedAspectLoader::class);
$aspects = $aspectLoader->getUnloadedAspects();
foreach ($aspects as $aspect) {
$aspectLoader->loadAndRegister($aspect);
}
$advisors = $aspectContainer->getByTag('advisor');

return $advisors;
return $aspectContainer->getServicesByInterface(Advisor::class);
}
}
9 changes: 4 additions & 5 deletions src/Console/Command/DebugAspectCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$aspectName = $input->getOption('aspect');
if (!$aspectName) {
$io->text('<info>' . get_class($this->aspectKernel) . '</info> has following enabled aspects:');
$aspects = $container->getByTag('aspect');
} else {
$aspect = $container->getAspect($aspectName);
$aspects = $container->getServicesByInterface(Aspect::class);
} elseif (is_string($aspectName) && is_subclass_of($aspectName, Aspect::class)) {
$aspect = $container->getService($aspectName);
$aspects[] = $aspect;
}
$this->showRegisteredAspectsInfo($io, $aspects);
Expand Down Expand Up @@ -106,8 +106,7 @@ private function showAspectPointcutsAndAdvisors(SymfonyStyle $io, Aspect $aspect
{
$container = $this->aspectKernel->getContainer();

/** @var AspectLoader $aspectLoader */
$aspectLoader = $container->get('aspect.loader');
$aspectLoader = $container->getService(AspectLoader::class);
$io->writeln('<comment>Pointcuts and advices</comment>');

$aspectItems = $aspectLoader->load($aspect);
Expand Down
2 changes: 1 addition & 1 deletion src/Console/Command/DebugWeavingCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int

$io->title('Weaving debug information');

$cachePathManager = $this->aspectKernel->getContainer()->get('aspect.cache.path.manager');
$cachePathManager = $this->aspectKernel->getContainer()->getService(CachePathManager::class);
$warmer = new CacheWarmer($this->aspectKernel, new NullOutput());
$warmer->warmUp();

Expand Down
75 changes: 28 additions & 47 deletions src/Core/AspectContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@
namespace Go\Core;

use OutOfBoundsException;
use Go\Aop\Advisor;
use Go\Aop\Aspect;
use Go\Aop\Pointcut;

/**
* Aspect container interface
Expand Down Expand Up @@ -68,77 +66,60 @@ interface AspectContainer
public const AOP_PROXIED_SUFFIX = '__AopProxied';

/**
* Return a service or value from the container
* Returns a service from the container.
*
* Supports lazy-initialization if value is defined as a closure, it will be invoked once to perform initialization.
*
* @param class-string<T> $className Class-name of service to retrieve from the container
* @return object&T
*
* @template T of object
*
* @return mixed
* @throws OutOfBoundsException if service was not found
*/
public function get(string $id);
public function getService(string $className): object;

/**
* Return list of service tagged with marker
* Return list of services tagged with marker interface
*
* @param class-string<T> $interfaceTagClassName Interface name of services to retrieve from the container
* @return T[]
*
* @template T
*/
public function getByTag(string $tag): array;
public function getServicesByInterface(string $interfaceTagClassName): array;

/**
* Returns a pointcut by identifier
* Returns a value from the container
*
* @param string $key Given key
*
* @return mixed
* @throws OutOfBoundsException if key was not found
*/
public function getPointcut(string $id): Pointcut;
public function getValue(string $key): mixed;

/**
* Checks if item with specified id is present in the container
*/
public function has(string $id): bool;

/**
* Store the pointcut in the container
*/
public function registerPointcut(Pointcut $pointcut, string $id): void;

/**
* Returns an advisor by identifier
*/
public function getAdvisor(string $id): Advisor;

/**
* Store the advisor in the container
*/
public function registerAdvisor(Advisor $advisor, string $id): void;

/**
* Register an aspect in the container
*/
public function registerAspect(Aspect $aspect): void;

/**
* Returns an aspect by id or class name
*/
public function getAspect(string $aspectName): Aspect;

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

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

/**
* Checks the freshness of AOP cache
* Checks if there are any file resources with changes after since given timestamp
*
* @return bool Whether or not concrete file is fresh
* @return bool Whether or not there are new changes (filemtime of any resource is greater than given)
*/
public function isFresh(int $timestamp): bool;
public function hasAnyResourceChangedSince(int $timestamp): bool;

/**
* Set a service into the container
* Adds a new item into the container
*
* @param mixed $value Value to store
*/
public function set(string $id, $value, array $tags = []): void;
public function add(string $id, mixed $value): void;
}
Loading

0 comments on commit 5d7e1ad

Please sign in to comment.