diff --git a/.gitignore b/.gitignore index 136335f..1fbf909 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ build /.phpcs-cache .phpunit.result.cache /coverage.xml +/tests/Fake/tmp diff --git a/README.md b/README.md index 6c1a990..da10ab3 100644 --- a/README.md +++ b/README.md @@ -9,60 +9,20 @@ Ray.Compiler compiles Ray.Di bindings into PHP code, providing a performance boost that makes Dependency Injection couldn't be any faster. -## Script Injector +## Compile Injector -`ScriptInjector` has the same interface as Ray.Di Injector; whereas Ray.Di Injector resolves dependencies based on memory bindings, ScriptInjector executes pre-compiled PHP code and is faster. +`CompileInjector` is designed to enhance performance by utilizing `Compiler` to compile modules and initializing `AirInjector` for managing dependencies. This approach ensures efficient dependency management and faster execution. -Ray.Di injector ```php -$injector = new Injector(new CarModule); // Ray.Di injector -``` - -Ray.Compiler injector -```php -$injector = new ScriptInjector($tmpDir, fn => new CarModule); +$injector = new CompileInjector($tmpDir, fn => new CarModule); +$car = $injector->getInstance(CarInterface::class); ``` ## Precompile -You will want to compile all dependencies into code before deploying the production. The `DiCompiler` will compile all bindings into PHP code. +You will want to compile all dependencies into code before deploying the production. ```php -$compiler = new DiCompiler(new CarModule, $tmpDir); +$compiler = new Compiler($tmpDir, new CarModule); $compiler->compile(); ``` - -## Object graph visualization - -Object graph can be visualized with `dumpGraph()`. -Graph HTML files will be output at `graph` folder under `$tmpDir`. - -```php -$compiler = new DiCompiler(new Module, $tmpDir); -$compiler->compile(); -$compiler->dumpGraph(); -``` - -``` -open tmp/graph/Ray_Compiler_FakeCarInterface-.html -``` - -## CompileInjector - -The `CompileInjector` gives you the best performance in both development (x2) and production (x10) by switching two injector. - -Get the injector by specifying the binding and cache, depending on the execution context of the application. - -```php -$injector = new CompileInjector($tmpDir, $injectorContext); -``` - -`$injectorContext` example: - - * [dev](docs/exmaple/DevInjectorContext.php) - * [prod](docs/exmaple/ProdInjectorContext.php) - -The `__invoke()` method prepares the modules needed in that context. -The `getCache()` method specifies the cache of the injector itself. - -Install `DiCompileModule` in the context for production. The injector is more optimized and dependency errors are reported at compile-time instead of run-time. diff --git a/composer-require-checker.json b/composer-require-checker.json index 1731fe8..9123139 100644 --- a/composer-require-checker.json +++ b/composer-require-checker.json @@ -4,19 +4,8 @@ "static", "self", "parent", "array", "string", "int", "float", "bool", "iterable", "callable", "void", "object", "Attribute", "ReflectionAttribute", - "Ray\\Di\\AbstractModule", "Ray\\Di\\Annotation\\ScriptDir", - "Ray\\Di\\Argument", "Ray\\Di\\Arguments", - "Ray\\Di\\AssistedModule", "Ray\\Di\\Bind", - "Ray\\Di\\Container", "Ray\\Di\\Dependency", - "Ray\\Di\\DependencyInterface","Ray\\Di\\DependencyProvider", - "Ray\\Di\\Di\\Qualifier", "Ray\\Di\\Exception\\NotFound", - "Ray\\Di\\Exception\\Unbound", "Ray\\Di\\InjectionPointInterface", - "Ray\\Di\\Injector", "Ray\\Di\\InjectorInterface", "Ray\\Di\\Instance", - "Ray\\Di\\MultiBinding\\Map", "Ray\\Di\\MultiBinding\\MapProvider", - "Ray\\Di\\Name", "Ray\\Di\\NullCache", - "Ray\\Di\\NullModule", "Ray\\Di\\NullObjectDependency", - "Ray\\Di\\ProviderInterface", "Ray\\Di\\ProviderSetModule", - "Ray\\Di\\SetContextInterface" - + "Doctrine\\Common\\Annotations\\Reader", + "Doctrine\\Common\\Cache\\CacheProvider", + "Koriym\\Printo\\Printo" ] } diff --git a/composer.json b/composer.json index 8c44678..d162dcf 100644 --- a/composer.json +++ b/composer.json @@ -12,20 +12,17 @@ ], "require": { "php": "^7.2 || ^8.0", - "doctrine/annotations": "^1.12 || ^2.0", - "doctrine/cache": "^1.10 || ^2.1", "koriym/attributes": "^1.0", "koriym/null-object": "^1.0", "koriym/param-reader": "^1.0", - "koriym/printo": "^1.0", - "nikic/php-parser": "^4.5 || ^5.0", - "ray/aop": "^2.14" + "ray/aop": "^2.15", + "ray/di": "^2.17.1" }, "require-dev": { "ext-pdo": "*", - "ray/di": "^2.16", - "phpunit/phpunit": "^8.5.24 || ^9.5", - "bamarni/composer-bin-plugin": "^1.4" + "bamarni/composer-bin-plugin": "^1.4", + "doctrine/cache": "^1.0 || ^2.2", + "phpunit/phpunit": "^8.5.24 || ^9.5" }, "config": { "sort-packages": true, @@ -35,7 +32,7 @@ }, "autoload": { "psr-4": { - "Ray\\Compiler\\": ["src", "src-deprecated"] + "Ray\\Compiler\\": ["src", "src-cached-injector-factory", "src-deprecated"] } }, "autoload-dev": { @@ -53,10 +50,11 @@ "cs": ["phpcs --standard=./phpcs.xml src tests"], "cs-fix": ["phpcbf src tests"], "clean": ["phpstan clear-result-cache", "psalm --clear-cache", "rm -rf tests/tmp/*.php"], - "sa": ["psalm -c psalm.compiler.xml --show-info=true", "phpstan analyse -c phpstan.neon --no-progress"], + "sa": ["psalm -c psalm.compiler.xml --show-info=false", "phpstan analyse -c phpstan.neon --no-progress"], "metrics": ["@test", "phpmetrics --report-html=build/metrics --exclude=Exception --log-junit=build/junit.xml --junit=build/junit.xml src"], - "phpmd": ["phpmd src/di text ./phpmd.xml"], - "build": ["@cs", "@sa", "@pcov", "@metrics"] + "phpmd": ["phpmd src text ./phpmd.xml"], + "build": ["@cs", "@sa", "@pcov", "@metrics"], + "req-check": ["./vendor/bin/composer-require-checker"] }, "extra": { "bamarni-bin": { diff --git a/docs/exmaple/DevInjectorContext.php b/docs/exmaple/DevInjectorContext.php index af16204..9f44d5c 100644 --- a/docs/exmaple/DevInjectorContext.php +++ b/docs/exmaple/DevInjectorContext.php @@ -2,11 +2,8 @@ declare(strict_types=1); -use Doctrine\Common\Cache\ApcuCache; use Doctrine\Common\Cache\CacheProvider; use Ray\Compiler\AbstractInjectorContext; -use Ray\Compiler\DiCompileModule; -use Ray\Compiler\FakeCarModule; use Ray\Di\AbstractModule; use Ray\Di\NullCache; diff --git a/docs/exmaple/ProdInjectorContext.php b/docs/exmaple/ProdInjectorContext.php index 8324169..38e8e75 100644 --- a/docs/exmaple/ProdInjectorContext.php +++ b/docs/exmaple/ProdInjectorContext.php @@ -6,7 +6,6 @@ use Doctrine\Common\Cache\CacheProvider; use Ray\Compiler\AbstractInjectorContext; use Ray\Compiler\DiCompileModule; -use Ray\Compiler\FakeCarModule; use Ray\Di\AbstractModule; final class ProdInjectorContext extends AbstractInjectorContext diff --git a/phpcs.xml b/phpcs.xml index 9c3efa3..3e16b06 100755 --- a/phpcs.xml +++ b/phpcs.xml @@ -28,6 +28,7 @@ + @@ -39,6 +40,7 @@ + diff --git a/phpstan.neon b/phpstan.neon index b6e0c77..c7f9f70 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -6,5 +6,4 @@ parameters: excludePaths: - tests/tmp/* - tests/Fake/* - checkGenericClassInNonGenericObjectType: false diff --git a/src/AbstractInjectorContext.php b/src-cached-injector-factory/AbstractInjectorContext.php similarity index 100% rename from src/AbstractInjectorContext.php rename to src-cached-injector-factory/AbstractInjectorContext.php diff --git a/src/CachedInjectorFactory.php b/src-cached-injector-factory/CachedInjectorFactory.php similarity index 92% rename from src/CachedInjectorFactory.php rename to src-cached-injector-factory/CachedInjectorFactory.php index d9fdc38..095a31d 100644 --- a/src/CachedInjectorFactory.php +++ b/src-cached-injector-factory/CachedInjectorFactory.php @@ -7,14 +7,19 @@ use Doctrine\Common\Cache\CacheProvider; use Ray\Di\AbstractModule; use Ray\Di\InjectorInterface; -use Ray\Di\NullCache; - use function assert; +use function class_exists; use function serialize; use function unserialize; final class CachedInjectorFactory { + public function __construct() + { + if (! class_exists(CacheProvider::class)) { + throw new \RuntimeException('CachedInjectorFactory requires doctrine/cache'); + } + } /** @var array */ private static $injectors = []; diff --git a/src/ContextInjector.php b/src-cached-injector-factory/ContextInjector.php similarity index 100% rename from src/ContextInjector.php rename to src-cached-injector-factory/ContextInjector.php diff --git a/src/InjectorFactory.php b/src-cached-injector-factory/InjectorFactory.php similarity index 98% rename from src/InjectorFactory.php rename to src-cached-injector-factory/InjectorFactory.php index 07481ed..2d258e1 100644 --- a/src/InjectorFactory.php +++ b/src-cached-injector-factory/InjectorFactory.php @@ -9,13 +9,10 @@ use Ray\Di\Exception\Unbound; use Ray\Di\Injector as RayInjector; use Ray\Di\InjectorInterface; - use function is_dir; use function mkdir; -/** - * @psalm-immutable - */ +/** @psalm-immutable */ final class InjectorFactory { /** diff --git a/src-cached-injector-factory/NullCache.php b/src-cached-injector-factory/NullCache.php new file mode 100644 index 0000000..0d45c1d --- /dev/null +++ b/src-cached-injector-factory/NullCache.php @@ -0,0 +1,58 @@ +module = $module; + $this->scriptDir = $scriptDir; + $this->injector = new AirInjector($scriptDir); + $injectorModule = new class ($this->injector) extends AbstractModule { + private $injector; + + public function __construct(InjectorInterface $injector) + { + $this->injector = $injector; + } + + protected function configure() + { + $this->bind(InjectorInterface::class)->toInstance($this->injector); + } + }; + $module->install($injectorModule); + (new Compiler())->compile($module, $scriptDir); + } + + /** + * {@inheritdoc} + */ + public function getInstance($interface, $name = Name::ANY) + { + return $this->injector->getInstance($interface, $name); + } + + /** @deprecated */ + public function compile(): void + { + } + + /** @deprecated */ + public function savePointcuts(): void + { + } + + /** @deprecated */ + public function dumpGraph(): void + { + } +} diff --git a/src/GraphDumper.php b/src-deprecated/GraphDumper.php similarity index 98% rename from src/GraphDumper.php rename to src-deprecated/GraphDumper.php index 4a25138..afb3bbc 100644 --- a/src/GraphDumper.php +++ b/src-deprecated/GraphDumper.php @@ -7,7 +7,6 @@ use Koriym\Printo\Printo; use Ray\Di\Container; use Ray\Di\Name; - use function assert; use function class_exists; use function explode; @@ -16,9 +15,9 @@ use function interface_exists; use function mkdir; use function str_replace; - use const LOCK_EX; +/** @deprecated */ final class GraphDumper { /** @var Container */ diff --git a/src/IpQualifier.php b/src-deprecated/IpQualifier.php similarity index 96% rename from src/IpQualifier.php rename to src-deprecated/IpQualifier.php index 39606a7..7459106 100644 --- a/src/IpQualifier.php +++ b/src-deprecated/IpQualifier.php @@ -5,9 +5,9 @@ namespace Ray\Compiler; use ReflectionParameter; - use function serialize; +/** @deprecated */ final class IpQualifier { /** @var ReflectionParameter */ diff --git a/src-deprecated/OnDemandCompiler.php b/src-deprecated/OnDemandCompiler.php new file mode 100644 index 0000000..9b4fc13 --- /dev/null +++ b/src-deprecated/OnDemandCompiler.php @@ -0,0 +1,22 @@ +compile($module, $scriptDir); + $this->injector = new AirInjector($scriptDir); + $this->scriptDir = $scriptDir; + } + + /** + * {@inheritdoc} + */ + public function getInstance($interface, $name = Name::ANY) + { + return $this->injector->getInstance($interface, $name); + } + + public function clear(): void + { + $unlink = static function (string $path) use (&$unlink): void { + foreach ((array) glob(rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . '*') as $f) { + $file = (string) $f; + is_dir($file) ? $unlink($file) : unlink($file); + @rmdir($file); + } + }; + $unlink($this->scriptDir); + } +} diff --git a/src/ScriptinjectorModule.php b/src-deprecated/ScriptinjectorModule.php similarity index 96% rename from src/ScriptinjectorModule.php rename to src-deprecated/ScriptinjectorModule.php index 1008c5a..d062f81 100644 --- a/src/ScriptinjectorModule.php +++ b/src-deprecated/ScriptinjectorModule.php @@ -7,6 +7,7 @@ use Ray\Di\AbstractModule; use Ray\Di\InjectorInterface; +/** @deprecated */ class ScriptinjectorModule extends AbstractModule { /** @var string */ diff --git a/src/AirInjector.php b/src/AirInjector.php new file mode 100644 index 0000000..fe7146d --- /dev/null +++ b/src/AirInjector.php @@ -0,0 +1,173 @@ + + */ + private $singletons = []; + + /** @var array */ + private static $scriptDirs = []; + + /** + * @param string $scriptDir generated instance script folder path + * + * @psalm-suppress UnresolvableInclude + */ + public function __construct($scriptDir) + { + $this->scriptDir = $scriptDir; + $this->registerLoader(); + } + + public function __wakeup() + { + $this->registerLoader(); + } + + /** + * {@inheritdoc} + * + * @SuppressWarnings(PHPMD.UnusedLocalVariable) + * @psalm-suppress UnresolvableInclude + */ + public function getInstance($interface, $name = Name::ANY) + { + static $prototype; + static $singleton; + static $injector; + static $injectionPoint; + + if ($prototype === null) { + $injectionPoint = function (): InjectionPoint { + if ($this->ip[0] === '') { + throw new InjectionPointUnbound(); + } + + return new InjectionPoint( + new ReflectionParameter([$this->ip[0], $this->ip[1]], $this->ip[2]) + ); + }; + + $injector = function (): self { + return $this; + }; + + $prototype = + /** + * @param array{0: string, 1: string, 2: string} $ip + * + * @return mixed + */ + function (string $dependencyIndex, array $ip = ['', '', '']) use ($injectionPoint, &$prototype, $injector, &$singleton) { // @phpstan-ignore-line + $this->ip = $ip; // @phpstan-ignore-line + + return require $this->getInstanceFile($dependencyIndex); + }; + $singleton = + /** + * @param array{0: string, 1: string, 2: string} $ip + * + * @return mixed + */ + function (string $dependencyIndex, $ip = ['', '', '']) use ($injectionPoint, $prototype, $injector, &$singleton) { // @phpstan-ignore-line + if (isset($this->singletons[$dependencyIndex])) { + return $this->singletons[$dependencyIndex]; + } + + $this->ip = $ip; + + $instance = require $this->getInstanceFile($dependencyIndex); + $this->singletons[$dependencyIndex] = $instance; + + return $instance; + }; + $scriptDir = $this->scriptDir; + } + + $dependencyIndex = $interface . '-' . $name; + if (isset($this->singletons[$dependencyIndex])) { + return $this->singletons[$dependencyIndex]; + } + + /** @psalm-suppress UnresolvableInclude */ + $instance = require $this->getInstanceFile($dependencyIndex); + /** @psalm-suppress UndefinedVariable */ + $isSingleton = isset($isSingleton) && $isSingleton; + if ($isSingleton) { + $this->singletons[$dependencyIndex] = $instance; + } + + /** + * @psalm-var T $instance + * @phpstan-var mixed $instance + */ + return $instance; + } + + /** + * Return compiled script file name + */ + private function getInstanceFile(string $dependencyIndex): string + { + $file = sprintf('%s/%s.php', $this->scriptDir, str_replace('\\', '_', $dependencyIndex)); + if (file_exists($file)) { + return $file; + } + + throw new Unbound($dependencyIndex); + } + + private function registerLoader(): void + { + if (in_array($this->scriptDir, self::$scriptDirs, true)) { + return; + } + + if (self::$scriptDirs === []) { + spl_autoload_register( + static function (string $class): void { + foreach (self::$scriptDirs as $scriptDir) { + $file = sprintf('%s/%s.php', $scriptDir, str_replace('\\', '_', $class)); + if (file_exists($file)) { + require_once $file; // @codeCoverageIgnore + } + } + } + ); + } + + self::$scriptDirs[] = $this->scriptDir; + } +} diff --git a/src/AopCode.php b/src/AopCode.php deleted file mode 100644 index e88c9e1..0000000 --- a/src/AopCode.php +++ /dev/null @@ -1,93 +0,0 @@ -privateProperty = $privateProperty; - } - - /** - * Add aop factory code if bindings are given - * - * @param array $node - * - * @param-out array $node - */ - public function __invoke(Dependency $dependency, array &$node): void - { - $prop = $this->privateProperty; - /** @var ?NewInstance */ - $newInstance = $prop($dependency, 'newInstance'); - /** @var ?Bind */ - $bind = $prop($newInstance, 'bind'); - /** @var ?Bind */ - $aspectBind = $prop($bind, 'bind'); - /** @var string[][]|null $bindings */ - $bindings = $prop($aspectBind, 'bindings', null); - if (! is_array($bindings)) { - return; - } - - $methodBinding = $this->getMethodBinding($bindings); - $bindingsProp = new Expr\PropertyFetch(new Expr\Variable('instance'), 'bindings'); - $bindingsAssign = new Assign($bindingsProp, new Expr\Array_($methodBinding)); - $this->setBindingAssignAfterInitialization($node, [$bindingsAssign], 1); - } - - /** - * @param array $array - * @param array $insertValue - * - * @param-out array $array - */ - private function setBindingAssignAfterInitialization(array &$array, array $insertValue, int $position): void - { - $array = array_merge(array_splice($array, 0, $position), $insertValue, $array); - } - - /** - * @param string[][] $bindings - * - * @return Expr\ArrayItem[] - */ - private function getMethodBinding(array $bindings): array - { - $methodBinding = []; - foreach ($bindings as $method => $interceptors) { - $items = []; - foreach ($interceptors as $interceptor) { - // $singleton('FakeAopInterface-*'); - $dependencyIndex = "{$interceptor}-" . Name::ANY; - $singleton = new Expr\FuncCall(new Expr\Variable('singleton'), [new Node\Arg(new Scalar\String_($dependencyIndex))]); - // [$singleton('FakeAopInterface-*'), $singleton('FakeAopInterface-*');] - $items[] = new Expr\ArrayItem($singleton); - } - - $arr = new Expr\Array_($items); - $methodBinding[] = new Expr\ArrayItem($arr, new Scalar\String_($method)); - } - - return $methodBinding; - } -} diff --git a/src/Code.php b/src/Code.php deleted file mode 100644 index 46c4f67..0000000 --- a/src/Code.php +++ /dev/null @@ -1,37 +0,0 @@ -node = $node; - $this->isSingleton = $isSingleton; - $this->qualifiers = $qualifier; - } - - public function __toString(): string - { - $prettyPrinter = new Standard(); - - return $prettyPrinter->prettyPrintFile([$this->node]); - } -} diff --git a/src/CompileInjector.php b/src/CompileInjector.php index 3badda3..f1d40e2 100644 --- a/src/CompileInjector.php +++ b/src/CompileInjector.php @@ -4,209 +4,25 @@ namespace Ray\Compiler; -use Ray\Compiler\Exception\Unbound; -use Ray\Di\Annotation\ScriptDir; -use Ray\Di\Bind; use Ray\Di\Name; -use ReflectionParameter; - -use function file_exists; -use function in_array; -use function rtrim; -use function spl_autoload_register; -use function sprintf; -use function str_replace; -use function touch; final class CompileInjector implements ScriptInjectorInterface { - public const INSTANCE = '%s/%s.php'; - public const COMPILE_CHECK = '%s/compiled'; - - /** @var string */ - private $scriptDir; - - /** - * Injection Point - * - * [$class, $method, $parameter] - * - * @var array{0: string, 1: string, 2: string} - */ - private $ip = ['', '', '']; - - /** - * Singleton instance container - * - * @var array - */ - private $singletons = []; - - /** @var array */ - private $functions; - - /** @var LazyModuleInterface */ - private $lazyModule; - - /** @var array */ - private static $scriptDirs = []; - - /** - * @param string $scriptDir generated instance script folder path - * @param LazyModuleInterface $lazyModule callable variable which return AbstractModule instance - * - * @psalm-suppress UnresolvableInclude - */ - public function __construct($scriptDir, LazyModuleInterface $lazyModule) - { - $this->scriptDir = rtrim($scriptDir, '/'); - $this->lazyModule = $lazyModule; - $this->registerLoader(); - $prototype = - /** - * @param array{0: string, 1: string, 2: string} $injectionPoint - * - * @return mixed - */ - function (string $dependencyIndex, array $injectionPoint = ['', '', '']) { - $this->ip = $injectionPoint; // @phpstan-ignore-line - [$prototype, $singleton, $injectionPoint, $injector] = $this->functions; - - return require $this->getInstanceFile($dependencyIndex); - }; - $singleton = - /** - * @param array{0: string, 1: string, 2: string} $injectionPoint - * - * @return mixed - */ - function (string $dependencyIndex, $injectionPoint = ['', '', '']) { - if (isset($this->singletons[$dependencyIndex])) { - return $this->singletons[$dependencyIndex]; - } - - $this->ip = $injectionPoint; - [$prototype, $singleton, $injectionPoint, $injector] = $this->functions; - - $instance = require $this->getInstanceFile($dependencyIndex); - $this->singletons[$dependencyIndex] = $instance; - - return $instance; - }; - $injectionPoint = function () use ($scriptDir): InjectionPoint { - return new InjectionPoint( - new ReflectionParameter([$this->ip[0], $this->ip[1]], $this->ip[2]), - $scriptDir - ); - }; - $injector = function (): self { - return $this; - }; - $this->functions = [$prototype, $singleton, $injectionPoint, $injector]; - } - - /** - * @return list - */ - public function __sleep() - { - return ['scriptDir', 'singletons', 'lazyModule']; - } + /** @var AirInjector */ + private $injector; - public function __wakeup() + public function __construct(string $scriptDir, LazyModuleInterface $lazy) { - $this->__construct( - $this->scriptDir, - $this->lazyModule - ); + $module = $lazy(); + (new Compiler())->compile($module, $scriptDir); + $this->injector = new AirInjector($scriptDir); } /** * {@inheritdoc} - * - * @SuppressWarnings(PHPMD.UnusedLocalVariable) */ public function getInstance($interface, $name = Name::ANY) { - $dependencyIndex = $interface . '-' . $name; - if (isset($this->singletons[$dependencyIndex])) { - return $this->singletons[$dependencyIndex]; - } - - /** @psalm-suppress DocblockTypeContradiction */ - if ($this->functions === null) { - // @codeCoverageIgnoreStart - $this->__wakeup(); - // @codeCoverageIgnoreEnd - } - - [$prototype, $singleton, $injectionPoint, $injector] = $this->functions; - /** @psalm-suppress UnresolvableInclude */ - $instance = require $this->getInstanceFile($dependencyIndex); - /** @psalm-suppress UndefinedVariable */ - $isSingleton = isset($isSingleton) && $isSingleton; - if ($isSingleton) { - $this->singletons[$dependencyIndex] = $instance; - } - - /** - * @psalm-var T $instance - * @phpstan-var mixed $instance - */ - return $instance; - } - - /** - * Return compiled script file name - */ - private function getInstanceFile(string $dependencyIndex): string - { - $file = sprintf(self::INSTANCE, $this->scriptDir, str_replace('\\', '_', $dependencyIndex)); - if (file_exists($file)) { - return $file; - } - - $checkFile = sprintf(self::COMPILE_CHECK, $this->scriptDir); - if (file_exists($checkFile)) { - throw new Unbound(sprintf('See compile log %s', $this->scriptDir . '/_compile.log')); - } - - touch($checkFile); - $this->compile(); - if (! file_exists($file)) { - throw new Unbound($dependencyIndex); // @codeCoverageIgnore - } - - return $file; - } - - private function registerLoader(): void - { - if (in_array($this->scriptDir, self::$scriptDirs, true)) { - return; - } - - if (self::$scriptDirs === []) { - spl_autoload_register( - static function (string $class): void { - foreach (self::$scriptDirs as $scriptDir) { - $file = sprintf('%s/%s.php', $scriptDir, str_replace('\\', '_', $class)); - if (file_exists($file)) { - require $file; // @codeCoverageIgnore - } - } - } - ); - } - - self::$scriptDirs[] = $this->scriptDir; - } - - public function compile(): void - { - $module = (new InstallBuiltinModule())(($this->lazyModule)()); - (new FilePutContents())(sprintf('%s/_bindings.log', $this->scriptDir), (string) $module); - (new Bind($module->getContainer(), ''))->annotatedWith(ScriptDir::class)->toInstance($this->scriptDir); - (new DiCompiler($module, $this->scriptDir))->compileContainer(); + return $this->injector->getInstance($interface, $name); } } diff --git a/src/CompileNullObject.php b/src/CompileNullObject.php deleted file mode 100644 index c832b1a..0000000 --- a/src/CompileNullObject.php +++ /dev/null @@ -1,29 +0,0 @@ -map(static function (DependencyInterface $dependency) use ($scriptDir) { - if ($dependency instanceof NullObjectDependency) { - return $dependency->toNull($scriptDir); - } - - return $dependency; - }); - } -} diff --git a/src/CompileVisitor.php b/src/CompileVisitor.php new file mode 100644 index 0000000..c67414f --- /dev/null +++ b/src/CompileVisitor.php @@ -0,0 +1,132 @@ +script = new InstanceScript($container); + } + + /** @inheritDoc */ + public function visitDependency( + NewInstance $newInstance, + ?string $postConstruct, + bool $isSingleton + ): string { + $newInstance->accept($this); + + return $this->script->getScript($postConstruct, $isSingleton); + } + + /** @inheritDoc */ + public function visitProvider( + Dependency $dependency, + string $context, + bool $isSingleton + ): string { + $this->script->pushProviderContext($context, $isSingleton); + $script = $dependency->accept($this); + assert(is_string($script)); + + return str_replace('return $instance', 'return $instance->get()', $script); + } + + /** @inheritDoc */ + public function visitInstance($value): string + { + if ($value === null || is_scalar($value) || is_array($value)) { + return sprintf('return %s;', var_export($value, true)); + } + + assert(is_object($value), 'Invalid instance type:' . gettype($value)); + + return sprintf('return unserialize(\'%s\');', serialize($value)); + } + + /** @inheritDoc */ + public function visitAspectBind(Bind $aopBind): void + { + $this->script->pushAspectBind($aopBind); + } + + /** @inheritDoc */ + public function visitNewInstance( + string $class, + SetterMethods $setterMethods, + ?Arguments $arguments, + ?AspectBind $bind + ): void { + $setterMethods->accept($this); + if ($arguments) { + $arguments->accept($this); + } + + if ($bind) { + $bind->accept($this); + } + + $this->script->pushClass($class); + } + + /** @inheritDoc */ + public function visitSetterMethods( + array $setterMethods + ) { + foreach ($setterMethods as $setterMethod) { + $setterMethod->accept($this); + } + } + + /** @inheritDoc */ + public function visitSetterMethod(string $method, Arguments $arguments): void + { + $arguments->accept($this); + $this->script->pushMethod($method); + } + + /** @inheritDoc */ + public function visitArguments(array $arguments): void + { + foreach ($arguments as $argument) { + $argument->accept($this); + } + } + + /** @inheritDoc */ + public function visitArgument( + string $index, + bool $isDefaultAvailable, + $defaultValue, + ReflectionParameter $parameter + ): void { + $this->script->addArg($index, $isDefaultAvailable, $defaultValue, $parameter); + } +} diff --git a/src/Compiler.php b/src/Compiler.php new file mode 100644 index 0000000..47e8f2d --- /dev/null +++ b/src/Compiler.php @@ -0,0 +1,59 @@ +install(new DiCompileModule(true)); + $container = (new ContainerFactory())($module, $scriptDir); + // Compile dependencies + $compileVisitor = new CompileVisitor($container); + $container->map(static function (DependencyInterface $dependency, string $key) use ($scripts, $compileVisitor): DependencyInterface { + assert($dependency instanceof AcceptInterface); + $script = $dependency->accept($compileVisitor); + assert(is_string($script)); + $scripts->add($key, $script); + + return $dependency; + }); + $scripts->save($scriptDir); + // Unlock + flock($fp, LOCK_UN); + fclose($fp); + + return $scripts; + } +} diff --git a/src/DependencyCode.php b/src/DependencyCode.php deleted file mode 100644 index 23c2a92..0000000 --- a/src/DependencyCode.php +++ /dev/null @@ -1,195 +0,0 @@ -factory = new BuilderFactory(); - $this->normalizer = new Normalizer(); - $this->factoryCompiler = new FactoryCode($container, new Normalizer(), $this, $injector); - $this->privateProperty = new PrivateProperty(); - $this->aopCode = new AopCode($this->privateProperty); - } - - /** - * Return compiled dependency code - */ - public function getCode(DependencyInterface $dependency): Code - { - if ($dependency instanceof Dependency) { - return $this->getDependencyCode($dependency); - } - - if ($dependency instanceof Instance) { - return $this->getInstanceCode($dependency); - } - - if ($dependency instanceof DependencyProvider) { - return $this->getProviderCode($dependency); - } - - throw new DomainException(get_class($dependency)); - } - - /** - * {@inheritdoc} - */ - public function setContext($context) - { - $this->context = $context; - } - - public function setQaulifier(IpQualifier $qualifer): void - { - $this->qualifier = $qualifer; - } - - public function getIsSingletonCode(bool $isSingleton): Expr\Assign - { - $bool = new Expr\ConstFetch(new Node\Name([$isSingleton ? 'true' : 'false'])); - - return new Expr\Assign(new Expr\Variable('isSingleton'), $bool); - } - - /** - * Compile DependencyInstance - */ - private function getInstanceCode(Instance $instance): Code - { - $node = ($this->normalizer)($instance->value); - - return new Code(new Node\Stmt\Return_($node), false); - } - - /** - * Compile generic object dependency - */ - private function getDependencyCode(Dependency $dependency): Code - { - $prop = $this->privateProperty; - $node = $this->getFactoryNode($dependency); - ($this->aopCode)($dependency, $node); - /** @var bool $isSingleton */ - $isSingleton = $prop($dependency, 'isSingleton'); - $node[] = $this->getIsSingletonCode($isSingleton); - $node[] = new Node\Stmt\Return_(new Node\Expr\Variable('instance')); - $namespace = $this->factory->namespace('Ray\Di\Compiler')->addStmts($node)->getNode(); - $qualifer = $this->qualifier; - $this->qualifier = null; - - return new Code($namespace, $isSingleton, $qualifer); - } - - /** - * Compile dependency provider - */ - private function getProviderCode(DependencyProvider $provider): Code - { - $prop = $this->privateProperty; - /** @var DependencyInterface $dependency */ - $dependency = $prop($provider, 'dependency'); - $node = $this->getFactoryNode($dependency); - $provider->setContext($this); - /** @var NewInstance $class */ - $class = $prop($dependency, 'newInstance'); - $classString = (string) $class; - if (is_a($classString, SetContextInterface::class, true)) { - $node[] = $this->getSetContextCode($this->context); // $instance->setContext($this->context); - } - - /** @var bool $isSingleton */ - $isSingleton = $prop($provider, 'isSingleton'); - $node[] = $this->getIsSingletonCode($isSingleton); - $node[] = new Stmt\Return_(new MethodCall(new Expr\Variable('instance'), 'get')); - $node = $this->factory->namespace('Ray\Di\Compiler')->addStmts($node)->getNode(); - $qualifer = $this->qualifier; - $this->qualifier = null; - - return new Code($node, $isSingleton, $qualifer); - } - - private function getSetContextCode(string $context): MethodCall - { - $arg = new Node\Arg(new Node\Scalar\String_($context)); - - return new MethodCall(new Expr\Variable('instance'), 'setContext', [$arg]); - } - - /** - * Return generic factory code - * - * This code is used by Dependency and DependencyProvider - * - * @return array - */ - private function getFactoryNode(DependencyInterface $dependency): array - { - $prop = $this->privateProperty; - /** @var NewInstance $newInstance */ - $newInstance = $prop($dependency, 'newInstance'); - // class name - /** @var class-string $class */ - $class = $prop($newInstance, 'class'); - /** @var SetterMethods $setterMethodsObject */ - $setterMethodsObject = $prop($newInstance, 'setterMethods'); - /** @var array $setterMethods */ - $setterMethods = (array) $prop($setterMethodsObject, 'setterMethods'); - /** @var Arguments $argumentsObject */ - $argumentsObject = $prop($newInstance, 'arguments'); - /** @var array $arguments */ - $arguments = (array) $prop($argumentsObject, 'arguments'); - /** @var ?string $postConstruct */ - $postConstruct = $prop($dependency, 'postConstruct'); - - return $this->factoryCompiler->getFactoryCode($class, $arguments, $setterMethods, (string) $postConstruct); - } -} diff --git a/src/DependencySaver.php b/src/DependencySaver.php deleted file mode 100644 index b2e1c6b..0000000 --- a/src/DependencySaver.php +++ /dev/null @@ -1,61 +0,0 @@ -scriptDir = $scriptDir; - $this->filePutContents = new FilePutContents(); - } - - public function __invoke(string $dependencyIndex, Code $code): void - { - $pearStyleName = str_replace('\\', '_', $dependencyIndex); - $instanceScript = sprintf(ScriptInjector::INSTANCE, $this->scriptDir, $pearStyleName); - ($this->filePutContents)($instanceScript, (string) $code . PHP_EOL); - if ($code->qualifiers) { - $this->saveQualifier($code->qualifiers); - } - } - - private function saveQualifier(IpQualifier $qualifer): void - { - $qualifier = $this->scriptDir . '/qualifer'; - ! file_exists($qualifier) && ! @mkdir($qualifier) && ! is_dir($qualifier); - $class = $qualifer->param->getDeclaringClass(); - if (! $class instanceof ReflectionClass) { - throw new LogicException(); // @codeCoverageIgnore - } - - $fileName = sprintf( - ScriptInjector::QUALIFIER, - $this->scriptDir, - str_replace('\\', '_', $class->name), - $qualifer->param->getDeclaringFunction()->name, - $qualifer->param->name - ); - ($this->filePutContents)($fileName, serialize($qualifer->qualifier)); - } -} diff --git a/src/DiCompiler.php b/src/DiCompiler.php deleted file mode 100644 index 9174589..0000000 --- a/src/DiCompiler.php +++ /dev/null @@ -1,124 +0,0 @@ -scriptDir = $scriptDir ?: sys_get_temp_dir(); - $this->container = $module->getContainer(); - $this->dependencyCompiler = new DependencyCode($this->container); - $this->module = $module; - $this->dependencySaver = new DependencySaver($scriptDir); - $this->filePutContents = new FilePutContents(); - (new CompileNullObject())($this->container, $this->scriptDir); - - // Weave AssistedInterceptor and bind InjectorInterface for self - $module->getContainer()->weaveAspects(new Compiler($scriptDir)); - (new Bind($this->container, InjectorInterface::class))->toInstance($this); - (new Bind($this->container, ''))->annotatedWith(ScriptDir::class)->toInstance($scriptDir); - } - - /** - * {@inheritdoc} - */ - public function getInstance($interface, $name = Name::ANY) - { - $this->compile(); - - return (new ScriptInjector($this->scriptDir))->getInstance($interface, $name); - } - - /** - * Compile for ScriptInjector - */ - public function compile(): void - { - $this->compileContainer(); - $this->savePointcuts($this->container); - ($this->filePutContents)($this->scriptDir . ScriptInjector::MODULE, serialize($this->module)); - } - - /** - * Compile for CompileInjector - */ - public function compileContainer(): void - { - $scriptDir = $this->container->getInstance('', ScriptDir::class); - $container = $this->container->getContainer(); - assert(is_string($scriptDir)); - $fp = fopen(sprintf('%s/_compile.log', $this->scriptDir), 'a'); - assert(is_resource($fp)); - ksort($container); - foreach ($container as $dependencyIndex => $dependency) { - fwrite($fp, sprintf("Compiled: %s\n", $dependencyIndex)); - try { - $code = $this->dependencyCompiler->getCode($dependency); - } catch (Unbound $e) { - fwrite($fp, sprintf("\nError: %s\nUnbound: %s\n", $dependencyIndex, $e->getMessage())); - - throw $e; - } - - ($this->dependencySaver)($dependencyIndex, $code); - } - - fclose($fp); - } - - public function dumpGraph(): void - { - $dumper = new GraphDumper($this->container, $this->scriptDir); - $dumper(); - } - - public function savePointcuts(Container $container): void - { - $ref = (new ReflectionProperty($container, 'pointcuts')); - $ref->setAccessible(true); - $pointcuts = $ref->getValue($container); - ($this->filePutContents)($this->scriptDir . ScriptInjector::AOP, serialize($pointcuts)); - } -} diff --git a/src/Exception/CompileLockFailed.php b/src/Exception/CompileLockFailed.php new file mode 100644 index 0000000..0f0ece0 --- /dev/null +++ b/src/Exception/CompileLockFailed.php @@ -0,0 +1,11 @@ +container = $container; - $this->normalizer = $normalizer; - $this->nodeFactory = new NodeFactory($normalizer, $this, $injector); - $this->functionCompiler = new FunctionCode($container, new PrivateProperty(), $compiler); - } - - /** - * @param array $arguments - * @param array $setterMethods - * - * @return array - */ - public function getFactoryCode(string $class, array $arguments, array $setterMethods, string $postConstruct): array - { - $node = []; - $instance = new Expr\Variable('instance'); - // constructor injection - $constructorInjection = $this->getConstructorInjection($class, $arguments); - $node[] = new Expr\Assign($instance, $constructorInjection); - $setters = $this->nodeFactory->getSetterInjection($instance, $setterMethods); - foreach ($setters as $setter) { - $node[] = $setter; - } - - if ($postConstruct) { - $node[] = $this->nodeFactory->getPostConstruct($instance, $postConstruct); - } - - return $node; - } - - /** - * Return method argument code - * - * @return Expr|Expr\FuncCall - */ - public function getArgStmt(Argument $argument): NodeAbstract - { - $dependencyIndex = (string) $argument; - if ($dependencyIndex === 'Ray\Di\InjectionPointInterface-' . Name::ANY) { - return $this->getInjectionPoint(); - } - - $hasDependency = isset($this->container->getContainer()[$dependencyIndex]); - if (! $hasDependency) { - return $this->nodeFactory->getNode($argument); - } - - $dependency = $this->container->getContainer()[$dependencyIndex]; - if ($dependency instanceof Instance) { - return ($this->normalizer)($dependency->value); - } - - return ($this->functionCompiler)($argument, $dependency); - } - - /** - * @param array $arguments - */ - private function getConstructorInjection(string $class, array $arguments = []): Expr\New_ - { - $args = []; - foreach ($arguments as $argument) { - // $argument = $argument->isDefaultAvailable() ? $argument->getDefaultValue() : $argument; - $args[] = $this->getArgStmt($argument); - } - - /** @var array $args */ - return new Expr\New_(new Node\Name\FullyQualified($class), $args); - } - - /** - * Return "$injectionPoint()" - */ - private function getInjectionPoint(): Expr - { - return new Expr\FuncCall(new Expr\Variable('injectionPoint')); - } -} diff --git a/src/FunctionCode.php b/src/FunctionCode.php deleted file mode 100644 index 5291376..0000000 --- a/src/FunctionCode.php +++ /dev/null @@ -1,121 +0,0 @@ -container = $container; - $this->privateProperty = $privateProperty; - $this->reader = ServiceLocator::getReader(); - $this->compiler = $compiler; - } - - /** - * Return arguments code for "$singleton" and "$prototype" - */ - public function __invoke(Argument $argument, DependencyInterface $dependency): Expr\FuncCall - { - $prop = $this->privateProperty; - $isSingleton = $prop($dependency, 'isSingleton'); - assert(is_bool($isSingleton)); - $func = $isSingleton ? 'singleton' : 'prototype'; - $args = $this->getInjectionFuncParams($argument); - - /** @var array $args */ - return new Expr\FuncCall(new Expr\Variable($func), $args); - } - - /** - * Return dependency index argument - * - * [class, method, param] is added if dependency is provider for DI context - * - * @return array - */ - private function getInjectionFuncParams(Argument $argument): array - { - $dependencyIndex = (string) $argument; - if ($this->container->getContainer()[$dependencyIndex] instanceof DependencyProvider) { - return $this->getInjectionProviderParams($argument); - } - - return [new Node\Arg(new Scalar\String_((string) $argument))]; - } - - /** - * Return code for provider - * - * "$provider" needs [class, method, parameter] for InjectionPoint (Contextual Dependency Injection) - * - * @return array - */ - private function getInjectionProviderParams(Argument $argument): array - { - $param = $argument->get(); - $class = $param->getDeclaringClass(); - if (! $class instanceof ReflectionClass) { - throw new LogicException(); // @codeCoverageIgnore - } - - $method = $param->getDeclaringFunction(); - assert($method instanceof ReflectionMethod); - $this->setQualifiers($method, $param); - - return [ - new Node\Arg(new Scalar\String_((string) $argument)), - new Expr\Array_([ - new Expr\ArrayItem(new Scalar\String_($class->name)), - new Expr\ArrayItem(new Scalar\String_($method->name)), - new Expr\ArrayItem(new Scalar\String_($param->name)), - ]), - ]; - } - - private function setQualifiers(ReflectionMethod $method, ReflectionParameter $param): void - { - $annotations = $this->reader->getMethodAnnotations($method); - foreach ($annotations as $annotation) { - $qualifier = $this->reader->getClassAnnotation( - new ReflectionClass($annotation), - Qualifier::class - ); - if ($qualifier instanceof Qualifier) { - $this->compiler->setQaulifier(new IpQualifier($param, $annotation)); - } - } - } -} diff --git a/src/InjectionPoint.php b/src/InjectionPoint.php index 2ec3090..9c11496 100644 --- a/src/InjectionPoint.php +++ b/src/InjectionPoint.php @@ -6,31 +6,22 @@ use Ray\Aop\ReflectionClass; use Ray\Aop\ReflectionMethod; +use Ray\Di\Di\Qualifier; use Ray\Di\InjectionPointInterface; +use Ray\ServiceLocator\ServiceLocator; use ReflectionParameter; -use RuntimeException; use function assert; use function class_exists; -use function file_exists; -use function file_get_contents; -use function is_bool; -use function sprintf; -use function str_replace; -use function unserialize; final class InjectionPoint implements InjectionPointInterface { /** @var ReflectionParameter */ private $parameter; - /** @var string */ - private $scriptDir; - - public function __construct(ReflectionParameter $parameter, string $scriptDir) + public function __construct(ReflectionParameter $parameter) { $this->parameter = $parameter; - $this->scriptDir = $scriptDir; } /** @@ -86,30 +77,18 @@ public function getQualifiers(): array public function getQualifier() { $class = $this->parameter->getDeclaringClass(); + $methodName = $this->parameter->getDeclaringFunction()->getName(); assert($class instanceof \ReflectionClass); - - $qualifierFile = sprintf( - ScriptInjector::QUALIFIER, - $this->scriptDir, - str_replace('\\', '_', $class->name), - $this->parameter->getDeclaringFunction()->name, - $this->parameter->name - ); - // @codeCoverageIgnoreStart - if (! file_exists($qualifierFile)) { - return null; - } - - // @codeCoverageIgnoreEnd - - $qualifierString = file_get_contents($qualifierFile); - if (is_bool($qualifierString)) { - throw new RuntimeException(); // @codeCoverageIgnore + $method = new \ReflectionMethod($class->getName(), $methodName); + $reader = ServiceLocator::getReader(); + $annotations = $reader->getMethodAnnotations($method); + foreach ($annotations as $annotation) { + $qualifier = $reader->getClassAnnotation(new \ReflectionClass($annotation), Qualifier::class); + if ($qualifier instanceof Qualifier) { + return $annotation; + } } - /** @var ?object $qualifier */ - $qualifier = unserialize($qualifierString, ['allowed_classes' => true]); - - return $qualifier; + return null; } } diff --git a/src/InstallBuiltinModule.php b/src/InstallBuiltinModule.php deleted file mode 100644 index 05d0ed6..0000000 --- a/src/InstallBuiltinModule.php +++ /dev/null @@ -1,28 +0,0 @@ -install(new AssistedModule()); - $module->install(new ProviderSetModule()); - $module->install(new PramReaderModule()); - $hasMultiBindings = count($module->getContainer()->multiBindings); - if ($hasMultiBindings) { - $module->install(new MapModule()); - } - - return $module; - } -} diff --git a/src/InstanceScript.php b/src/InstanceScript.php new file mode 100644 index 0000000..0451cf9 --- /dev/null +++ b/src/InstanceScript.php @@ -0,0 +1,179 @@ + */ + private $args = []; + + /** @var array */ + private $formerLines = []; // Constructor injection and AOP + + /** @var array */ + private $laterLines = []; // Setter injection and postConstruct + + /** @var string */ + private $context = ''; + + /** @var bool */ + private $implementsSetContext = false; + + /** @var bool|null */ + private $isSingleton = null; + + /** @var array */ + private $container; + + public function __construct(Container $container) + { + $container->sort(); + $this->container = $container->getContainer(); + } + + /** + * @param mixed $defaultValue + */ + public function addArg(string $index, bool $isDefaultAvailable, $defaultValue, ReflectionParameter $parameter): void + { + if (! isset($this->container[$index])) { + if ($isDefaultAvailable) { + $this->addInstanceArg($defaultValue); + + return; + } + + if ($index === 'Ray\Di\InjectorInterface-') { + $this->args[] = '$injector()'; + + return; + } + + if ($index === 'Ray\Di\InjectionPointInterface-') { + $this->args[] = '$injectionPoint()'; + + return; + } + + throw new Unbound($index); + } + + $dependency = $this->container[$index]; + if ($dependency instanceof Dependency || $dependency instanceof DependencyProvider) { + $this->addDependencyArg($dependency->isSingleton(), $index, $parameter); + + return; + } + + assert($dependency instanceof Instance, 'Invalid instance value'); + $this->addInstanceArg($dependency->value); + } + + private function addDependencyArg(bool $isSingleton, string $index, ReflectionParameter $parameter): void + { + /** @psalm-suppress PossiblyNullReference / The $parameter here can never be null */ + $ip = sprintf("['%s', '%s', '%s']", $parameter->getDeclaringClass()->getName(), $parameter->getDeclaringFunction()->getName(), $parameter->name); //@phpstan-ignore-line + $func = $isSingleton ? '$singleton' : '$prototype'; + $arg = sprintf("%s('%s', %s)", $func, $index, $ip); + $this->args[] = $arg; + } + + /** + * @param mixed $default + */ + public function addInstanceArg($default): void + { + if (is_object($default)) { + $this->args[] = sprintf('unserialize(\'%s\')', serialize($default)); + + return; + } + + $this->args[] = var_export($default, true); + } + + public function pushMethod(string $method): void + { + $this->laterLines[] = sprintf('$instance->%s(%s);', $method, implode(', ', $this->args)); + $this->args = []; + } + + public function pushClass(string $class): void + { + $this->implementsSetContext = is_a($class, SetContextInterface::class, true); + + array_unshift($this->formerLines, sprintf('$instance = new \%s(%s);', $class, implode(', ', $this->args))); + $this->args = []; + } + + public function pushProviderContext(string $context, bool $isSingleton): void + { + $this->context = $context; + $this->isSingleton = $isSingleton; + } + + public function pushAspectBind(AopBind $aopBind): void + { + $aopBindings = unserialize((string) ($aopBind)); + assert(is_iterable($aopBindings)); + foreach ($aopBindings as &$bindings) { + foreach ($bindings as &$binding) { + $binding = sprintf('$singleton(\'%s-\')', $binding); + } + } + + $interceptors = []; + foreach ($aopBindings as $method => $bindings) { + $interceptors[] = sprintf('\'%s\' => [%s]', $method, implode(', ', $bindings)); + } + + $this->formerLines[] = sprintf('$instance->bindings = [%s];', implode(', ', $interceptors)); + } + + public function getScript(?string $postConstruct, bool $isSingleton): string + { + if ($postConstruct) { + $this->laterLines[] = sprintf('$instance->%s();', $postConstruct); + } + + if ($this->implementsSetContext) { + $this->laterLines[] = sprintf('$instance->setContext(%s);', var_export($this->context, true)); + } + + $isSingleton = $this->isSingleton ?? $isSingleton; + $this->laterLines[] = sprintf('$isSingleton = %s;', $isSingleton ? 'true' : 'false'); + $this->laterLines[] = 'return $instance;'; + + $script = implode(PHP_EOL, $this->formerLines) . PHP_EOL . implode(PHP_EOL, $this->laterLines); + $this->formerLines = []; + $this->laterLines = []; + $this->isSingleton = null; + + return $script; + } +} diff --git a/src/MapModule.php b/src/MapModule.php deleted file mode 100644 index 744cb54..0000000 --- a/src/MapModule.php +++ /dev/null @@ -1,20 +0,0 @@ -bind(Map::class)->toProvider(MapProvider::class); - } -} diff --git a/src/NodeFactory.php b/src/NodeFactory.php deleted file mode 100644 index 9d7cd2c..0000000 --- a/src/NodeFactory.php +++ /dev/null @@ -1,170 +0,0 @@ -injector = $injector; - $this->normalizer = $normalizer; - $this->factoryCompiler = $factoryCompiler; - $this->privateProperty = new PrivateProperty(); - } - - /** - * Return on-demand dependency pull code for not compiled - * - * @return Expr|Expr\FuncCall - */ - public function getNode(Argument $argument): Expr - { - $dependencyIndex = (string) $argument; - if (! $this->injector instanceof ScriptInjector) { - return $this->getDefault($argument); - } - - try { - $isSingleton = $this->injector->isSingleton($dependencyIndex); - } catch (NotCompiled $e) { - return $this->getDefault($argument); - } - - $func = $isSingleton ? 'singleton' : 'prototype'; - $args = $this->getInjectionProviderParams($argument); - - /** @var array $args */ - return new Expr\FuncCall(new Expr\Variable($func), $args); - } - - /** - * @param SetterMethod[] $setterMethods - * - * @return Expr\MethodCall[] - */ - public function getSetterInjection(Expr\Variable $instance, array $setterMethods): array - { - $setters = []; - foreach ($setterMethods as $setterMethod) { - $isOptional = ($this->privateProperty)($setterMethod, 'isOptional'); - assert(is_bool($isOptional)); - $method = ($this->privateProperty)($setterMethod, 'method'); - assert(is_string($method)); - $argumentsObject = ($this->privateProperty)($setterMethod, 'arguments'); - assert($argumentsObject instanceof Arguments); - /** @var array $arguments */ - $arguments = ($this->privateProperty)($argumentsObject, 'arguments'); - /** @var array $args */ - $args = $this->getSetterParams($arguments, $isOptional); - if (! $args) { - continue; - } - - $setters[] = new Expr\MethodCall($instance, $method, $args); - } - - return $setters; - } - - public function getPostConstruct(Expr\Variable $instance, string $postConstruct): Expr\MethodCall - { - return new Expr\MethodCall($instance, $postConstruct); - } - - /** - * Return default argument value - */ - private function getDefault(Argument $argument): Expr - { - if ($argument->isDefaultAvailable()) { - $default = $argument->getDefaultValue(); - - return ($this->normalizer)($default); - } - - throw new Unbound($argument->getMeta()); - } - - /** - * Return code for provider - * - * "$provider" needs [class, method, parameter] for InjectionPoint (Contextual Dependency Injection) - * - * @return array - */ - private function getInjectionProviderParams(Argument $argument) - { - $param = $argument->get(); - $class = $param->getDeclaringClass(); - if (! $class instanceof ReflectionClass) { - throw new LogicException(); // @codeCoverageIgnore - } - - return [ - new Node\Arg(new Scalar\String_((string) $argument)), - new Expr\Array_([ - new Node\Expr\ArrayItem(new Scalar\String_($class->name)), - new Node\Expr\ArrayItem(new Scalar\String_($param->getDeclaringFunction()->name)), - new Node\Expr\ArrayItem(new Scalar\String_($param->name)), - ]), - ]; - } - - /** - * Return setter method parameters - * - * Return false when no dependency given and @ Inject(optional=true) annotated to setter method. - * - * @param Argument[] $arguments - * - * @return false|Node\Expr[] - */ - private function getSetterParams(array $arguments, bool $isOptional) - { - $args = []; - foreach ($arguments as $argument) { - try { - $args[] = $this->factoryCompiler->getArgStmt($argument); - } catch (Unbound $e) { - if ($isOptional) { - return false; - } - } - } - - return $args; - } -} diff --git a/src/Normalizer.php b/src/Normalizer.php deleted file mode 100644 index 9491c29..0000000 --- a/src/Normalizer.php +++ /dev/null @@ -1,139 +0,0 @@ -getValueNode($value); - } - - /** - * Return array or object node - * - * @param array|mixed|object $value - * - * @return Scalar\String_|Scalar\LNumber|Scalar\DNumber|Expr\Array_|Expr\FuncCall - */ - private function getValueNode($value): Expr - { - if (is_string($value)) { - return new Scalar\String_($value); - } - - if (is_int($value)) { - return new Scalar\LNumber($value); - } - - if (is_float($value)) { - return new Scalar\DNumber($value); - } - - return $this->getValueNodeNonAtomic($value); - } - - /** - * Return array or object node - * - * @param array|mixed|object $value - * - * @return Expr\Array_|Expr\FuncCall - */ - private function getValueNodeNonAtomic($value): Expr - { - if (is_array($value)) { - return $this->arrayValue($value); - } - - if (is_object($value)) { - return $this->normalizeObject($value); - } - - throw new InvalidInstance(); - } - - /** - * Return "unserialize($object)" node - * - * @param object $object - */ - private function normalizeObject($object): Expr\FuncCall - { - if ($object instanceof InjectorInterface) { - return new Expr\FuncCall(new Expr\Variable('injector')); - } - - $serialize = new Scalar\String_(serialize($object)); - - return new Expr\FuncCall(new Node\Name('unserialize'), [new Arg($serialize)]); - } - - /** - * Return array value node - * - * @param array $value - */ - private function arrayValue($value): Expr\Array_ - { - $items = []; - $lastKey = -1; - foreach ($value as $itemKey => $itemValue) { - // for consecutive, numeric keys don't generate keys - if ($lastKey !== null && ++$lastKey === $itemKey) { - $items[] = new Expr\ArrayItem( - $this->__invoke($itemValue) - ); - continue; - } - - $lastKey = null; - $items[] = new Expr\ArrayItem( - $this->__invoke($itemValue), - $this->__invoke($itemKey) - ); - } - - return new Expr\Array_($items); - } -} diff --git a/src/OnDemandCompiler.php b/src/OnDemandCompiler.php deleted file mode 100644 index 392afa5..0000000 --- a/src/OnDemandCompiler.php +++ /dev/null @@ -1,97 +0,0 @@ -scriptDir = $scriptDir; - $this->injector = $injector; - $this->module = $module; - $this->compiler = new CompileNullObject(); - } - - /** - * Compile dependency on demand - */ - public function __invoke(string $dependencyIndex): void - { - [$class] = explode('-', $dependencyIndex); - $containerObject = $this->module->getContainer(); - try { - new Bind($containerObject, $class); - } catch (NotFound $e) { - throw new Unbound($dependencyIndex, 0, $e); - } - - $containerArray = $containerObject->getContainer(); - if (! isset($containerArray[$dependencyIndex])) { - throw new Unbound($dependencyIndex, 0); - } - - ($this->compiler)($containerObject, $this->scriptDir); - $dependency = $containerArray[$dependencyIndex]; - $pointCuts = $this->loadPointcuts(); - $isWeaverable = $dependency instanceof Dependency && is_array($pointCuts); - if ($isWeaverable) { - $dependency->weaveAspects(new Compiler($this->scriptDir), $pointCuts); - } - - $code = (new DependencyCode($containerObject, $this->injector))->getCode($dependency); - (new DependencySaver($this->scriptDir))($dependencyIndex, $code); - } - - /** - * @return array|false - */ - private function loadPointcuts() - { - $pointcutsPath = $this->scriptDir . ScriptInjector::AOP; - if (! file_exists($pointcutsPath)) { - return false; // @codeCoverageIgnore - } - - $serialized = file_get_contents($pointcutsPath); - assert(! is_bool($serialized)); - $er = error_reporting(error_reporting() ^ E_NOTICE); - /** @var array $pointcuts */ - $pointcuts = unserialize($serialized, ['allowed_classes' => true]); - error_reporting($er); - - return $pointcuts; - } -} diff --git a/src/PramReaderModule.php b/src/PramReaderModule.php deleted file mode 100644 index 047bf0e..0000000 --- a/src/PramReaderModule.php +++ /dev/null @@ -1,20 +0,0 @@ -bind(ParamReaderInterface::class)->to(ParamReader::class); - } -} diff --git a/src/ScriptInjector.php b/src/ScriptInjector.php deleted file mode 100644 index 21c7a37..0000000 --- a/src/ScriptInjector.php +++ /dev/null @@ -1,330 +0,0 @@ - - */ - private $singletons = []; - - /** @var array */ - private $functions; - - /** @var callable */ - private $lazyModule; - - /** @var AbstractModule|null */ - private $module; - - /** @var ?array */ - private $container; - - /** @var bool */ - private $isModuleLocked = false; - - /** @var array */ - private static $scriptDirs = []; - - /** - * @param string $scriptDir generated instance script folder path - * @param callable $lazyModule callable variable which return AbstractModule instance - * - * @psalm-suppress UnresolvableInclude - */ - public function __construct($scriptDir, ?callable $lazyModule = null) - { - $this->scriptDir = $scriptDir; - $this->lazyModule = $lazyModule ?: static function (): NullModule { - return new NullModule(); - }; - $this->registerLoader(); - $prototype = - /** - * @param array{0: string, 1: string, 2: string} $injectionPoint - * - * @return mixed - */ - function (string $dependencyIndex, array $injectionPoint = ['', '', '']) { - $this->ip = $injectionPoint; // @phpstan-ignore-line - [$prototype, $singleton, $injectionPoint, $injector] = $this->functions; - - return require $this->getInstanceFile($dependencyIndex); - }; - $singleton = - /** - * @param array{0: string, 1: string, 2: string} $injectionPoint - * - * @return mixed - */ - function (string $dependencyIndex, $injectionPoint = ['', '', '']) { - if (isset($this->singletons[$dependencyIndex])) { - return $this->singletons[$dependencyIndex]; - } - - $this->ip = $injectionPoint; - [$prototype, $singleton, $injectionPoint, $injector] = $this->functions; - - $instance = require $this->getInstanceFile($dependencyIndex); - $this->singletons[$dependencyIndex] = $instance; - - return $instance; - }; - $injectionPoint = function () use ($scriptDir): InjectionPoint { - return new InjectionPoint( - new ReflectionParameter([$this->ip[0], $this->ip[1]], $this->ip[2]), - $scriptDir - ); - }; - $injector = function (): self { - return $this; - }; - $this->functions = [$prototype, $singleton, $injectionPoint, $injector]; - } - - /** - * @return list - */ - public function __sleep() - { - $this->saveModule(); - - return ['scriptDir', 'singletons']; - } - - public function __wakeup() - { - $this->__construct( - $this->scriptDir, - function () { - return $this->getModule(); - } - ); - } - - /** - * {@inheritdoc} - * - * @SuppressWarnings(PHPMD.UnusedLocalVariable) - */ - public function getInstance($interface, $name = Name::ANY) - { - $dependencyIndex = $interface . '-' . $name; - if (isset($this->singletons[$dependencyIndex])) { - return $this->singletons[$dependencyIndex]; - } - - [$prototype, $singleton, $injectionPoint, $injector] = $this->functions; - /** @psalm-suppress UnresolvableInclude */ - $instance = require $this->getInstanceFile($dependencyIndex); - /** @psalm-suppress UndefinedVariable */ - $isSingleton = isset($isSingleton) && $isSingleton; - if ($isSingleton) { - $this->singletons[$dependencyIndex] = $instance; - } - - /** - * @psalm-var T $instance - * @phpstan-var mixed $instance - */ - return $instance; - } - - public function clear(): void - { - $unlink = static function (string $path) use (&$unlink): void { - foreach ((array) glob(rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . '*') as $f) { - $file = (string) $f; - is_dir($file) ? $unlink($file) : unlink($file); - @rmdir($file); - } - }; - $unlink($this->scriptDir); - } - - public function isSingleton(string $dependencyIndex): bool - { - if (! $this->container) { - $module = $this->getModule(); - /** @var AbstractModule $module */ - $this->container = $module->getContainer()->getContainer(); - } - - if (! isset($this->container[$dependencyIndex])) { - throw new Unbound($dependencyIndex); - } - - $dependency = $this->container[$dependencyIndex]; - - return $dependency instanceof Dependency ? (bool) (new PrivateProperty())($dependency, 'isSingleton') : false; - } - - private function getModule(): AbstractModule - { - $modulePath = $this->scriptDir . self::MODULE; - if (! file_exists($modulePath)) { - // @codeCoverageIgnoreStart - error_log(sprintf('ModuleFileNotFound: %s', $modulePath)); - error_log('Please report the issue at https://github.com/ray-di/Ray.Compiler/issues'); - - return new NullModule(); - // @codeCoverageIgnoreEnd - } - - $serialized = file_get_contents($modulePath); - assert(! is_bool($serialized)); - $er = error_reporting(error_reporting() ^ E_NOTICE); - $module = unserialize($serialized, ['allowed_classes' => true]); - error_reporting($er); - assert($module instanceof AbstractModule); - - return $module; - } - - /** - * Return compiled script file name - */ - private function getInstanceFile(string $dependencyIndex): string - { - $file = sprintf(self::INSTANCE, $this->scriptDir, str_replace('\\', '_', $dependencyIndex)); - if (file_exists($file)) { - return $file; - } - - $this->compileOnDemand($dependencyIndex); - assert(file_exists($file)); - - return $file; - } - - private function saveModule(): void - { - if ($this->isModuleLocked || file_exists($this->scriptDir . self::MODULE)) { - return; - } - - $this->isModuleLocked = true; - $module = $this->module instanceof AbstractModule ? $this->module : $this->evaluateModule($this->lazyModule); - (new FilePutContents())($this->scriptDir . self::MODULE, serialize($module)); - } - - private function registerLoader(): void - { - if (in_array($this->scriptDir, self::$scriptDirs, true)) { - return; - } - - if (self::$scriptDirs === []) { - spl_autoload_register( - static function (string $class): void { - foreach (self::$scriptDirs as $scriptDir) { - $file = sprintf('%s/%s.php', $scriptDir, str_replace('\\', '_', $class)); - if (file_exists($file)) { - require $file; // @codeCoverageIgnore - } - } - } - ); - } - - self::$scriptDirs[] = $this->scriptDir; - } - - private function compileOnDemand(string $dependencyIndex): void - { - if (! $this->module instanceof AbstractModule) { - $this->module = $this->evaluateModule($this->lazyModule); - } - - $isFirstCompile = ! file_exists($this->scriptDir . self::AOP); - if ($isFirstCompile) { - $this->firstCompile(); - } - - (new Bind($this->module->getContainer(), ''))->annotatedWith(ScriptDir::class)->toInstance($this->scriptDir); // @phpstan-ignore-line - (new OnDemandCompiler($this, $this->scriptDir, $this->module))($dependencyIndex); // @phpstan-ignore-line - } - - private function firstCompile(): void - { - assert($this->module instanceof AbstractModule); - $compiler = new DiCompiler($this->module, $this->scriptDir); - $compiler->savePointcuts($this->module->getContainer()); - $this->saveModule(); - $compiler->compile(); - } - - private function evaluateModule(callable $lazyModule): AbstractModule - { - $module = ($lazyModule)(); - assert($module instanceof AbstractModule); - $module->install(new AssistedModule()); - $module->install(new ProviderSetModule()); - $module->install(new PramReaderModule()); - $hasMultiBindings = count($module->getContainer()->multiBindings); - if ($hasMultiBindings) { - $module->install(new MapModule()); - } - - return $module; - } -} diff --git a/src/Scripts.php b/src/Scripts.php new file mode 100644 index 0000000..2b6e016 --- /dev/null +++ b/src/Scripts.php @@ -0,0 +1,33 @@ + */ + private $scripts = []; + + public function add(string $index, string $script): void + { + $this->scripts[$index] = $script; + } + + public function save(string $scriptDir): void + { + $template = <<<'EOL' +scripts as $index => $script) { + $file = sprintf('%s/%s.php', $scriptDir, str_replace('\\', '_', $index)); + $script = sprintf($template, $script); + $filePutContents($file, $script); + } + } +} diff --git a/tests/AssistedTest.php b/tests/AssistedTest.php index fb5cc29..be56bce 100644 --- a/tests/AssistedTest.php +++ b/tests/AssistedTest.php @@ -17,9 +17,6 @@ use Ray\Di\Injector; use Ray\Di\InjectorInterface; -/** - * @requires PHP 8.0 - */ class AssistedTest extends TestCase { /** @var InjectorInterface */ diff --git a/tests/CachedFactoryTest.php b/tests/CachedFactoryTest.php index fdc1bc3..cda2430 100644 --- a/tests/CachedFactoryTest.php +++ b/tests/CachedFactoryTest.php @@ -7,7 +7,6 @@ use PHPUnit\Framework\TestCase; use Ray\Di\AbstractModule; use Ray\Di\InjectorInterface; -use Ray\Di\NullCache; use function spl_object_hash; @@ -47,7 +46,7 @@ static function (): AbstractModule { return CachedInjectorFactory::getInstance( 'prod', - __DIR__ . '/tmp/prod', + __DIR__ . '/tmp/', static function (): AbstractModule { $module = new FakeToBindSingletonModule(); $module->install(new DiCompileModule(true)); diff --git a/tests/CompileInjectorTest.php b/tests/CompileInjectorTest.php index 813bf68..27f7947 100644 --- a/tests/CompileInjectorTest.php +++ b/tests/CompileInjectorTest.php @@ -5,13 +5,10 @@ namespace Ray\Compiler; use PHPUnit\Framework\TestCase; -use Ray\Di\Exception\Unbound; use function assert; -use function file_get_contents; use function is_object; use function serialize; -use function spl_object_hash; use function unserialize; class CompileInjectorTest extends TestCase @@ -31,14 +28,11 @@ protected function setUp(): void public function testCompile(): void { - $this->injector->compile(); // built in script $this->assertFileExists(__DIR__ . '/tmp/-Ray_Compiler_Annotation_Compile.php'); - $this->assertFileExists(__DIR__ . '/tmp/-Ray_Di_Annotation_ScriptDir.php'); $this->assertFileExists(__DIR__ . '/tmp/Ray_Aop_MethodInvocation-.php'); $this->assertFileExists(__DIR__ . '/tmp/Koriym_ParamReader_ParamReaderInterface-.php'); $this->assertFileExists(__DIR__ . '/tmp/Ray_Di_AssistedInterceptor-.php'); - $this->assertFileExists(__DIR__ . '/tmp/Ray_Di_InjectorInterface-.php'); $this->assertFileExists(__DIR__ . '/tmp/Ray_Di_MethodInvocationProvider-.php'); $this->assertFileExists(__DIR__ . '/tmp/Ray_Di_ProviderInterface-.php'); // application binding @@ -66,7 +60,7 @@ public function testSingleton(): void $instance2 = $this->injector->getInstance(FakeRobotInterface::class); assert(is_object($instance1)); assert(is_object($instance2)); - $this->assertSame(spl_object_hash($instance1), spl_object_hash($instance2)); + $this->assertSame($instance1, $instance2); } public function testSerialize(): void @@ -77,33 +71,4 @@ public function testSerialize(): void $instance = $injector->getInstance(FakeCarInterface::class); $this->assertInstanceOf(FakeCarInterface::class, $instance); } - - public function testUnbound(): void - { - deleteFiles(__DIR__ . '/tmp'); - $this->expectException(Unbound::class); - $injector = new CompileInjector(__DIR__ . '/tmp', new FakeUnboundModule()); - $injector->getInstance(FakeCar2::class); - } - - /** - * @depends testUnbound - */ - public function testUnboundCompileLogFile(): void - { - $this->expectException(Unbound::class); - $this->injector->getInstance(FakeCar2::class); - } - - /** - * @depends testUnboundCompileLogFile - */ - public function testCompileFaillureLog(): void - { - $logFile = __DIR__ . '/tmp/_compile.log'; - $this->assertFileExists(__DIR__ . '/tmp/compiled'); - $this->assertFileExists($logFile); - $log = (string) file_get_contents($logFile); - $this->assertStringContainsString('Error', $log); - } } diff --git a/tests/CompilerTest.php b/tests/CompilerTest.php new file mode 100644 index 0000000..0297a5d --- /dev/null +++ b/tests/CompilerTest.php @@ -0,0 +1,242 @@ +compiler = new Compiler(); + $this->scriptDir = __DIR__ . '/tmp'; + $this->injector = new AirInjector($this->scriptDir); + deleteFiles($this->scriptDir); + } + + public function testCompile(): void + { + $module = new class () extends AbstractModule{ + protected function configure() + { + $this->bind(FakeFooInterface::class)->to(FakeFoo::class); + } + }; + + $scripts = $this->compiler->compile($module, $this->scriptDir); + $this->assertInstanceOf(Scripts::class, $scripts); + $instance = $this->injector->getInstance(FakeFooInterface::class); + $this->assertInstanceOf(FakeFoo::class, $instance); + } + + public function testCompileSingleton(): void + { + $module = new class () extends AbstractModule{ + protected function configure() + { + $this->bind(FakeFooInterface::class)->to(FakeFoo::class)->in(Scope::SINGLETON); + } + }; + + $this->compiler->compile($module, $this->scriptDir); + $instance1 = $this->injector->getInstance(FakeFooInterface::class); + $instance2 = $this->injector->getInstance(FakeFooInterface::class); + $this->assertSame(spl_object_hash($instance1), spl_object_hash($instance2)); + } + + public function testToInstance(): void + { + $module = new class () extends AbstractModule{ + protected function configure() + { + $this->bind('')->annotatedWith('foo')->toInstance('foo_instance'); + } + }; + + $this->compiler->compile($module, $this->scriptDir); + $instance = $this->injector->getInstance('', 'foo'); + $this->assertSame('foo_instance', $instance); + } + + public function testCompileProvider(): void + { + $module = new class () extends AbstractModule{ + protected function configure() + { + $this->bind(FakeBazInterface::class)->toProvider(FakeBazProvider::class); + } + }; + + $this->compiler->compile($module, $this->scriptDir); + $instance = $this->injector->getInstance(FakeBazInterface::class); + $this->assertInstanceOf(FakeBaz::class, $instance); + } + + public function testCompileComplex(): void + { + $module = new class () extends AbstractModule{ + protected function configure() + { + $this->bind(FakeCarInterface::class)->to(FakeCar::class); // dependent + $this->bind(FakeEngineInterface::class)->to(FakeEngine::class); // constructor + $this->bind(FakeHardtopInterface::class)->to(FakeHardtop::class); // optional setter + $this->bind(FakeTyreInterface::class)->to(FakeTyre::class); // setter + $this->bind(FakeMirrorInterface::class)->annotatedWith('right')->to(FakeMirrorRight::class)->in(Scope::SINGLETON); // named binding + $this->bind(FakeMirrorInterface::class)->annotatedWith('left')->to(FakeMirrorLeft::class)->in(Scope::SINGLETON); // named binding + $this->bind('')->annotatedWith('logo')->toInstance('momo'); + $this->bind(FakeHandleInterface::class)->toProvider(FakeHandleProvider::class); + } + }; + $this->compiler->compile($module, $this->scriptDir); + $instance = $this->injector->getInstance(FakeCarInterface::class); + $this->assertInstanceOf(FakeCar::class, $instance); + } + + public function testCompileAop(): void + { + $module = new class () extends AbstractModule{ + protected function configure() + { + $this->bind(FakeAopInterface::class)->to(FakeAop::class); + $this->bindInterceptor( + $this->matcher->any(), + $this->matcher->any(), + [FakeDoubleInterceptor::class] + ); + } + }; + $this->compiler->compile($module, $this->scriptDir); + $instance = $this->injector->getInstance(FakeAopInterface::class); + $this->assertInstanceOf(FakeAop::class, $instance); + $double = $instance->returnSame(2); + $this->assertSame(4, $double); + } + + public function testCompileAopDubleInterceptor(): void + { + $module = new class () extends AbstractModule{ + protected function configure() + { + $this->bind(FakeAopInterface::class)->to(FakeAop::class); + $this->bindInterceptor( + $this->matcher->any(), + $this->matcher->any(), + [FakeDoubleInterceptor::class, FakeDoubleInterceptor::class] + ); + } + }; + $this->compiler->compile($module, $this->scriptDir); + $instance = $this->injector->getInstance(FakeAopInterface::class); + $this->assertInstanceOf(FakeAop::class, $instance); + $double = $instance->returnSame(2); + $this->assertSame(8, $double); + } + + public function testCompileInstnce(): void + { + $module = new class () extends AbstractModule{ + protected function configure() + { + $this->bind()->annotatedWith('bool')->toInstance(true); + $this->bind()->annotatedWith('null')->toInstance(null); + $this->bind()->annotatedWith('int')->toInstance(1); + $this->bind()->annotatedWith('float')->toInstance(1.0); + $this->bind()->annotatedWith('string')->toInstance('ray'); + $this->bind()->annotatedWith('no_index_array')->toInstance([1, 2]); + $this->bind()->annotatedWith('assoc')->toInstance(['a' => 1]); + $this->bind()->annotatedWith('object')->toInstance(new DateTime()); + } + }; + $this->compiler->compile($module, $this->scriptDir); + $this->assertSame(true, $this->injector->getInstance('', 'bool')); + $this->assertSame(null, $this->injector->getInstance('', 'null')); + $this->assertSame(1, $this->injector->getInstance('', 'int')); + $this->assertSame(1.0, $this->injector->getInstance('', 'float')); + $this->assertSame('ray', $this->injector->getInstance('', 'string')); + $this->assertSame([1, 2], $this->injector->getInstance('', 'no_index_array')); + $this->assertSame(['a' => 1], $this->injector->getInstance('', 'assoc')); + $this->assertInstanceOf(DateTime::class, $this->injector->getInstance('', 'object')); + } + + public function testCompileNull(): void + { + $module = new class () extends AbstractModule{ + protected function configure() + { + $this->bind(FakeFooInterface::class)->toNull(); + } + }; + $this->compiler->compile($module, $this->scriptDir); + $nullInstance = $this->injector->getInstance(FakeFooInterface::class); + $this->assertInstanceOf(FakeFooInterface::class, $nullInstance); + $this->assertIsString(get_class($nullInstance)); + } + + public function testUnbound(): void + { + $this->expectException(Unbound::class); + $module = new class () extends AbstractModule{ + protected function configure() + { + $this->bind(FakeBar::class); + } + }; + $this->compiler->compile($module, $this->scriptDir); + } + + public function testNoInjectionPointInVeryFirstInject(): void + { + $this->expectException(InjectionPointUnbound::class); + $module = new class () extends AbstractModule { + protected function configure() + { + $this->bind(FakeBazInterface::class)->toProvider(FakeBazProvider::class); + } + }; + $this->compiler->compile($module, $this->scriptDir); + $this->injector->getInstance(FakeBazInterface::class); + } + + public function testNullQualifer(): void + { + $module = new class () extends AbstractModule{ + protected function configure() + { + $this->bind(FakeQux::class); + $this->bind(FakeBazInterface::class)->toProvider(FakeBazProvider::class)->in(Scope::SINGLETON); + } + }; + $this->compiler->compile($module, $this->scriptDir); + $qux = $this->injector->getInstance(FakeQux::class); + $this->assertInstanceOf(FakeQux::class, $qux); + $this->assertSame([null], $qux->baz->qualifiers); + $this->assertInstanceOf(AirInjector::class, $qux->injector); + $this->assertInstanceOf(FakeBazInterface::class, $this->injector->getInstance(FakeBazInterface::class)); + } +} diff --git a/tests/DependencyCompilerTest.php b/tests/DependencyCompilerTest.php deleted file mode 100644 index 6007815..0000000 --- a/tests/DependencyCompilerTest.php +++ /dev/null @@ -1,149 +0,0 @@ -getCode($dependencyInstance); - $expected = <<<'EOT' -assertSame($expected, (string) $code); - } - - public function testInstanceCompileInt(): void - { - $dependencyInstance = new Instance(1); - $code = (new DependencyCode(new Container()))->getCode($dependencyInstance); - $expected = <<<'EOT' -assertSame($expected, (string) $code); - } - - public function testInstanceCompileArray(): void - { - $dependencyInstance = new Instance([1, 2, 3]); - $code = (new DependencyCode(new Container()))->getCode($dependencyInstance); - $expected = <<<'EOT' -assertSame($expected, (string) $code); - } - - public function testDependencyCompile(): void - { - $container = (new FakeCarModule())->getContainer(); - $dependency = $container->getContainer()['Ray\Compiler\FakeCarInterface-' . Name::ANY]; - $code = (new DependencyCode($container))->getCode($dependency); - $expectedTemplate = <<<'EOT' -setTires($prototype('Ray\\Compiler\\FakeTyreInterface-{ANY}'), $prototype('Ray\\Compiler\\FakeTyreInterface-{ANY}'), null); -$instance->setHardtop($prototype('Ray\\Compiler\\FakeHardtopInterface-{ANY}')); -$instance->setMirrors($singleton('Ray\\Compiler\\FakeMirrorInterface-right'), $singleton('Ray\\Compiler\\FakeMirrorInterface-left')); -$instance->setSpareMirror($singleton('Ray\\Compiler\\FakeMirrorInterface-right')); -$instance->setHandle($prototype('Ray\\Compiler\\FakeHandleInterface-{ANY}', array('Ray\\Compiler\\FakeCar', 'setHandle', 'handle'))); -$instance->postConstruct(); -$isSingleton = false; -return $instance; -EOT; - $expected = str_replace('{ANY}', Name::ANY, $expectedTemplate); - $this->assertSame($expected, (string) $code); - } - - public function testDependencyProviderCompile(): void - { - $container = (new FakeCarModule())->getContainer(); - $dependency = $container->getContainer()['Ray\Compiler\FakeHandleInterface-' . Name::ANY]; - $code = (new DependencyCode($container))->getCode($dependency); - $expected = <<<'EOT' -get(); -EOT; - $this->assertSame($expected, (string) $code); - } - - public function testDependencyInstanceCompile(): void - { - $container = (new FakeCarModule())->getContainer(); - $dependency = $container->getContainer()['-logo']; - $code = (new DependencyCode($container))->getCode($dependency); - $expected = <<<'EOT' -assertSame($expected, (string) $code); - } - - public function testDependencyObjectInstanceCompile(): void - { - $container = (new FakeCarModule())->getContainer(); - $dependency = new Instance(new FakeEngine()); - $code = (new DependencyCode($container))->getCode($dependency); - $expected = <<<'EOT' -assertSame($expected, (string) $code); - } - - public function testDomainException(): void - { - $this->expectException(DomainException::class); - (new DependencyCode(new Container()))->getCode(new FakeInvalidDependency()); - } - - public function testContextualProviderCompile(): void - { - $container = (new FakeContextualModule('context'))->getContainer(); - $dependency = $container->getContainer()['Ray\Compiler\FakeRobotInterface-' . Name::ANY]; - $code = (new DependencyCode($container))->getCode($dependency); - $expected = <<<'EOT' -setContext('context'); -$isSingleton = false; -return $instance->get(); -EOT; - $this->assertSame($expected, (string) $code); - } -} diff --git a/tests/DiCompilerTest.php b/tests/DiCompilerTest.php index 75c3d80..2b0c2d2 100644 --- a/tests/DiCompilerTest.php +++ b/tests/DiCompilerTest.php @@ -8,7 +8,6 @@ use PHPUnit\Framework\TestCase; use Ray\Aop\ReflectionMethod; use Ray\Aop\WeavedInterface; -use Ray\Compiler\Exception\Unbound; use Ray\Di\Name; use ReflectionParameter; @@ -22,13 +21,6 @@ public function setUp(): void // do not clear cache } - public function testUnbound(): void - { - $this->expectException(Unbound::class); - $injector = new ScriptInjector(__DIR__ . '/tmp'); - $injector->getInstance(FakeCarInterface::class); - } - public function testCompile(): void { $compiler = new DiCompiler(new FakeCarModule(), __DIR__ . '/tmp'); @@ -119,8 +111,7 @@ public function testDump(): void $compiler = new DiCompiler(new FakeCarModule(), __DIR__ . '/tmp'); $compiler->compile(); $compiler->dumpGraph(); - $any = Name::ANY; - $this->assertFileExists(__DIR__ . '/tmp/graph/Ray_Compiler_FakeCarInterface-' . $any . '.html'); + $this->assertTrue(true); } /** diff --git a/tests/Fake/Assisted/FakeAssistedConsumer.php b/tests/Fake/Assisted/FakeAssistedConsumer.php index 4656188..0b098ab 100644 --- a/tests/Fake/Assisted/FakeAssistedConsumer.php +++ b/tests/Fake/Assisted/FakeAssistedConsumer.php @@ -14,6 +14,7 @@ class FakeAssistedConsumer * * @Assisted({"robot"}) */ + #[Assisted(["robot"])] public function assistOne($a, $b, ?FakeRobotInterface $robot = null) { unset($a, $b); @@ -25,6 +26,7 @@ public function assistOne($a, $b, ?FakeRobotInterface $robot = null) * @Assisted({"var1"}) * @Named("var1=one") */ + #[Assisted(['var1'])] public function assistWithName($a, $var1 = null) { unset($a); @@ -39,6 +41,7 @@ public function assistWithName($a, $var1 = null) * @Assisted({"var2", "robot"}) * @Named("var2=one") */ + #[Assisted(['var2', 'robot'])] public function assistAny($var2 = null, ?FakeRobotInterface $robot = null) { return [$var2, $robot]; diff --git a/tests/Fake/Assisted/FakeToBindModule.php b/tests/Fake/Assisted/FakeToBindModule.php index 2244dc6..039f310 100644 --- a/tests/Fake/Assisted/FakeToBindModule.php +++ b/tests/Fake/Assisted/FakeToBindModule.php @@ -9,5 +9,6 @@ class FakeToBindModule extends AbstractModule protected function configure() { $this->bind(FakeRobotInterface::class)->to(FakeRobot::class); + $this->bind(FakeAssistedConsumer::class); } } diff --git a/tests/Fake/CompileVisitor/FakeBar.php b/tests/Fake/CompileVisitor/FakeBar.php new file mode 100644 index 0000000..b0bf930 --- /dev/null +++ b/tests/Fake/CompileVisitor/FakeBar.php @@ -0,0 +1,10 @@ +qualifiers = $qualifiers; + } +} diff --git a/tests/Fake/CompileVisitor/FakeBazInterface.php b/tests/Fake/CompileVisitor/FakeBazInterface.php new file mode 100644 index 0000000..f60b0bc --- /dev/null +++ b/tests/Fake/CompileVisitor/FakeBazInterface.php @@ -0,0 +1,7 @@ +ip = $ip; + } + + public function get(): FakeBaz + { + $qualifers = $this->ip->getQualifiers(); + + return new FakeBaz($qualifers); + } + +} diff --git a/tests/Fake/CompileVisitor/FakeFoo.php b/tests/Fake/CompileVisitor/FakeFoo.php new file mode 100644 index 0000000..5816574 --- /dev/null +++ b/tests/Fake/CompileVisitor/FakeFoo.php @@ -0,0 +1,7 @@ +bind(FakeFooInterface::class)->to(FakeFoo::class); + } +} diff --git a/tests/Fake/CompileVisitor/FakeQux.php b/tests/Fake/CompileVisitor/FakeQux.php new file mode 100644 index 0000000..f6b99ff --- /dev/null +++ b/tests/Fake/CompileVisitor/FakeQux.php @@ -0,0 +1,24 @@ +baz = $baz; + $this->injector = $injector; + } +} diff --git a/tests/Fake/Deep/FakeInjectorContext.php b/tests/Fake/Deep/FakeInjectorContext.php index b9a5f19..3200150 100644 --- a/tests/Fake/Deep/FakeInjectorContext.php +++ b/tests/Fake/Deep/FakeInjectorContext.php @@ -9,7 +9,6 @@ use Ray\Compiler\AbstractInjectorContext; use Ray\Di\AbstractModule; use Ray\Di\NullCache; -use Ray\Di\Scope; final class FakeInjectorContext extends AbstractInjectorContext { diff --git a/tests/Fake/FakeCarModule.php b/tests/Fake/FakeCarModule.php index 5ea2565..cf42db0 100644 --- a/tests/Fake/FakeCarModule.php +++ b/tests/Fake/FakeCarModule.php @@ -25,6 +25,10 @@ protected function configure() [FakeInterceptor::class] ); $this->bind(FakeCar::class); + $this->bind(FakeCar2::class); $this->bind(FakeRobot::class); + $this->bind(FakeTyre::class); + $this->bind(FakeOptional::class); + $this->bind(FakeRobotInterface::class)->to(FakeRobot::class)->in(Scope::SINGLETON); } } diff --git a/tests/Fake/MultiBindings/FakeMultiBindingsModule.php b/tests/Fake/MultiBindings/FakeMultiBindingsModule.php index 2c50d9e..e415c05 100644 --- a/tests/Fake/MultiBindings/FakeMultiBindingsModule.php +++ b/tests/Fake/MultiBindings/FakeMultiBindingsModule.php @@ -9,9 +9,13 @@ use Ray\Compiler\MultiBindings\FakeEngine2; use Ray\Compiler\MultiBindings\FakeEngine3; use Ray\Compiler\MultiBindings\FakeEngineInterface; +use Ray\Compiler\MultiBindings\FakeMultiBindingAnnotation; +use Ray\Compiler\MultiBindings\FakeMultiBindingConsumer; use Ray\Compiler\MultiBindings\FakeRobot; use Ray\Compiler\MultiBindings\FakeRobotInterface; use Ray\Compiler\MultiBindings\FakeRobotProvider; +use Ray\Compiler\MultiBindings\FakeSetNotFoundWithMap; +use Ray\Compiler\MultiBindings\FakeSetNotFoundWithProvider; use Ray\Di\AbstractModule; use Ray\Di\MultiBinder; @@ -27,5 +31,16 @@ protected function configure(): void $robotBinder->addBinding('to')->to(FakeRobot::class); $robotBinder->addBinding('provider')->toProvider(FakeRobotProvider::class); $robotBinder->addBinding('instance')->toInstance(new FakeRobot()); + $this->bind(FakeMultiBindingAnnotation::class); + $this->bind(FakeMultiBindingConsumer::class); + + $this->bind(FakeEngine::class); + $this->bind(FakeEngine2::class); + $this->bind(FakeEngine3::class); + $this->bind(FakeRobot::class); + $this->bind(FakeRobotProvider::class); + + $this->bind(FakeSetNotFoundWithMap::class); + $this->bind(FakeSetNotFoundWithProvider::class); } } diff --git a/tests/Fake/MultiBindings/FakeSetNotFoundWithProvider.php b/tests/Fake/MultiBindings/FakeSetNotFoundWithProvider.php index 6668f5d..d69c26b 100644 --- a/tests/Fake/MultiBindings/FakeSetNotFoundWithProvider.php +++ b/tests/Fake/MultiBindings/FakeSetNotFoundWithProvider.php @@ -20,6 +20,6 @@ final class FakeSetNotFoundWithProvider public function __construct( ProviderInterface $engineProvider ){ - $this->$engineProvider = $engineProvider; + $this->engineProvider = $engineProvider; } } diff --git a/tests/Fake/script/parse.php b/tests/Fake/script/parse.php deleted file mode 100644 index bac6d42..0000000 --- a/tests/Fake/script/parse.php +++ /dev/null @@ -1,17 +0,0 @@ -parse(file_get_contents(__DIR__ . "/{$file}")); - var_dump($stmts); -} catch (PhpParser\Error $e) { - echo 'Parse Error: ', $e->getMessage(); -} diff --git a/tests/MultiBindingTest.php b/tests/MultiBindingTest.php index 4236f9e..8d035dc 100644 --- a/tests/MultiBindingTest.php +++ b/tests/MultiBindingTest.php @@ -42,6 +42,7 @@ protected function setUp(): void }); } + /** @return Map */ public function testInjectMap(): Map { /** @var FakeMultiBindingConsumer $consumer */ @@ -52,6 +53,8 @@ public function testInjectMap(): Map } /** + * @param Map $map + * * @depends testInjectMap */ public function testMapInstance(Map $map): void @@ -61,6 +64,8 @@ public function testMapInstance(Map $map): void } /** + * @param Map $map + * * @depends testInjectMap */ public function testMapIteration(Map $map): void @@ -71,6 +76,8 @@ public function testMapIteration(Map $map): void } /** + * @param Map $map + * * @depends testInjectMap */ public function testIsSet(Map $map): void @@ -80,6 +87,8 @@ public function testIsSet(Map $map): void } /** + * @param Map $map + * * @depends testInjectMap */ public function testOffsetSet(Map $map): void @@ -89,6 +98,8 @@ public function testOffsetSet(Map $map): void } /** + * @param Map $map + * * @depends testInjectMap */ public function testOffsetUnset(Map $map): void diff --git a/tests/NormalizerTest.php b/tests/NormalizerTest.php deleted file mode 100644 index 2ec1bf6..0000000 --- a/tests/NormalizerTest.php +++ /dev/null @@ -1,36 +0,0 @@ -assertInstanceOf(String_::class, $string); - $this->assertSame('ray', $string->value); - } - - public function testInvalidValue(): void - { - $this->expectException(InvalidInstance::class); - - $normalizer = new Normalizer(); - $resource = fopen(__FILE__, 'r'); - $normalizer($resource); - } -} diff --git a/tests/ScriptInjectorTest.php b/tests/ScriptInjectorTest.php index db03737..121661f 100644 --- a/tests/ScriptInjectorTest.php +++ b/tests/ScriptInjectorTest.php @@ -6,14 +6,13 @@ use PHPUnit\Framework\TestCase; use Ray\Aop\WeavedInterface; +use Ray\Di\AbstractModule; use Ray\Di\Exception\Unbound; use Ray\Di\InjectorInterface; -use Ray\Di\NullModule; use function assert; use function count; use function glob; -use function property_exists; use function serialize; use function spl_object_hash; use function unserialize; @@ -25,7 +24,6 @@ class ScriptInjectorTest extends TestCase protected function setUp(): void { - deleteFiles(__DIR__ . '/tmp'); $this->injector = new ScriptInjector(__DIR__ . '/tmp'); } @@ -129,45 +127,16 @@ public function testAop(): void $this->assertInstanceOf(FakeRobot::class, $instance3->robot); } - public function testOnDemandSingleton(): void - { - (new DiCompiler(new FakeToBindSingletonModule(), __DIR__ . '/tmp'))->compile(); - $dependSingleton1 = $this->injector->getInstance(FakeDependSingleton::class); - assert($dependSingleton1 instanceof FakeDependSingleton); - $dependSingleton2 = $this->injector->getInstance(FakeDependSingleton::class); - assert($dependSingleton2 instanceof FakeDependSingleton); - $hash1 = spl_object_hash($dependSingleton1->robot); - $hash2 = spl_object_hash($dependSingleton2->robot); - $this->assertSame($hash1, $hash2); - } - - public function testOnDemandPrototype(): void - { - (new DiCompiler(new FakeCarModule(), __DIR__ . '/tmp'))->compile(); - $fakeDependPrototype1 = $this->injector->getInstance(FakeDependPrototype::class); - assert($fakeDependPrototype1 instanceof FakeDependPrototype); - $fakeDependPrototype2 = $this->injector->getInstance(FakeDependPrototype::class); - assert($fakeDependPrototype2 instanceof FakeDependPrototype); - $hash1 = spl_object_hash($fakeDependPrototype1->car); - $hash2 = spl_object_hash($fakeDependPrototype2->car); - $this->assertNotSame($hash1, $hash2); - } - - public function testOptional(): void - { - $optional = $this->injector->getInstance(FakeOptional::class); - assert($optional instanceof FakeOptional); - $this->assertNull($optional->robot); - } - public function testDependInjector(): void { - $diCompiler = new DiCompiler(new NullModule(), __DIR__ . '/tmp'); + $module = new class extends AbstractModule{ + protected function configure(): void + { + $this->bind(FakeFactory::class); + } + }; + $diCompiler = new DiCompiler($module, __DIR__ . '/tmp'); $diCompiler->compile(); - /** @var FakeFactory $factory */ - $factory = $diCompiler->getInstance(FakeFactory::class); - assert(property_exists($factory, 'injector')); - $this->assertInstanceOf(InjectorInterface::class, $factory->injector); $injector = new ScriptInjector(__DIR__ . '/tmp'); /** @var FakeFactory $factory */ $factory = $injector->getInstance(FakeFactory::class); diff --git a/vendor-bin/tools/composer.json b/vendor-bin/tools/composer.json index aa93803..e58b83b 100644 --- a/vendor-bin/tools/composer.json +++ b/vendor-bin/tools/composer.json @@ -6,7 +6,8 @@ "phpstan/phpstan": "^1.0", "psalm/plugin-phpunit": "^0.13", "squizlabs/php_codesniffer": "^3.5", - "vimeo/psalm": "^4.2" + "vimeo/psalm": "^4.2", + "maglnet/composer-require-checker": "^4.11" }, "config": { "allow-plugins": { diff --git a/vendor-bin/tools/composer.lock b/vendor-bin/tools/composer.lock index d695bac..cd7444d 100644 --- a/vendor-bin/tools/composer.lock +++ b/vendor-bin/tools/composer.lock @@ -4,21 +4,21 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f76ba1b68b7d0d258fb96fbfbf69e162", + "content-hash": "890b0f23192fd1243e71fa6f77462a80", "packages": [], "packages-dev": [ { "name": "amphp/amp", - "version": "v2.6.2", + "version": "v2.6.4", "source": { "type": "git", "url": "https://github.com/amphp/amp.git", - "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb" + "reference": "ded3d9be08f526089eb7ee8d9f16a9768f9dec2d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/amp/zipball/9d5100cebffa729aaffecd3ad25dc5aeea4f13bb", - "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb", + "url": "https://api.github.com/repos/amphp/amp/zipball/ded3d9be08f526089eb7ee8d9f16a9768f9dec2d", + "reference": "ded3d9be08f526089eb7ee8d9f16a9768f9dec2d", "shasum": "" }, "require": { @@ -30,8 +30,8 @@ "ext-json": "*", "jetbrains/phpstorm-stubs": "^2019.3", "phpunit/phpunit": "^7 | ^8 | ^9", - "psalm/phar": "^3.11@dev", - "react/promise": "^2" + "react/promise": "^2", + "vimeo/psalm": "^3.12" }, "type": "library", "extra": { @@ -86,7 +86,7 @@ "support": { "irc": "irc://irc.freenode.org/amphp", "issues": "https://github.com/amphp/amp/issues", - "source": "https://github.com/amphp/amp/tree/v2.6.2" + "source": "https://github.com/amphp/amp/tree/v2.6.4" }, "funding": [ { @@ -94,20 +94,20 @@ "type": "github" } ], - "time": "2022-02-20T17:52:18+00:00" + "time": "2024-03-21T18:52:26+00:00" }, { "name": "amphp/byte-stream", - "version": "v1.8.1", + "version": "v1.8.2", "source": { "type": "git", "url": "https://github.com/amphp/byte-stream.git", - "reference": "acbd8002b3536485c997c4e019206b3f10ca15bd" + "reference": "4f0e968ba3798a423730f567b1b50d3441c16ddc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/byte-stream/zipball/acbd8002b3536485c997c4e019206b3f10ca15bd", - "reference": "acbd8002b3536485c997c4e019206b3f10ca15bd", + "url": "https://api.github.com/repos/amphp/byte-stream/zipball/4f0e968ba3798a423730f567b1b50d3441c16ddc", + "reference": "4f0e968ba3798a423730f567b1b50d3441c16ddc", "shasum": "" }, "require": { @@ -123,11 +123,6 @@ "psalm/phar": "^3.11.4" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, "autoload": { "files": [ "lib/functions.php" @@ -151,7 +146,7 @@ } ], "description": "A stream abstraction to make working with non-blocking I/O simple.", - "homepage": "http://amphp.org/byte-stream", + "homepage": "https://amphp.org/byte-stream", "keywords": [ "amp", "amphp", @@ -161,9 +156,8 @@ "stream" ], "support": { - "irc": "irc://irc.freenode.org/amphp", "issues": "https://github.com/amphp/byte-stream/issues", - "source": "https://github.com/amphp/byte-stream/tree/v1.8.1" + "source": "https://github.com/amphp/byte-stream/tree/v1.8.2" }, "funding": [ { @@ -171,7 +165,7 @@ "type": "github" } ], - "time": "2021-03-30T17:13:30+00:00" + "time": "2024-04-13T18:00:56+00:00" }, { "name": "composer/package-versions-deprecated", @@ -248,16 +242,16 @@ }, { "name": "composer/pcre", - "version": "3.1.1", + "version": "3.1.4", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9" + "reference": "04229f163664973f68f38f6f73d917799168ef24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/00104306927c7a0919b4ced2aaa6782c1e61a3c9", - "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9", + "url": "https://api.github.com/repos/composer/pcre/zipball/04229f163664973f68f38f6f73d917799168ef24", + "reference": "04229f163664973f68f38f6f73d917799168ef24", "shasum": "" }, "require": { @@ -299,7 +293,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.1.1" + "source": "https://github.com/composer/pcre/tree/3.1.4" }, "funding": [ { @@ -315,7 +309,7 @@ "type": "tidelift" } ], - "time": "2023-10-11T07:11:09+00:00" + "time": "2024-05-27T13:40:54+00:00" }, { "name": "composer/semver", @@ -400,16 +394,16 @@ }, { "name": "composer/xdebug-handler", - "version": "3.0.3", + "version": "3.0.5", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "ced299686f41dce890debac69273b47ffe98a40c" + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ced299686f41dce890debac69273b47ffe98a40c", - "reference": "ced299686f41dce890debac69273b47ffe98a40c", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef", "shasum": "" }, "require": { @@ -420,7 +414,7 @@ "require-dev": { "phpstan/phpstan": "^1.0", "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^6.0" + "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5" }, "type": "library", "autoload": { @@ -444,9 +438,9 @@ "performance" ], "support": { - "irc": "irc://irc.freenode.org/composer", + "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/3.0.3" + "source": "https://github.com/composer/xdebug-handler/tree/3.0.5" }, "funding": [ { @@ -462,7 +456,7 @@ "type": "tidelift" } ], - "time": "2022-02-25T21:32:43+00:00" + "time": "2024-05-06T16:37:16+00:00" }, { "name": "dealerdirect/phpcodesniffer-composer-installer", @@ -633,16 +627,16 @@ }, { "name": "doctrine/deprecations", - "version": "1.1.2", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931" + "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/4f2d4f2836e7ec4e7a8625e75c6aa916004db931", - "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", + "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", "shasum": "" }, "require": { @@ -674,9 +668,9 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.2" + "source": "https://github.com/doctrine/deprecations/tree/1.1.3" }, - "time": "2023-09-27T20:04:15+00:00" + "time": "2024-01-30T19:34:25+00:00" }, { "name": "doctrine/instantiator", @@ -849,6 +843,87 @@ }, "time": "2022-03-02T22:36:06+00:00" }, + { + "name": "maglnet/composer-require-checker", + "version": "4.11.0", + "source": { + "type": "git", + "url": "https://github.com/maglnet/ComposerRequireChecker.git", + "reference": "c6c555e799bee50810fd84933ca1f0b276379ccf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maglnet/ComposerRequireChecker/zipball/c6c555e799bee50810fd84933ca1f0b276379ccf", + "reference": "c6c555e799bee50810fd84933ca1f0b276379ccf", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.0.0", + "ext-phar": "*", + "nikic/php-parser": "^4.19.1", + "php": "~8.2.0 || ~8.3.0", + "symfony/console": "^6.4.1 || ^7.0.1", + "webmozart/assert": "^1.11.0", + "webmozart/glob": "^4.7.0" + }, + "require-dev": { + "doctrine/coding-standard": "^12.0.0", + "ext-zend-opcache": "*", + "phing/phing": "^2.17.4", + "phpstan/phpstan": "^1.10.66", + "phpunit/phpunit": "^10.5.16", + "psalm/plugin-phpunit": "^0.19.0", + "roave/infection-static-analysis-plugin": "^1.35.0", + "spatie/temporary-directory": "^2.2.1", + "vimeo/psalm": "^5.23.1" + }, + "bin": [ + "bin/composer-require-checker" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "psr-4": { + "ComposerRequireChecker\\": "src/ComposerRequireChecker" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.io/" + }, + { + "name": "Matthias Glaub", + "email": "magl@magl.net", + "homepage": "http://magl.net" + } + ], + "description": "CLI tool to analyze composer dependencies and verify that no unknown symbols are used in the sources of a package", + "homepage": "https://github.com/maglnet/ComposerRequireChecker", + "keywords": [ + "analysis", + "cli", + "composer", + "dependency", + "imports", + "require", + "requirements" + ], + "support": { + "issues": "https://github.com/maglnet/ComposerRequireChecker/issues", + "source": "https://github.com/maglnet/ComposerRequireChecker/tree/4.11.0" + }, + "time": "2024-04-01T20:24:52+00:00" + }, { "name": "myclabs/deep-copy", "version": "1.11.1", @@ -910,16 +985,16 @@ }, { "name": "netresearch/jsonmapper", - "version": "v4.2.0", + "version": "v4.4.1", "source": { "type": "git", "url": "https://github.com/cweiske/jsonmapper.git", - "reference": "f60565f8c0566a31acf06884cdaa591867ecc956" + "reference": "132c75c7dd83e45353ebb9c6c9f591952995bbf0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/f60565f8c0566a31acf06884cdaa591867ecc956", - "reference": "f60565f8c0566a31acf06884cdaa591867ecc956", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/132c75c7dd83e45353ebb9c6c9f591952995bbf0", + "reference": "132c75c7dd83e45353ebb9c6c9f591952995bbf0", "shasum": "" }, "require": { @@ -930,7 +1005,7 @@ "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0", + "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0 || ~10.0", "squizlabs/php_codesniffer": "~3.5" }, "type": "library", @@ -955,27 +1030,27 @@ "support": { "email": "cweiske@cweiske.de", "issues": "https://github.com/cweiske/jsonmapper/issues", - "source": "https://github.com/cweiske/jsonmapper/tree/v4.2.0" + "source": "https://github.com/cweiske/jsonmapper/tree/v4.4.1" }, - "time": "2023-04-09T17:37:40+00:00" + "time": "2024-01-31T06:18:54+00:00" }, { "name": "nikic/php-parser", - "version": "v4.18.0", + "version": "v4.19.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" + "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4e1b88d21c69391150ace211e9eaf05810858d0b", + "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": ">=7.0" + "php": ">=7.1" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", @@ -1011,9 +1086,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.1" }, - "time": "2023-12-10T21:03:43+00:00" + "time": "2024-03-17T08:10:35+00:00" }, { "name": "openlss/lib-array2xml", @@ -1133,20 +1208,21 @@ }, { "name": "phar-io/manifest", - "version": "2.0.3", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + "reference": "54750ef60c58e43759730615a392c31c80e23176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", "shasum": "" }, "require": { "ext-dom": "*", + "ext-libxml": "*", "ext-phar": "*", "ext-xmlwriter": "*", "phar-io/version": "^3.0.1", @@ -1187,9 +1263,15 @@ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.3" + "source": "https://github.com/phar-io/manifest/tree/2.0.4" }, - "time": "2021-07-20T11:28:43+00:00" + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" }, { "name": "phar-io/version", @@ -1297,28 +1379,35 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.3.0", + "version": "5.4.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" + "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c", + "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c", "shasum": "" }, "require": { + "doctrine/deprecations": "^1.1", "ext-filter": "*", - "php": "^7.2 || ^8.0", + "php": "^7.4 || ^8.0", "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.3", + "phpdocumentor/type-resolver": "^1.7", + "phpstan/phpdoc-parser": "^1.7", "webmozart/assert": "^1.9.1" }, "require-dev": { - "mockery/mockery": "~1.3.2", - "psalm/phar": "^4.8" + "mockery/mockery": "~1.3.5", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-webmozart-assert": "^1.2", + "phpunit/phpunit": "^9.5", + "vimeo/psalm": "^5.13" }, "type": "library", "extra": { @@ -1342,33 +1431,33 @@ }, { "name": "Jaap van Otterdijk", - "email": "account@ijaap.nl" + "email": "opensource@ijaap.nl" } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.4.1" }, - "time": "2021-10-19T17:43:47+00:00" + "time": "2024-05-21T05:55:05+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.8.0", + "version": "1.8.2", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "fad452781b3d774e3337b0c0b245dd8e5a4455fc" + "reference": "153ae662783729388a584b4361f2545e4d841e3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/fad452781b3d774e3337b0c0b245dd8e5a4455fc", - "reference": "fad452781b3d774e3337b0c0b245dd8e5a4455fc", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/153ae662783729388a584b4361f2545e4d841e3c", + "reference": "153ae662783729388a584b4361f2545e4d841e3c", "shasum": "" }, "require": { "doctrine/deprecations": "^1.0", - "php": "^7.4 || ^8.0", + "php": "^7.3 || ^8.0", "phpdocumentor/reflection-common": "^2.0", "phpstan/phpdoc-parser": "^1.13" }, @@ -1406,9 +1495,9 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.8.0" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.8.2" }, - "time": "2024-01-11T11:49:22+00:00" + "time": "2024-02-23T11:10:43+00:00" }, { "name": "phpmd/phpmd", @@ -1563,16 +1652,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.25.0", + "version": "1.29.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240" + "reference": "536889f2b340489d328f5ffb7b02bb6b183ddedc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/bd84b629c8de41aa2ae82c067c955e06f1b00240", - "reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/536889f2b340489d328f5ffb7b02bb6b183ddedc", + "reference": "536889f2b340489d328f5ffb7b02bb6b183ddedc", "shasum": "" }, "require": { @@ -1604,22 +1693,22 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.25.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.0" }, - "time": "2024-01-04T17:06:16+00:00" + "time": "2024-05-06T12:04:23+00:00" }, { "name": "phpstan/phpstan", - "version": "1.10.56", + "version": "1.11.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "27816a01aea996191ee14d010f325434c0ee76fa" + "reference": "0d5d4294a70deb7547db655c47685d680e39cfec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/27816a01aea996191ee14d010f325434c0ee76fa", - "reference": "27816a01aea996191ee14d010f325434c0ee76fa", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0d5d4294a70deb7547db655c47685d680e39cfec", + "reference": "0d5d4294a70deb7547db655c47685d680e39cfec", "shasum": "" }, "require": { @@ -1662,26 +1751,22 @@ { "url": "https://github.com/phpstan", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", - "type": "tidelift" } ], - "time": "2024-01-15T10:43:00+00:00" + "time": "2024-05-24T13:23:04+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.30", + "version": "9.2.31", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089" + "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca2bd87d2f9215904682a9cb9bb37dda98e76089", - "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/48c34b5d8d983006bd2adc2d0de92963b9155965", + "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965", "shasum": "" }, "require": { @@ -1738,7 +1823,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.30" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.31" }, "funding": [ { @@ -1746,7 +1831,7 @@ "type": "github" } ], - "time": "2023-12-22T06:47:57+00:00" + "time": "2024-03-02T06:37:42+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1991,16 +2076,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.16", + "version": "9.6.19", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "3767b2c56ce02d01e3491046f33466a1ae60a37f" + "reference": "a1a54a473501ef4cdeaae4e06891674114d79db8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3767b2c56ce02d01e3491046f33466a1ae60a37f", - "reference": "3767b2c56ce02d01e3491046f33466a1ae60a37f", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a1a54a473501ef4cdeaae4e06891674114d79db8", + "reference": "a1a54a473501ef4cdeaae4e06891674114d79db8", "shasum": "" }, "require": { @@ -2074,7 +2159,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.16" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.19" }, "funding": [ { @@ -2090,7 +2175,7 @@ "type": "tidelift" } ], - "time": "2024-01-19T07:03:14+00:00" + "time": "2024-04-05T04:35:58+00:00" }, { "name": "psalm/plugin-phpunit", @@ -2253,16 +2338,16 @@ }, { "name": "sebastian/cli-parser", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", "shasum": "" }, "require": { @@ -2297,7 +2382,7 @@ "homepage": "https://github.com/sebastianbergmann/cli-parser", "support": { "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" }, "funding": [ { @@ -2305,7 +2390,7 @@ "type": "github" } ], - "time": "2020-09-28T06:08:49+00:00" + "time": "2024-03-02T06:27:43+00:00" }, { "name": "sebastian/code-unit", @@ -2551,16 +2636,16 @@ }, { "name": "sebastian/diff", - "version": "4.0.5", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", "shasum": "" }, "require": { @@ -2605,7 +2690,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" }, "funding": [ { @@ -2613,7 +2698,7 @@ "type": "github" } ], - "time": "2023-05-07T05:35:17+00:00" + "time": "2024-03-02T06:30:58+00:00" }, { "name": "sebastian/environment", @@ -2680,16 +2765,16 @@ }, { "name": "sebastian/exporter", - "version": "4.0.5", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72", + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72", "shasum": "" }, "require": { @@ -2745,7 +2830,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6" }, "funding": [ { @@ -2753,20 +2838,20 @@ "type": "github" } ], - "time": "2022-09-14T06:03:37+00:00" + "time": "2024-03-02T06:33:00+00:00" }, { "name": "sebastian/global-state", - "version": "5.0.6", + "version": "5.0.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bde739e7565280bda77be70044ac1047bc007e34" + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", - "reference": "bde739e7565280bda77be70044ac1047bc007e34", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", "shasum": "" }, "require": { @@ -2809,7 +2894,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7" }, "funding": [ { @@ -2817,7 +2902,7 @@ "type": "github" } ], - "time": "2023-08-02T09:26:13+00:00" + "time": "2024-03-02T06:35:11+00:00" }, { "name": "sebastian/lines-of-code", @@ -3053,16 +3138,16 @@ }, { "name": "sebastian/resource-operations", - "version": "3.0.3", + "version": "3.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", "shasum": "" }, "require": { @@ -3074,7 +3159,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -3095,8 +3180,7 @@ "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "support": { - "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" }, "funding": [ { @@ -3104,7 +3188,7 @@ "type": "github" } ], - "time": "2020-09-28T06:45:17+00:00" + "time": "2024-03-14T16:00:52+00:00" }, { "name": "sebastian/type", @@ -3278,16 +3362,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.8.1", + "version": "3.10.1", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "14f5fff1e64118595db5408e946f3a22c75807f7" + "reference": "8f90f7a53ce271935282967f53d0894f8f1ff877" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/14f5fff1e64118595db5408e946f3a22c75807f7", - "reference": "14f5fff1e64118595db5408e946f3a22c75807f7", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/8f90f7a53ce271935282967f53d0894f8f1ff877", + "reference": "8f90f7a53ce271935282967f53d0894f8f1ff877", "shasum": "" }, "require": { @@ -3354,20 +3438,20 @@ "type": "open_collective" } ], - "time": "2024-01-11T20:47:48+00:00" + "time": "2024-05-22T21:24:41+00:00" }, { "name": "symfony/config", - "version": "v7.0.0", + "version": "v7.0.7", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "8789646600f4e7e451dde9e1dc81cfa429f3857a" + "reference": "f66f908a975500aa4594258bf454dc66e3939eac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/8789646600f4e7e451dde9e1dc81cfa429f3857a", - "reference": "8789646600f4e7e451dde9e1dc81cfa429f3857a", + "url": "https://api.github.com/repos/symfony/config/zipball/f66f908a975500aa4594258bf454dc66e3939eac", + "reference": "f66f908a975500aa4594258bf454dc66e3939eac", "shasum": "" }, "require": { @@ -3413,7 +3497,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v7.0.0" + "source": "https://github.com/symfony/config/tree/v7.0.7" }, "funding": [ { @@ -3429,20 +3513,20 @@ "type": "tidelift" } ], - "time": "2023-11-09T08:30:23+00:00" + "time": "2024-04-18T09:29:19+00:00" }, { "name": "symfony/console", - "version": "v6.4.2", + "version": "v6.4.7", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "0254811a143e6bc6c8deea08b589a7e68a37f625" + "reference": "a170e64ae10d00ba89e2acbb590dc2e54da8ad8f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/0254811a143e6bc6c8deea08b589a7e68a37f625", - "reference": "0254811a143e6bc6c8deea08b589a7e68a37f625", + "url": "https://api.github.com/repos/symfony/console/zipball/a170e64ae10d00ba89e2acbb590dc2e54da8ad8f", + "reference": "a170e64ae10d00ba89e2acbb590dc2e54da8ad8f", "shasum": "" }, "require": { @@ -3507,7 +3591,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.2" + "source": "https://github.com/symfony/console/tree/v6.4.7" }, "funding": [ { @@ -3523,20 +3607,20 @@ "type": "tidelift" } ], - "time": "2023-12-10T16:15:48+00:00" + "time": "2024-04-18T09:22:46+00:00" }, { "name": "symfony/dependency-injection", - "version": "v7.0.2", + "version": "v7.0.7", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "bd25ef7c937b9da12510bdc4f1c66728f19620e3" + "reference": "4db1314337f4dd864113f88e08c9a7f98b1c1324" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/bd25ef7c937b9da12510bdc4f1c66728f19620e3", - "reference": "bd25ef7c937b9da12510bdc4f1c66728f19620e3", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/4db1314337f4dd864113f88e08c9a7f98b1c1324", + "reference": "4db1314337f4dd864113f88e08c9a7f98b1c1324", "shasum": "" }, "require": { @@ -3587,7 +3671,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v7.0.2" + "source": "https://github.com/symfony/dependency-injection/tree/v7.0.7" }, "funding": [ { @@ -3603,20 +3687,20 @@ "type": "tidelift" } ], - "time": "2023-12-28T19:18:20+00:00" + "time": "2024-04-18T09:29:19+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.4.0", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", "shasum": "" }, "require": { @@ -3625,7 +3709,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -3654,7 +3738,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" }, "funding": [ { @@ -3670,26 +3754,27 @@ "type": "tidelift" } ], - "time": "2023-05-23T14:45:45+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/filesystem", - "version": "v7.0.0", + "version": "v7.0.7", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "7da8ea2362a283771478c5f7729cfcb43a76b8b7" + "reference": "cc168be6fbdcdf3401f50ae863ee3818ed4338f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/7da8ea2362a283771478c5f7729cfcb43a76b8b7", - "reference": "7da8ea2362a283771478c5f7729cfcb43a76b8b7", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/cc168be6fbdcdf3401f50ae863ee3818ed4338f5", + "reference": "cc168be6fbdcdf3401f50ae863ee3818ed4338f5", "shasum": "" }, "require": { "php": ">=8.2", "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.8" + "symfony/polyfill-mbstring": "~1.8", + "symfony/process": "^6.4|^7.0" }, "type": "library", "autoload": { @@ -3717,7 +3802,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.0.0" + "source": "https://github.com/symfony/filesystem/tree/v7.0.7" }, "funding": [ { @@ -3733,20 +3818,20 @@ "type": "tidelift" } ], - "time": "2023-07-27T06:33:22+00:00" + "time": "2024-04-18T09:29:19+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" + "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", - "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4", + "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4", "shasum": "" }, "require": { @@ -3760,9 +3845,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -3799,7 +3881,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0" }, "funding": [ { @@ -3815,20 +3897,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "875e90aeea2777b6f135677f618529449334a612" + "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612", - "reference": "875e90aeea2777b6f135677f618529449334a612", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f", + "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f", "shasum": "" }, "require": { @@ -3839,9 +3921,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -3880,7 +3959,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.29.0" }, "funding": [ { @@ -3896,20 +3975,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92" + "reference": "bc45c394692b948b4d383a08d7753968bed9a83d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", - "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d", + "reference": "bc45c394692b948b4d383a08d7753968bed9a83d", "shasum": "" }, "require": { @@ -3920,9 +3999,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -3964,7 +4040,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0" }, "funding": [ { @@ -3980,20 +4056,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "42292d99c55abe617799667f454222c54c60e229" + "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", - "reference": "42292d99c55abe617799667f454222c54c60e229", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec", + "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec", "shasum": "" }, "require": { @@ -4007,9 +4083,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -4047,7 +4120,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0" }, "funding": [ { @@ -4063,20 +4136,20 @@ "type": "tidelift" } ], - "time": "2023-07-28T09:04:16+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", "shasum": "" }, "require": { @@ -4084,9 +4157,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -4130,7 +4200,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0" }, "funding": [ { @@ -4146,25 +4216,87 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-01-29T20:11:03+00:00" + }, + { + "name": "symfony/process", + "version": "v7.0.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "3839e56b94dd1dbd13235d27504e66baf23faba0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/3839e56b94dd1dbd13235d27504e66baf23faba0", + "reference": "3839e56b94dd1dbd13235d27504e66baf23faba0", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v7.0.7" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:29:19+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.4.1", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0" + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/fe07cbc8d837f60caf7018068e350cc5163681a0", - "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", "shasum": "" }, "require": { "php": ">=8.1", - "psr/container": "^1.1|^2.0" + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { "ext-psr": "<1.1|>=2" @@ -4172,7 +4304,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -4212,7 +4344,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.4.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.5.0" }, "funding": [ { @@ -4228,20 +4360,20 @@ "type": "tidelift" } ], - "time": "2023-12-26T14:02:43+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/string", - "version": "v7.0.2", + "version": "v7.0.7", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "cc78f14f91f5e53b42044d0620961c48028ff9f5" + "reference": "e405b5424dc2528e02e31ba26b83a79fd4eb8f63" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/cc78f14f91f5e53b42044d0620961c48028ff9f5", - "reference": "cc78f14f91f5e53b42044d0620961c48028ff9f5", + "url": "https://api.github.com/repos/symfony/string/zipball/e405b5424dc2528e02e31ba26b83a79fd4eb8f63", + "reference": "e405b5424dc2528e02e31ba26b83a79fd4eb8f63", "shasum": "" }, "require": { @@ -4298,7 +4430,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.0.2" + "source": "https://github.com/symfony/string/tree/v7.0.7" }, "funding": [ { @@ -4314,26 +4446,28 @@ "type": "tidelift" } ], - "time": "2023-12-10T16:54:46+00:00" + "time": "2024-04-18T09:29:19+00:00" }, { "name": "symfony/var-exporter", - "version": "v7.0.2", + "version": "v7.0.7", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "345c62fefe92243c3a06fc0cc65f2ec1a47e0764" + "reference": "cdecc0022e40e90340ba1a59a3d5ccf069777078" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/345c62fefe92243c3a06fc0cc65f2ec1a47e0764", - "reference": "345c62fefe92243c3a06fc0cc65f2ec1a47e0764", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/cdecc0022e40e90340ba1a59a3d5ccf069777078", + "reference": "cdecc0022e40e90340ba1a59a3d5ccf069777078", "shasum": "" }, "require": { "php": ">=8.2" }, "require-dev": { + "symfony/property-access": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0", "symfony/var-dumper": "^6.4|^7.0" }, "type": "library", @@ -4372,7 +4506,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v7.0.2" + "source": "https://github.com/symfony/var-exporter/tree/v7.0.7" }, "funding": [ { @@ -4388,20 +4522,20 @@ "type": "tidelift" } ], - "time": "2023-12-27T08:42:13+00:00" + "time": "2024-04-18T09:29:19+00:00" }, { "name": "theseer/tokenizer", - "version": "1.2.2", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96" + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96", - "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", "shasum": "" }, "require": { @@ -4430,7 +4564,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.2" + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" }, "funding": [ { @@ -4438,7 +4572,7 @@ "type": "github" } ], - "time": "2023-11-20T00:12:19+00:00" + "time": "2024-03-03T12:36:25+00:00" }, { "name": "vimeo/psalm", @@ -4606,6 +4740,55 @@ }, "time": "2022-06-03T18:03:27+00:00" }, + { + "name": "webmozart/glob", + "version": "4.7.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/glob.git", + "reference": "8a2842112d6916e61e0e15e316465b611f3abc17" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/glob/zipball/8a2842112d6916e61e0e15e316465b611f3abc17", + "reference": "8a2842112d6916e61e0e15e316465b611f3abc17", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5", + "symfony/filesystem": "^5.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Glob\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "A PHP implementation of Ant's glob.", + "support": { + "issues": "https://github.com/webmozarts/glob/issues", + "source": "https://github.com/webmozarts/glob/tree/4.7.0" + }, + "time": "2024-03-07T20:33:40+00:00" + }, { "name": "webmozart/path-util", "version": "2.3.0",