Skip to content

Commit

Permalink
Merge pull request #67: Added custom dependency injection handler in …
Browse files Browse the repository at this point in the history
…Kernel
  • Loading branch information
WalterWoshid committed Nov 5, 2023
2 parents 3e6b9ca + 2ed35d5 commit 0e475dc
Show file tree
Hide file tree
Showing 15 changed files with 320 additions and 13 deletions.
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "okapi/aop",
"description": "PHP AOP is a PHP library that provides a powerful Aspect Oriented Programming (AOP) implementation for PHP.",
"version": "1.2.7",
"version": "1.2.8",
"type": "library",
"homepage": "https://github.com/okapi-web/php-aop",
"license": "MIT",
Expand All @@ -26,7 +26,7 @@
"require": {
"php": ">=8.1",
"nette/php-generator": "^4.0",
"okapi/code-transformer": "^1.3.4",
"okapi/code-transformer": "^1.3.5",
"okapi/wildcards": "^1.0",
"okapi/singleton": "^1.0",
"php-di/php-di": "^7.0"
Expand Down
30 changes: 24 additions & 6 deletions src/AopKernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
*/
namespace Okapi\Aop;

use Closure;
use DI\Attribute\Inject;
use Okapi\Aop\Attributes\Aspect;
use Okapi\Aop\Component\ComponentType;
use Okapi\Aop\Core\AutoloadInterceptor\ClassLoader;
use Okapi\Aop\Core\Cache\CachePaths;
use Okapi\Aop\Core\Cache\CacheStateFactory;
use Okapi\Aop\Core\Cache\CacheStateManager;
use Okapi\Aop\Core\Container\AspectManager;
use Okapi\Aop\Core\Cache\{CachePaths, CacheStateFactory, CacheStateManager};
use Okapi\Aop\Core\Container\{AspectManager, TransformerManager};
use Okapi\Aop\Core\Options;
use Okapi\Aop\Core\Processor\AspectProcessor;
use Okapi\Aop\Core\Transformer\NetteReflectionWithBetterReflection;
Expand All @@ -20,6 +20,7 @@
use Okapi\CodeTransformer\Core\Cache\CachePaths as CodeTransformerCachePaths;
use Okapi\CodeTransformer\Core\Cache\CacheStateFactory as CodeTransformerCacheStateFactory;
use Okapi\CodeTransformer\Core\Cache\CacheStateManager as CodeTransformerCacheStateManager;
use Okapi\CodeTransformer\Core\Container\TransformerManager as CodeTransformerTransformerManager;
use Okapi\CodeTransformer\Core\DI;
use Okapi\CodeTransformer\Core\Options as CodeTransformerOptions;
use Okapi\CodeTransformer\Core\Processor\TransformerProcessor;
Expand Down Expand Up @@ -99,6 +100,9 @@ protected static function registerDependencyInjection(): void
DI::set(CodeTransformerCacheStateManager::class, decorate(function () {
return DI::get(CacheStateManager::class);
}));
DI::set(CodeTransformerTransformerManager::class, decorate(function () {
return DI::get(TransformerManager::class);
}));
}

/**
Expand All @@ -118,11 +122,25 @@ protected function preInit(): void
}

/**
* @inheritDoc
* Custom dependency injection handler.
*
* Pass a closure that takes an aspect/transformer class name as the
* argument and returns an aspect/transformer instance.
*
* @return null|Closure(class-string, ComponentType): object
*/
protected function dependencyInjectionHandler(): ?Closure
{
// Override this method to configure the dependency injection handler

return null;
}

