Skip to content

Commit eafee5a

Browse files
authored
Merge pull request #15: Added custom dependency injection handler in Kernel
2 parents d44dc97 + cb50c36 commit eafee5a

File tree

62 files changed

+822
-320
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+822
-320
lines changed

composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "okapi/code-transformer",
33
"description": "PHP Code Transformer is a PHP library that allows you to modify and transform the source code of a loaded PHP class.",
4-
"version": "1.3.3",
4+
"version": "1.3.4",
55
"type": "library",
66
"homepage": "https://github.com/okapi-web/php-code-transformer",
77
"license": "MIT",

src/CodeTransformerKernel.php

+17-7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Okapi\CodeTransformer;
44

5+
use Closure;
56
use DI\Attribute\Inject;
67
use Okapi\CodeTransformer\Core\AutoloadInterceptor;
78
use Okapi\CodeTransformer\Core\Cache\CacheStateManager;
@@ -160,7 +161,7 @@ public static function init(): void
160161
}
161162

162163
/**
163-
* Register the dependency injection.
164+
* Internal dependency injection.
164165
*
165166
* @return void
166167
*/
@@ -199,22 +200,31 @@ protected function configureOptions(): void
199200
}
200201

201202
/**
202-
* Register the services.
203+
* Custom dependency injection handler.
203204
*
204-
* @return void
205+
* Pass a closure that takes a transformer class name as the argument and
206+
* returns a transformer instance.
207+
*
208+
* @return null|Closure(class-string<Transformer>): Transformer
205209
*/
210+
protected function dependencyInjectionHandler(): ?Closure
211+
{
212+
// Override this method to configure the dependency injection handler
213+
214+
return null;
215+
}
216+
206217
protected function registerServices(): void
207218
{
208-
// Options provider
209219
$this->options->register();
210220

211-
// Manage the user-defined transformers
221+
$this->transformerManager->registerCustomDependencyInjectionHandler(
222+
$this->dependencyInjectionHandler()
223+
);
212224
$this->transformerManager->register();
213225

214-
// Cache path manager
215226
$this->cacheStateManager->register();
216227

217-
// Stream filter -> Source transformer
218228
$this->streamFilter->register();
219229
}
220230

src/Core/AutoloadInterceptor/ClassLoader.php

