Skip to content

Develop #1

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

Merged
merged 18 commits into from
Apr 19, 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
1 change: 1 addition & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ ij_php_align_key_value_pairs = true
ij_php_align_multiline_parameters_in_calls = true
ij_php_align_phpdoc_comments = true
ij_php_align_phpdoc_param_names = true
ij_php_blank_lines_before_package = 0
ij_php_comma_after_last_argument = true
ij_php_comma_after_last_array_element = true
ij_php_comma_after_last_closure_use_var = true
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ class Kernel extends CodeTransformerKernel

<?php

use Okapi\CodeTransformer\Service\StreamFilter\Metadata\Code;
use Okapi\CodeTransformer\Transformer;
use Okapi\CodeTransformer\Transformer\Code;

// Extend from the "Transformer" class
class StringTransformer extends Transformer
Expand All @@ -112,12 +112,12 @@ class StringTransformer extends Transformer
{
// I recommend using the Microsoft\PhpParser library to parse the source
// code. It's already included in the dependencies of this package and
// the "$code->sourceFileNode" property contains the parsed source code.
// the "$code->getSourceFileNode()" property contains the parsed source code.

// But you can also use any other library or manually parse the source
// code with basic PHP string functions and "$code->getOriginalSource()"

$sourceFileNode = $code->sourceFileNode;
$sourceFileNode = $code->getSourceFileNode();

// Iterate over all nodes
foreach ($sourceFileNode->getDescendantNodes() as $node) {
Expand Down Expand Up @@ -155,8 +155,8 @@ class StringTransformer extends Transformer
namespace Okapi\CodeTransformer\Tests\Stubs\Transformer;

use Microsoft\PhpParser\TokenKind;
use Okapi\CodeTransformer\Service\StreamFilter\Metadata\Code;
use Okapi\CodeTransformer\Transformer;
use Okapi\CodeTransformer\Transformer\Code;

// Replace all "private" keywords with "public"
class UnPrivateTransformer extends Transformer
Expand All @@ -168,7 +168,7 @@ class UnPrivateTransformer extends Transformer

public function transform(Code $code): void
{
$sourceFileNode = $code->sourceFileNode;
$sourceFileNode = $code->getSourceFileNode();

// Iterate over all tokens
foreach ($sourceFileNode->getDescendantTokens() as $token) {
Expand Down
27 changes: 27 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# 1. Class Name matching
Optimize the class name matching by using efficient data structures or
algorithms (e.g. trie-based matching or regular expressions).

# 2. Cache management
More sophisticated cache management strategy, such as Least Recently Used (LRU)
or Time-To-Live (TTL) based eviction, to ensure that cache remains up-to-date
and efficient.

# 3. Parallelization
Parallelize the process of matching and transforming classes and methods to
reduce the overall processing time.

# 4. Incremental updates
Incremental update mechanism to process only new or changed classes and methods.

# 5. Monitoring
Monitor the performance of the library to identify bottlenecks and areas that
need optimization (e.g. Profilers or benchmarking suites).

# 6. Documentation
- Document how to use xdebug with php-unit tests that use the
`#[RunTestsInSeparateProcesses]` attribute (PhpStorm)
- Create a flowchart

# 7. Testing
- Add tests for the `order` property of the `Transformer` class
11 changes: 8 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "okapi/code-transformer",
"description": "PHP Code Transformer is a PHP library that allows you to modify and transform the source code of a loaded PHP class.",
"version": "1.1.1",
"version": "1.2.0",
"type": "library",
"homepage": "https://github.com/okapi-web/php-code-transformer",
"license": "MIT",
Expand All @@ -28,7 +28,9 @@
"okapi/filesystem": "^1.0",
"okapi/path": "^1.0",
"okapi/singleton": "^1.0",
"okapi/wildcards": "^1.0"
"okapi/wildcards": "^1.0",
"php-di/php-di": "^7.0",
"roave/better-reflection": "^6.8"
},
"require-dev": {
"phpunit/phpunit": "dev-main",
Expand All @@ -37,7 +39,10 @@
"autoload": {
"psr-4": {
"Okapi\\CodeTransformer\\": "src/"
}
},
"files": [
"src/functions.php"
]
},
"autoload-dev": {
"psr-4": {
Expand Down
164 changes: 119 additions & 45 deletions src/CodeTransformerKernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@

namespace Okapi\CodeTransformer;

use Okapi\CodeTransformer\Exception\Kernel\DirectKernelInitializationException;
use Okapi\CodeTransformer\Service\AutoloadInterceptor;
use Okapi\CodeTransformer\Service\CacheStateManager;
use Okapi\CodeTransformer\Service\Options;
use Okapi\CodeTransformer\Service\StreamFilter;
use Okapi\CodeTransformer\Service\TransformerContainer;
use DI\Attribute\Inject;
use Okapi\CodeTransformer\Core\AutoloadInterceptor;
use Okapi\CodeTransformer\Core\Cache\CacheStateManager;
use Okapi\CodeTransformer\Core\Container\TransformerManager;
use Okapi\CodeTransformer\Core\DI;
use Okapi\CodeTransformer\Core\Exception\Kernel\DirectKernelInitializationException;
use Okapi\CodeTransformer\Core\Options;
use Okapi\CodeTransformer\Core\StreamFilter;
use Okapi\Singleton\Singleton;

/**
* # Code Transformer Kernel
*
* The `CodeTransformerKernel` is the heart of the Code Transformer library.
* This class is the heart of the Code Transformer library.
* It manages an environment for Code Transformation.
*
* 1. Extends this class and define a list of transformers in the
Expand All @@ -24,6 +26,58 @@ abstract class CodeTransformerKernel
{
use Singleton;

// region DI

#[Inject]
private Options $options;

#[Inject]
protected TransformerManager $transformerContainer;

#[Inject]
private CacheStateManager $cacheStateManager;

#[Inject]
private StreamFilter $streamFilter;

#[Inject]
private AutoloadInterceptor $autoloadInterceptor;

/**
* Make the constructor public to allow the DI container to instantiate the class.
*/
public function __construct() {}

// endregion

// region Settings

/**
* The cache directory.
* <br><b>Default:</b> ROOT_DIR/cache/code-transformer<br>
*
* @var string|null
*/
protected ?string $cacheDir = null;

/**
* The cache file mode.
* <br><b>Default:</b> 0777 & ~{@link umask()}<br>
*
* @var int|null
*/
protected ?int $cacheFileMode = null;

/**
* Enable debug mode. This will disable the cache.
* <br><b>Default:</b> false<br>
*
* @var bool
*/
protected bool $debug = false;

// endregion

/**
* List of transformers to be applied.
*
Expand All @@ -32,47 +86,67 @@ abstract class CodeTransformerKernel
protected array $transformers = [];

/**
* Initialize the kernel.
* Resolve instance with dependency injection.
*
* @param string|null $cacheDir The cache directory.
* <br><b>Default:</b> ROOT_DIR/cache/code-transformer<br>
* @param int|null $cacheFileMode The cache file mode.
* <br><b>Default:</b> 0777 & ~{@link umask()}<br>
* @param bool|null $debug Enable debug mode. This will disable the cache.
* <br><b>Default:</b> false<br>
* @inheritDoc
*/
public static function getInstance(): static
{
if (!isset(static::$instance)) {
static::registerDependencyInjection();

static::$instance = DI::get(static::class);
}

return static::$instance;
}

/**
* Initialize the kernel.
*
* @return void
*/
public static function init(
?string $cacheDir,
?int $cacheFileMode = null,
bool $debug = false,
): void {
self::ensureNotKernelNamespace();

$instance = self::getInstance();
$instance->ensureNotInitialized();
public static function init(): void
{
static::ensureNotKernelNamespace();

// Only initialize the kernel if there are transformers
if ($instance->transformers) {
// Pre-initialize the services
$instance = static::getInstance();
$instance->ensureNotInitialized();

// Set options
Options::setOptions(
cacheDir: $cacheDir,
cacheFileMode: $cacheFileMode,
debug: $debug,
);
// Initialize the services
$instance->preInit();
$instance->registerServices();
$instance->registerAutoloadInterceptor();

// Add the transformers
TransformerContainer::addTransformers($instance->transformers);
$instance->setInitialized();
}

// Register the services
$instance->registerServices();
$instance->registerAutoloadInterceptor();
}
/**
* Register the dependency injection.
*
* @return void
*/
protected static function registerDependencyInjection(): void
{
DI::getInstance()->register();
}

$instance->setInitialized();
/**
* Pre-initialize the services.
*
* @return void
*/
protected function preInit(): void
{
// Set options
$this->options->setOptions(
cacheDir: $this->cacheDir,
cacheFileMode: $this->cacheFileMode,
debug: $this->debug,
);

// Add the transformers
$this->transformerContainer->addTransformers($this->transformers);
}

/**
Expand All @@ -83,16 +157,16 @@ public static function init(
protected function registerServices(): void
{
// Options provider
Options::register();
$this->options->register();

// Manage the user-defined transformers
TransformerContainer::register();
$this->transformerContainer->register();

// Cache path manager
CacheStateManager::register();
$this->cacheStateManager->register();

// Stream filter -> Source transformer
StreamFilter::register();
$this->streamFilter->register();
}

/**
Expand All @@ -103,15 +177,15 @@ protected function registerServices(): void
protected function registerAutoloadInterceptor(): void
{
// Overload the composer class loaders
AutoloadInterceptor::register();
$this->autoloadInterceptor->register();
}

/**
* Make sure that the kernel is not called from this class.
*
* @return void
*/
private static function ensureNotKernelNamespace(): void
protected static function ensureNotKernelNamespace(): void
{
// Get current namespace and class name
$namespace = get_called_class();
Expand Down
Loading