protected function registerServices(): void
{
// Manage the user-defined aspects
$this->aspectManager->registerCustomDependencyInjectionHandler(
$this->dependencyInjectionHandler(),
);
$this->aspectManager->register();

parent::registerServices();
Expand Down
9 changes: 9 additions & 0 deletions src/Component/ComponentType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Okapi\Aop\Component;

enum ComponentType
{
case TRANSFORMER;
case ASPECT;
}
31 changes: 27 additions & 4 deletions src/Core/Container/AspectManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
/** @noinspection PhpPropertyOnlyWrittenInspection */
namespace Okapi\Aop\Core\Container;

use Closure;
use DI\Attribute\Inject;
use Error;
use Exception;
use Okapi\Aop\Attributes\Aspect;
use Okapi\Aop\Component\ComponentType;
use Okapi\Aop\Core\Attributes\Base\BaseAdvice;
use Okapi\Aop\Core\Exception\Aspect\AspectNotFoundException;
use Okapi\Aop\Core\Exception\Aspect\InvalidAspectClassNameException;
Expand Down Expand Up @@ -53,6 +55,11 @@ class AspectManager
*/
private array $adviceContainers = [];

/**
* @var null|Closure(class-string, ): object
*/
private ?Closure $dependencyInjectionHandler = null;

// region Pre-Initialization

/**
Expand All @@ -74,6 +81,15 @@ public function addAspects(array $aspectClasses): void

// region Initialization

/**
* @param null|(Closure(class-string, ComponentType): object) $dependencyInjectionHandler
*/
public function registerCustomDependencyInjectionHandler(
?Closure $dependencyInjectionHandler
): void {
$this->dependencyInjectionHandler = $dependencyInjectionHandler;
}

/**
* Register the aspect container.
*
Expand Down Expand Up @@ -123,10 +139,17 @@ public function loadAspect(mixed $aspectClassName): void
}

// Instantiate the aspect
try {
$aspectInstance = DI::make($aspectClassName);
} catch (Error|Exception) {
throw new AspectNotFoundException($aspectClassName);
if ($this->dependencyInjectionHandler) {
$aspectInstance = ($this->dependencyInjectionHandler)(
$aspectClassName,
ComponentType::ASPECT,
);
} else {
try {
$aspectInstance = DI::make($aspectClassName);
} catch (Error|Exception) {
throw new AspectNotFoundException($aspectClassName);
}
}

// Create a reflection of the aspect
Expand Down
14 changes: 14 additions & 0 deletions src/Core/Container/TransformerManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace Okapi\Aop\Core\Container;

use Okapi\Aop\Component\ComponentType;
use Okapi\CodeTransformer\Core\Container\TransformerManager as CodeTransformerTransformerManager;

class TransformerManager extends CodeTransformerTransformerManager
{
protected function getAdditionalDependencyInjectionParams(): array
{
return [ComponentType::TRANSFORMER];
}
}
2 changes: 1 addition & 1 deletion src/Core/Invocation/AdviceChain.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ className: $this->className,
$result = $adviceRefMethod->invoke($aspectInstance, $invocation);

// Check if the advice method will return a value
$hasReturnValue = $adviceRefMethod->getReturnType()?->getName() !== 'void';
$hasReturnValue = $adviceRefMethod->getReturnType()?->__toString() !== 'void';

// 1. Accept return value of advice method OR
// 2. Check if the advice method used "setResult()" OR
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Okapi\Aop\Tests\Functional\Kernel\CustomDependencyInjectionHandler;

use Okapi\Aop\Attributes\After;
use Okapi\Aop\Attributes\Aspect as AspectAttribute;

#[AspectAttribute]
class Aspect
{
#[After(
class: Target::class,
method: 'answer',
)]
public function higherAnswer(): int
{
return 420;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Okapi\Aop\Tests\Functional\Kernel\CustomDependencyInjectionHandler;

use Okapi\Aop\Tests\Util;
use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
use PHPUnit\Framework\TestCase;

#[RunTestsInSeparateProcesses]
class CustomDependencyInjectionHandlerTest extends TestCase
{
public function testCustomDependencyInjectionHandler(): void
{
Util::clearCache();

ob_start();

Kernel::init();

$output = ob_get_clean();

$this->assertStringContainsString(
'Generating aspect/transformer instance: ' . Aspect::class,
$output,
);

$class = new Target();

$this->assertSame(
420,
$class->answer(),
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Okapi\Aop\Tests\Functional\Kernel\CustomDependencyInjectionHandler;

use Closure;
use Okapi\Aop\AopKernel;
use Okapi\Aop\Tests\Util;

class Kernel extends AopKernel
{
protected ?string $cacheDir = Util::CACHE_DIR;

protected function dependencyInjectionHandler(): ?Closure
{
return function (string $className) {
echo 'Generating aspect/transformer instance: ' . $className . PHP_EOL;

return new $className();
};
}

protected array $aspects = [
Aspect::class,
];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Okapi\Aop\Tests\Functional\Kernel\CustomDependencyInjectionHandler;

class Target
{
public function answer(): int
{
return 42;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php
/** @noinspection PhpUnused */
namespace Okapi\Aop\Tests\Integration\TransformerAndAspectDependencyInjectionHandler;

use Okapi\Aop\Attributes\After;
use Okapi\Aop\Attributes\Aspect as AspectAttribute;
use Okapi\Aop\Invocation\AfterMethodInvocation;

#[AspectAttribute]
class Aspect
{
#[After(
class: Target::class,
method: 'answer',
)]
public function higherAnswer(AfterMethodInvocation $methodInvocation): int|float
{
$result = $methodInvocation->proceed();

return $result + 378;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace Okapi\Aop\Tests\Integration\TransformerAndAspectDependencyInjectionHandler;

use Closure;
use Okapi\Aop\AopKernel;
use Okapi\Aop\Component\ComponentType;
use Okapi\Aop\Tests\Util;

class Kernel extends AopKernel
{
protected ?string $cacheDir = Util::CACHE_DIR;

protected function dependencyInjectionHandler(): ?Closure
{
return function (string $className, ComponentType $type) {
/** @noinspection PhpIfWithCommonPartsInspection */
if ($type === ComponentType::ASPECT) {
echo 'Generating aspect instance: ' . $className . PHP_EOL;

return new $className();
} else {
echo 'Generating transformer instance: ' . $className . PHP_EOL;

return new $className();
}
};
}

protected array $aspects = [
Aspect::class,
];

protected array $transformers = [
Transformer::class,
];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Okapi\Aop\Tests\Integration\TransformerAndAspectDependencyInjectionHandler;

class Target
{
public function answer(): int|float
{
return 42;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace Okapi\Aop\Tests\Integration\TransformerAndAspectDependencyInjectionHandler;

use Microsoft\PhpParser\Node\DelimitedList\QualifiedNameList;
use Microsoft\PhpParser\Node\MethodDeclaration;
use Microsoft\PhpParser\Node\NumericLiteral;
use Okapi\CodeTransformer\Transformer as TransformerClass;
use Okapi\CodeTransformer\Transformer\Code;

class Transformer extends TransformerClass
{
public function getTargetClass(): string|array
{
return Target::class;
}

/** @noinspection PhpPossiblePolymorphicInvocationInspection */
public function transform(Code $code): void
{
$sourceFileNode = $code->getSourceFileNode();

foreach ($sourceFileNode->getDescendantNodes() as $node) {
if ($node instanceof QualifiedNameList
&& $node->getFirstAncestor(MethodDeclaration::class)?->getName() === 'answer'
) {
$code->edit($node, 'int|float');
}

if ($node instanceof NumericLiteral
&& $node->getFirstAncestor(MethodDeclaration::class)?->getName() === 'answer'
) {
$text = $node->getText();
$code->edit($node, "$text.69");
}
}
}
}
Loading

0 comments on commit 0e475dc

Please sign in to comment.