Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added custom dependency injection handler in Kernel #67

Merged
merged 4 commits into from
Nov 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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