+1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ public function loadClass($namespacedClass): bool
8686
* @return false|string
8787
*
8888
* @noinspection PhpParameterNameChangedDuringInheritanceInspection
89+
* @noinspection PhpStatementHasEmptyBodyInspection
8990
*/
9091
public function findFile($namespacedClass): false|string
9192
{

src/Core/Cache/CacheStateManager.php

+7-1
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,14 @@ public function register(): void
8989
*/
9090
private function initializeCacheDirectory(): void
9191
{
92+
$cacheDir = $this->options->getCacheDir();
93+
94+
if (file_exists($cacheDir)) {
95+
return;
96+
}
97+
9298
Filesystem::mkdir(
93-
$this->options->getCacheDir(),
99+
$cacheDir,
94100
$this->options->getCacheFileMode(),
95101
recursive: true,
96102
);

src/Core/Container/TransformerManager.php

+55-26
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
/** @noinspection PhpPropertyOnlyWrittenInspection */
33
namespace Okapi\CodeTransformer\Core\Container;
44

5+
use Closure;
56
use Error;
67
use Exception;
78
use Okapi\CodeTransformer\Core\DI;
89
use Okapi\CodeTransformer\Core\Exception\Transformer\InvalidTransformerClassException;
10+
use Okapi\CodeTransformer\Core\Exception\Transformer\InvalidTransformerClassNameException;
911
use Okapi\CodeTransformer\Core\Exception\Transformer\TransformerNotFoundException;
1012
use Okapi\CodeTransformer\Core\ServiceInterface;
1113
use Okapi\CodeTransformer\Transformer;
@@ -32,6 +34,11 @@ class TransformerManager implements ServiceInterface
3234
*/
3335
private array $transformerContainers = [];
3436

37+
/**
38+
* @var ?Closure(class-string<Transformer>): Transformer
39+
*/
40+
private ?Closure $dependencyInjectionHandler = null;
41+
3542
// region Pre-Initialization
3643

3744
/**
@@ -54,51 +61,73 @@ public function addTransformers(array $transformers): void
5461
// region Initialization
5562

5663
/**
57-
* Register the transformer container.
58-
*
59-
* @return void
64+
* @param null|(Closure(class-string<Transformer>): Transformer) $dependencyInjectionHandler
6065
*/
66+
public function registerCustomDependencyInjectionHandler(
67+
?Closure $dependencyInjectionHandler
68+
): void {
69+
$this->dependencyInjectionHandler = $dependencyInjectionHandler;
70+
}
71+
6172
public function register(): void
6273
{
6374
$this->loadTransformers();
6475
}
6576

77+
private function loadTransformers(): void
78+
{
79+
foreach ($this->transformers as $transformer) {
80+
$this->loadTransformer($transformer);
81+
}
82+
}
83+
6684
/**
67-
* Get the transformer instances.
68-
*
69-
* @return void
85+
* @param class-string<Transformer> $transformerClassName
7086
*
7187
* @noinspection PhpUnhandledExceptionInspection
7288
* @noinspection PhpDocMissingThrowsInspection
7389
*/
74-
private function loadTransformers(): void
90+
private function loadTransformer(mixed $transformerClassName): void
7591
{
76-
foreach ($this->transformers as $transformer) {
77-
// Instantiate the transformer
92+
// Check if the transformer is already loaded
93+
if (array_key_exists($transformerClassName, $this->transformerContainers)) {
94+
// @codeCoverageIgnoreStart
95+
return;
96+
// @codeCoverageIgnoreEnd
97+
}
98+
99+
// Validate the transformer
100+
if (gettype($transformerClassName) !== 'string') {
101+
throw new InvalidTransformerClassNameException;
102+
}
103+
104+
// Instantiate the transformer
105+
if ($this->dependencyInjectionHandler) {
106+
$transformerInstance = ($this->dependencyInjectionHandler)($transformerClassName);
107+
} else {
78108
try {
79-
$transformerInstance = DI::make($transformer);
109+
$transformerInstance = DI::make($transformerClassName);
80110
} catch (Error|Exception) {
81-
throw new TransformerNotFoundException($transformer);
111+
throw new TransformerNotFoundException($transformerClassName);
82112
}
113+
}
83114

84-
// Validate the transformer
85-
$isTransformer = $transformerInstance instanceof Transformer;
86-
if (!$isTransformer) {
87-
throw new InvalidTransformerClassException($transformer);
88-
}
89-
assert($transformerInstance instanceof Transformer);
115+
// Validate the transformer
116+
$isTransformer = $transformerInstance instanceof Transformer;
117+
if (!$isTransformer) {
118+
throw new InvalidTransformerClassException($transformerClassName);
119+
}
90120

91-
// Create transformer container
92-
$transformerContainer = DI::make(TransformerContainer::class, [
93-
'transformerInstance' => $transformerInstance,
94-
]);
121+
// Create transformer container
122+
$transformerContainer = DI::make(TransformerContainer::class, [
123+
'transformerInstance' => $transformerInstance,
124+
]);
95125

96-
// Create a reflection of the transformer
97-
$transformerRefClass = new BaseReflectionClass($transformerInstance);
126+
// Create a reflection of the transformer
127+
$transformerRefClass = new BaseReflectionClass($transformerInstance);
98128

99-
$filePath = $transformerRefClass->getFileName();
100-
$this->transformerContainers[$filePath] = $transformerContainer;
101-
}
129+
$filePath = $transformerRefClass->getFileName();
130+
$this->transformerContainers[$filePath] = $transformerContainer;
102131
}
103132

104133
// endregion
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
namespace Okapi\CodeTransformer\Core\Exception\Transformer;
4+
5+
use Okapi\CodeTransformer\Core\Exception\TransformerException;
6+
7+
class InvalidTransformerClassNameException extends TransformerException
8+
{
9+
public function __construct()
10+
{
11+
parent::__construct(
12+
'Transformer class name in Kernel must be a string.',
13+
);
14+
}
15+
}

tests/Functional/ReplaceStringInClassTest.php renamed to tests/Functional/Cache/CachedFileAndDestructor/CachedFileAndDestructorTest.php

+10-11
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,26 @@
11
<?php
22

3-
namespace Okapi\CodeTransformer\Tests\Functional;
3+
namespace Okapi\CodeTransformer\Tests\Functional\Cache\CachedFileAndDestructor;
44

55
use Okapi\CodeTransformer\Core\Cache\CacheStateManager;
66
use Okapi\CodeTransformer\Core\DI;
77
use Okapi\CodeTransformer\Tests\ClassLoaderMockTrait;
8-
use Okapi\CodeTransformer\Tests\Stubs\ClassesToTransform\StringClass;
9-
use Okapi\CodeTransformer\Tests\Stubs\Kernel\ApplicationKernel;
10-
use Okapi\CodeTransformer\Tests\Stubs\Transformer\StringTransformer;
8+
use Okapi\CodeTransformer\Tests\Functional\Cache\CachedFileAndDestructor\Target\StringClass;
9+
use Okapi\CodeTransformer\Tests\Functional\Cache\CachedFileAndDestructor\Transformer\StringTransformer;
1110
use Okapi\CodeTransformer\Tests\Util;
1211
use Okapi\Filesystem\Filesystem;
1312
use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
1413
use PHPUnit\Framework\TestCase;
1514

1615
#[RunTestsInSeparateProcesses]
17-
class ReplaceStringInClassTest extends TestCase
16+
class CachedFileAndDestructorTest extends TestCase
1817
{
1918
use ClassLoaderMockTrait;
2019

2120
public function testReplaceStringInClass(): void
2221
{
2322
Util::clearCache();
24-
ApplicationKernel::init();
23+
Kernel::init();
2524

2625
$class = StringClass::class;
2726
$this->assertWillBeTransformed($class);
@@ -32,7 +31,7 @@ public function testReplaceStringInClass(): void
3231
$stringClass->test(),
3332
);
3433

35-
$file = Util::CLASSES_TO_TRANSFORM_DIR . '/StringClass.php';
34+
$file = Util::getFilePath(StringClass::class);
3635
$content = Filesystem::readFile($file);
3736

3837
$this->assertEquals(
@@ -43,7 +42,7 @@ public function testReplaceStringInClass(): void
4342

4443
public function testCachedReplaceStringClass(): void
4544
{
46-
ApplicationKernel::init();
45+
Kernel::init();
4746

4847
$class = StringClass::class;
4948
$this->assertTransformerLoadedFromCache($class);
@@ -57,7 +56,7 @@ public function testCachedReplaceStringClass(): void
5756

5857
public function testCachedFile(): void
5958
{
60-
$cachedFilePath = Util::CACHED_CLASSES_TO_TRANSFORM_DIR . '/StringClass.php';
59+
$cachedFilePath = Util::getTransformedFilePath(StringClass::class);
6160

6261
$this->assertFileExists($cachedFilePath);
6362
$file = Filesystem::readFile($cachedFilePath);
@@ -76,7 +75,7 @@ public function testCachedFile(): void
7675
public function testDestructor(): void
7776
{
7877
Util::clearCache();
79-
ApplicationKernel::init();
78+
Kernel::init();
8079

8180
$class = StringClass::class;
8281
$stringClass = new $class();
@@ -89,7 +88,7 @@ public function testDestructor(): void
8988

9089
$file = require Util::CACHE_STATES_FILE;
9190

92-
$key = 'CODE_TRANSFORMER_APP_DIR\tests\Stubs\ClassesToTransform\StringClass.php';
91+
$key = 'CODE_TRANSFORMER_APP_DIR\tests\Functional\Cache\CachedFileAndDestructor\Target\StringClass.php';
9392
$key = str_replace('\\', DIRECTORY_SEPARATOR, $key);
9493
$this->assertArrayHasKey($key, $file);
9594
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Okapi\CodeTransformer\Tests\Functional\Cache\CachedFileAndDestructor;
4+
5+
use Okapi\CodeTransformer\CodeTransformerKernel;
6+
use Okapi\CodeTransformer\Tests\Functional\Cache\CachedFileAndDestructor\Transformer\StringTransformer;
7+
use Okapi\CodeTransformer\Tests\Util;
8+
9+
class Kernel extends CodeTransformerKernel
10+
{
11+
protected ?string $cacheDir = Util::CACHE_DIR;
12+
13+
protected array $transformers = [
14+
StringTransformer::class,
15+
];
16+
}

tests/Stubs/ClassesToTransform/StringClass.php renamed to tests/Functional/Cache/CachedFileAndDestructor/Target/StringClass.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
namespace Okapi\CodeTransformer\Tests\Stubs\ClassesToTransform;
3+
namespace Okapi\CodeTransformer\Tests\Functional\Cache\CachedFileAndDestructor\Target;
44

55
class StringClass
66
{

tests/Stubs/Transformer/StringTransformer.php renamed to tests/Functional/Cache/CachedFileAndDestructor/Transformer/StringTransformer.php

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<?php
22

3-
namespace Okapi\CodeTransformer\Tests\Stubs\Transformer;
3+
namespace Okapi\CodeTransformer\Tests\Functional\Cache\CachedFileAndDestructor\Transformer;
44

55
use Microsoft\PhpParser\Node\StringLiteral;
6-
use Okapi\CodeTransformer\Tests\Stubs\ClassesToTransform\MultipleTransformersClass;
7-
use Okapi\CodeTransformer\Tests\Stubs\ClassesToTransform\StringClass;
6+
use Okapi\CodeTransformer\Tests\Functional\Cache\CachedFileAndDestructor\Target\StringClass;
7+
use Okapi\CodeTransformer\Tests\Functional\Transformer\MultipleTransformer\TargetClass;
88
use Okapi\CodeTransformer\Transformer;
99
use Okapi\CodeTransformer\Transformer\Code;
1010

@@ -14,7 +14,7 @@ class StringTransformer extends Transformer
1414

1515
public function getTargetClass(): string|array
1616
{
17-
return [StringClass::class, 'Okapi*Tests*StringClass', MultipleTransformersClass::class];
17+
return [StringClass::class, 'Okapi*Tests*StringClass', TargetClass::class];
1818
}
1919

2020
public function transform(Code $code): void

tests/Functional/DeleteCacheFileTest.php renamed to tests/Functional/Cache/DeleteCacheFile/DeleteCacheFileTest.php

+6-8
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
<?php
22

3-
namespace Okapi\CodeTransformer\Tests\Functional;
3+
namespace Okapi\CodeTransformer\Tests\Functional\Cache\DeleteCacheFile;
44

55
use Okapi\CodeTransformer\Tests\ClassLoaderMockTrait;
6-
use Okapi\CodeTransformer\Tests\Stubs\ClassesToTransform\DeleteCacheFileClass;
7-
use Okapi\CodeTransformer\Tests\Stubs\Kernel\ApplicationKernel;
86
use Okapi\CodeTransformer\Tests\Util;
97
use Okapi\Filesystem\Filesystem;
108
use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
@@ -18,9 +16,9 @@ class DeleteCacheFileTest extends TestCase
1816
public function testDeleteCacheFileClass(): void
1917
{
2018
Util::clearCache();
21-
ApplicationKernel::init();
19+
Kernel::init();
2220

23-
$class = DeleteCacheFileClass::class;
21+
$class = Target::class;
2422
$this->assertWillBeTransformed($class);
2523

2624
$deleteCacheFileClass = new $class();
@@ -32,15 +30,15 @@ public function testDeleteCacheFileClass(): void
3230

3331
public function testCachedDeleteCacheFileClass(): void
3432
{
35-
ApplicationKernel::init();
33+
Kernel::init();
3634

37-
$cachedFilePath = Util::CACHED_CLASSES_TO_TRANSFORM_DIR . '/DeleteCacheFileClass.php';
35+
$cachedFilePath = Util::getTransformedFilePath(Target::class);
3836

3937
$this->assertFileExists($cachedFilePath);
4038
Filesystem::rm($cachedFilePath);
4139
$this->assertFileDoesNotExist($cachedFilePath);
4240

43-
$class = DeleteCacheFileClass::class;
41+
$class = Target::class;
4442
$this->assertWillBeTransformed($class);
4543

4644
$deleteCacheFileClass = new $class();

0 commit comments

Comments
 (0)