From 92840e21bf23dbdf257bf59f72e14cbbdf6e006d Mon Sep 17 00:00:00 2001 From: Dmitrii Derepko Date: Sat, 13 Apr 2024 20:21:04 +0700 Subject: [PATCH 1/8] Fix lazy loading --- config/di.php | 8 +++++-- config/routes.php | 4 ++++ src/Controller/DefaultController.php | 27 ++++++++++++----------- src/GeneratorProxy.php | 32 ++++++++++++++++++++++++++++ src/Gii.php | 18 +++++----------- src/Request/GeneratorRequest.php | 2 +- 6 files changed, 63 insertions(+), 28 deletions(-) create mode 100644 src/GeneratorProxy.php diff --git a/config/di.php b/config/di.php index fe6fc121..83350623 100644 --- a/config/di.php +++ b/config/di.php @@ -4,6 +4,7 @@ use Yiisoft\Injector\Injector; use Yiisoft\Yii\Gii\GeneratorInterface; +use Yiisoft\Yii\Gii\GeneratorProxy; use Yiisoft\Yii\Gii\Gii; use Yiisoft\Yii\Gii\GiiInterface; use Yiisoft\Yii\Gii\ParametersProvider; @@ -22,8 +23,11 @@ /** * @var $loader Closure(): GeneratorInterface */ - $loader = fn() => $injector->make($class, $generator['parameters'] ?? []); - $generatorsInstances[$class] = $loader; + $loader = new GeneratorProxy( + fn() => $injector->make($class, $generator['parameters'] ?? []), + $class, + ); + $generatorsInstances[$class::getId()] = $loader; } return new Gii($generatorsInstances); }, diff --git a/config/routes.php b/config/routes.php index b457c242..2f5b8dd9 100644 --- a/config/routes.php +++ b/config/routes.php @@ -10,6 +10,7 @@ use Psr\Http\Message\ResponseFactoryInterface; use Yiisoft\Csrf\CsrfMiddleware; use Yiisoft\DataResponse\Middleware\FormatDataResponseAsJson; +use Yiisoft\RequestProvider\RequestCatcherMiddleware; use Yiisoft\Router\Group; use Yiisoft\Router\Route; use Yiisoft\Validator\ValidatorInterface; @@ -47,14 +48,17 @@ static function (ResponseFactoryInterface $responseFactory, ValidatorInterface $ ->name('generator'), Route::post('/{generator}/preview') ->middleware(BodyParamsMiddleware::class) + ->middleware(RequestCatcherMiddleware::class) ->action([DefaultController::class, 'preview']) ->name('preview'), Route::post('/{generator}/generate') ->middleware(BodyParamsMiddleware::class) + ->middleware(RequestCatcherMiddleware::class) ->action([DefaultController::class, 'generate']) ->name('generate'), Route::post('/{generator}/diff') ->middleware(BodyParamsMiddleware::class) + ->middleware(RequestCatcherMiddleware::class) ->action([DefaultController::class, 'diff']) ->name('diff') ) diff --git a/src/Controller/DefaultController.php b/src/Controller/DefaultController.php index 24ff60d0..2c32a3d9 100644 --- a/src/Controller/DefaultController.php +++ b/src/Controller/DefaultController.php @@ -19,7 +19,7 @@ use Yiisoft\Yii\Gii\Exception\InvalidGeneratorCommandException; use Yiisoft\Yii\Gii\Generator\CommandHydrator; use Yiisoft\Yii\Gii\GeneratorCommandInterface; -use Yiisoft\Yii\Gii\GeneratorInterface; +use Yiisoft\Yii\Gii\GeneratorProxy; use Yiisoft\Yii\Gii\GiiInterface; use Yiisoft\Yii\Gii\ParametersProvider; use Yiisoft\Yii\Gii\Request\GeneratorRequest; @@ -37,7 +37,10 @@ public function list(GiiInterface $gii): ResponseInterface $generators = $gii->getGenerators(); return $this->responseFactory->createResponse([ - 'generators' => array_map($this->serializeGenerator(...), array_values($generators)), + 'generators' => array_map( + $this->serializeGenerator(...), + array_values(array_map(fn(GeneratorProxy $proxy) => $proxy->getClass(), $generators)), + ), ]); } @@ -46,7 +49,7 @@ public function get(GeneratorRequest $request): ResponseInterface $generator = $request->getGenerator(); return $this->responseFactory->createResponse( - $this->serializeGenerator($generator) + $this->serializeGenerator($generator::class) ); } @@ -150,12 +153,12 @@ private function serializeCodeFile(CodeFile $file): array ]; } - private function serializeGenerator(GeneratorInterface $generator): array + /** + * @psalm-param class-string $generatorClass + */ + private function serializeGenerator(string $generatorClass): array { - /** - * @psalm-var class-string $commandClass - */ - $commandClass = $generator::getCommandClass(); + $commandClass = $generatorClass::getCommandClass(); $dataset = new AttributesRulesProvider($commandClass); $rules = $dataset->getRules(); @@ -182,12 +185,12 @@ private function serializeGenerator(GeneratorInterface $generator): array } return [ - 'id' => $generator::getId(), - 'name' => $generator::getName(), - 'description' => $generator::getDescription(), + 'id' => $generatorClass::getId(), + 'name' => $generatorClass::getName(), + 'description' => $generatorClass::getDescription(), 'commandClass' => $commandClass, 'attributes' => $attributesResult, - 'templates' => $this->parametersProvider->getTemplates($generator::getId()), + 'templates' => $this->parametersProvider->getTemplates($generatorClass::getId()), ]; } diff --git a/src/GeneratorProxy.php b/src/GeneratorProxy.php new file mode 100644 index 00000000..e90fab7a --- /dev/null +++ b/src/GeneratorProxy.php @@ -0,0 +1,32 @@ + $class + */ + public function __construct(private Closure $loader, private string $class) + { + } + + /** + * @return class-string + */ + public function getClass(): string + { + return $this->class; + } + + public function loadGenerator(): GeneratorInterface + { + return $this->generator ??= ($this->loader)(); + } +} diff --git a/src/Gii.php b/src/Gii.php index 002b8a98..39a65ba8 100644 --- a/src/Gii.php +++ b/src/Gii.php @@ -4,7 +4,6 @@ namespace Yiisoft\Yii\Gii; -use Closure; use Yiisoft\Yii\Gii\Exception\GeneratorNotFoundException; /** @@ -13,31 +12,24 @@ final class Gii implements GiiInterface { /** - * @param array $generators + * @param array $proxies */ - public function __construct(private array $generators) + public function __construct(private array $proxies) { } public function addGenerator(GeneratorInterface $generator): void { - $this->generators[$generator::getId()] = $generator; + $this->proxies[$generator::getId()] = new GeneratorProxy(fn () => $generator, $generator::class); } public function getGenerator(string $id): GeneratorInterface { - if (!isset($this->generators[$id])) { - throw new GeneratorNotFoundException('Generator "' . $id . '" not found'); - } - - return $this->generators[$id] instanceof Closure ? $this->generators[$id]() : $this->generators[$id]; + return $this->proxies[$id]?->loadGenerator() ?? throw new GeneratorNotFoundException('Generator "' . $id . '" not found'); } public function getGenerators(): array { - return array_map( - fn (Closure|GeneratorInterface $generator) => $generator instanceof Closure ? $generator() : $generator, - $this->generators - ); + return $this->proxies; } } diff --git a/src/Request/GeneratorRequest.php b/src/Request/GeneratorRequest.php index e63568a0..e6adeff2 100644 --- a/src/Request/GeneratorRequest.php +++ b/src/Request/GeneratorRequest.php @@ -4,9 +4,9 @@ namespace Yiisoft\Yii\Gii\Request; -use Yiisoft\Hydrator\Temp\RouteArgument; use Yiisoft\Input\Http\Attribute\Parameter\Body; use Yiisoft\Input\Http\RequestInputInterface; +use Yiisoft\Router\HydratorAttribute\RouteArgument; use Yiisoft\Yii\Gii\GeneratorInterface; use Yiisoft\Yii\Gii\GiiInterface; From 0f91903ac5f6a2e47f32f0a3a9af09c5aac78fdc Mon Sep 17 00:00:00 2001 From: xepozz Date: Sat, 13 Apr 2024 13:22:22 +0000 Subject: [PATCH 2/8] Apply Rector changes (CI) --- src/GeneratorProxy.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GeneratorProxy.php b/src/GeneratorProxy.php index e90fab7a..fc4b09cc 100644 --- a/src/GeneratorProxy.php +++ b/src/GeneratorProxy.php @@ -13,7 +13,7 @@ class GeneratorProxy /** * @psalm-param class-string $class */ - public function __construct(private Closure $loader, private string $class) + public function __construct(private readonly Closure $loader, private readonly string $class) { } From e2b0e8e1308ddbcf9cb91839faba8fa77fcb744f Mon Sep 17 00:00:00 2001 From: Dmitrii Derepko Date: Wed, 29 May 2024 02:32:13 +0300 Subject: [PATCH 3/8] Fix deps --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index d2d14aa4..b4d540f5 100644 --- a/composer.json +++ b/composer.json @@ -55,8 +55,9 @@ "roave/infection-static-analysis-plugin": "^1.23", "spatie/phpunit-watcher": "^1.23", "vimeo/psalm": "^5.13", - "yiisoft/active-record": "^3.0@dev", + "yiisoft/active-record": "^dev-master", "yiisoft/cache": "^3.0", + "yiisoft/db": "1.2 as dev-master", "yiisoft/db-sqlite": "^1.0", "yiisoft/di": "^1.1", "yiisoft/dummy-provider": "^1.0", From e1541063e444cefd6ad1b1c7a4885199233fb171 Mon Sep 17 00:00:00 2001 From: Dmitrii Derepko Date: Wed, 29 May 2024 02:33:00 +0300 Subject: [PATCH 4/8] Fix deps --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index b4d540f5..f259e9ad 100644 --- a/composer.json +++ b/composer.json @@ -55,7 +55,7 @@ "roave/infection-static-analysis-plugin": "^1.23", "spatie/phpunit-watcher": "^1.23", "vimeo/psalm": "^5.13", - "yiisoft/active-record": "^dev-master", + "yiisoft/active-record": "dev-master", "yiisoft/cache": "^3.0", "yiisoft/db": "1.2 as dev-master", "yiisoft/db-sqlite": "^1.0", From fccb92a686c09504daf661a269039137adb5deea Mon Sep 17 00:00:00 2001 From: Dmitrii Derepko Date: Wed, 29 May 2024 02:37:32 +0300 Subject: [PATCH 5/8] Fix tests --- composer.json | 3 ++- phpunit.xml.dist | 1 + src/Gii.php | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index f259e9ad..5473736d 100644 --- a/composer.json +++ b/composer.json @@ -99,7 +99,8 @@ "sort-packages": true, "allow-plugins": { "infection/extension-installer": true, - "composer/package-versions-deprecated": true + "composer/package-versions-deprecated": true, + "php-http/discovery": false } }, "scripts": { diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 4ce94439..691f57cb 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -6,6 +6,7 @@ colors="true" failOnRisky="true" failOnWarning="true" + displayDetailsOnTestsThatTriggerWarnings="true" stopOnFailure="false" executionOrder="random" resolveDependencies="true" diff --git a/src/Gii.php b/src/Gii.php index 39a65ba8..7fcdfa1c 100644 --- a/src/Gii.php +++ b/src/Gii.php @@ -25,7 +25,9 @@ public function addGenerator(GeneratorInterface $generator): void public function getGenerator(string $id): GeneratorInterface { - return $this->proxies[$id]?->loadGenerator() ?? throw new GeneratorNotFoundException('Generator "' . $id . '" not found'); + return isset($this->proxies[$id]) + ? $this->proxies[$id]->loadGenerator() + : throw new GeneratorNotFoundException('Generator "' . $id . '" not found'); } public function getGenerators(): array From c8c18401a2409a3e24686925377afd4367f02382 Mon Sep 17 00:00:00 2001 From: Dmitrii Derepko Date: Wed, 29 May 2024 03:01:03 +0300 Subject: [PATCH 6/8] Fix tests --- config/di.php | 6 +++--- src/Controller/DefaultController.php | 10 +++++++++- src/GeneratorProxy.php | 6 +++--- src/Gii.php | 19 +++++++++++++------ src/GiiInterface.php | 6 +----- src/Validator/TemplateRuleHandler.php | 6 +++++- tests/TestCase.php | 18 ++++++++++-------- 7 files changed, 44 insertions(+), 27 deletions(-) diff --git a/config/di.php b/config/di.php index 83350623..09054a1a 100644 --- a/config/di.php +++ b/config/di.php @@ -15,7 +15,7 @@ return [ GiiInterface::class => function (Injector $injector) use ($params): GiiInterface { - $generatorsInstances = []; + $proxies = []; $generators = $params['yiisoft/yii-gii']['generators']; foreach ($generators as $generator) { @@ -27,9 +27,9 @@ fn() => $injector->make($class, $generator['parameters'] ?? []), $class, ); - $generatorsInstances[$class::getId()] = $loader; + $proxies[$class::getId()] = $loader; } - return new Gii($generatorsInstances); + return new Gii($proxies, []); }, ParametersProvider::class => [ 'class' => ParametersProvider::class, diff --git a/src/Controller/DefaultController.php b/src/Controller/DefaultController.php index 2c32a3d9..cce96e35 100644 --- a/src/Controller/DefaultController.php +++ b/src/Controller/DefaultController.php @@ -19,6 +19,7 @@ use Yiisoft\Yii\Gii\Exception\InvalidGeneratorCommandException; use Yiisoft\Yii\Gii\Generator\CommandHydrator; use Yiisoft\Yii\Gii\GeneratorCommandInterface; +use Yiisoft\Yii\Gii\GeneratorInterface; use Yiisoft\Yii\Gii\GeneratorProxy; use Yiisoft\Yii\Gii\GiiInterface; use Yiisoft\Yii\Gii\ParametersProvider; @@ -39,7 +40,14 @@ public function list(GiiInterface $gii): ResponseInterface return $this->responseFactory->createResponse([ 'generators' => array_map( $this->serializeGenerator(...), - array_values(array_map(fn(GeneratorProxy $proxy) => $proxy->getClass(), $generators)), + array_values( + array_map( + fn (GeneratorInterface|GeneratorProxy $generator) => $generator instanceof GeneratorProxy + ? $generator->getClass() + : $generator::class, + $generators + ) + ), ), ]); } diff --git a/src/GeneratorProxy.php b/src/GeneratorProxy.php index fc4b09cc..2ceec9ab 100644 --- a/src/GeneratorProxy.php +++ b/src/GeneratorProxy.php @@ -6,19 +6,19 @@ use Closure; -class GeneratorProxy +final class GeneratorProxy { private ?GeneratorInterface $generator = null; /** - * @psalm-param class-string $class + * @psalm-param class-string $class */ public function __construct(private readonly Closure $loader, private readonly string $class) { } /** - * @return class-string + * @return class-string */ public function getClass(): string { diff --git a/src/Gii.php b/src/Gii.php index 7fcdfa1c..c5f197a2 100644 --- a/src/Gii.php +++ b/src/Gii.php @@ -6,25 +6,29 @@ use Yiisoft\Yii\Gii\Exception\GeneratorNotFoundException; -/** - * @psalm-import-type LazyGenerator from GiiInterface - */ final class Gii implements GiiInterface { /** * @param array $proxies + * @param array $instances */ - public function __construct(private array $proxies) + public function __construct( + private readonly array $proxies, + private array $instances, + ) { } public function addGenerator(GeneratorInterface $generator): void { - $this->proxies[$generator::getId()] = new GeneratorProxy(fn () => $generator, $generator::class); + $this->instances[$generator::getId()] = $generator; } public function getGenerator(string $id): GeneratorInterface { + if (isset($this->instances[$id])) { + return $this->instances[$id]; + } return isset($this->proxies[$id]) ? $this->proxies[$id]->loadGenerator() : throw new GeneratorNotFoundException('Generator "' . $id . '" not found'); @@ -32,6 +36,9 @@ public function getGenerator(string $id): GeneratorInterface public function getGenerators(): array { - return $this->proxies; + return [ + ...$this->instances, + ...$this->proxies, + ]; } } diff --git a/src/GiiInterface.php b/src/GiiInterface.php index 614435d3..76d6fa4e 100644 --- a/src/GiiInterface.php +++ b/src/GiiInterface.php @@ -4,12 +4,8 @@ namespace Yiisoft\Yii\Gii; -use Closure; use Yiisoft\Yii\Gii\Exception\GeneratorNotFoundException; -/** - * @psalm-type LazyGenerator = Closure(): GeneratorInterface - */ interface GiiInterface { /** @@ -23,7 +19,7 @@ public function addGenerator(GeneratorInterface $generator): void; public function getGenerator(string $id): GeneratorInterface; /** - * @return GeneratorInterface[] + * @return GeneratorInterface[]|GeneratorProxy[] */ public function getGenerators(): array; } diff --git a/src/Validator/TemplateRuleHandler.php b/src/Validator/TemplateRuleHandler.php index b779f6ea..ab5ad734 100644 --- a/src/Validator/TemplateRuleHandler.php +++ b/src/Validator/TemplateRuleHandler.php @@ -12,6 +12,7 @@ use Yiisoft\Validator\ValidationContext; use Yiisoft\Yii\Gii\GeneratorCommandInterface; use Yiisoft\Yii\Gii\GeneratorInterface; +use Yiisoft\Yii\Gii\GeneratorProxy; use Yiisoft\Yii\Gii\GiiInterface; use Yiisoft\Yii\Gii\ParametersProvider; @@ -79,9 +80,12 @@ public function validate(mixed $value, object $rule, ValidationContext $context) private function getGenerator(GeneratorCommandInterface $dataSet): GeneratorInterface { foreach ($this->gii->getGenerators() as $generator) { - if ($generator::getCommandClass() === $dataSet::class) { + if ($generator instanceof GeneratorInterface && $generator::getCommandClass() === $dataSet::class) { return $generator; } + if ($generator instanceof GeneratorProxy && $generator->getClass()::getCommandClass() === $dataSet::class) { + return $generator->loadGenerator(); + } } throw new RuntimeException(sprintf('Unknown generator "%s".', $dataSet::class)); } diff --git a/tests/TestCase.php b/tests/TestCase.php index 9dfc3aa5..35019d00 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -28,6 +28,7 @@ use Yiisoft\Validator\Validator; use Yiisoft\Validator\ValidatorInterface; use Yiisoft\Yii\Gii\Generator as Generators; +use Yiisoft\Yii\Gii\GeneratorProxy; use Yiisoft\Yii\Gii\Gii; use Yiisoft\Yii\Gii\GiiInterface; @@ -54,15 +55,16 @@ protected function getContainer(array $definitions = []): ContainerInterface $config = ContainerConfig::create() ->withDefinitions([ GiiInterface::class => function (ContainerInterface $container) { - $generators = [ - Generators\Controller\Generator::getId() => Generators\Controller\Generator::class, - Generators\ActiveRecord\Generator::getId() => Generators\ActiveRecord\Generator::class, + $proxies = [ + Generators\Controller\Generator::getId() => new GeneratorProxy( + fn() => $container->get(Generators\Controller\Generator::class), + Generators\Controller\Generator::class, + ), ]; - $generatorsInstances = []; - foreach ($generators as $class) { - $generatorsInstances[] = $container->get($class); - } - return new Gii($generatorsInstances); + $instances = [ + Generators\ActiveRecord\Generator::getId() => $container->get(Generators\ActiveRecord\Generator::class), + ]; + return new Gii($proxies, $instances); }, Aliases::class => new Aliases( [ From b3e33592413fd2a9f7e9aed25bd549719bd0665c Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Wed, 29 May 2024 00:01:48 +0000 Subject: [PATCH 7/8] Apply fixes from StyleCI --- src/Gii.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Gii.php b/src/Gii.php index c5f197a2..1ebee47b 100644 --- a/src/Gii.php +++ b/src/Gii.php @@ -15,8 +15,7 @@ final class Gii implements GiiInterface public function __construct( private readonly array $proxies, private array $instances, - ) - { + ) { } public function addGenerator(GeneratorInterface $generator): void From 346cee61dd6bc342c1bcd14d892c211132ce228a Mon Sep 17 00:00:00 2001 From: xepozz Date: Wed, 29 May 2024 00:02:10 +0000 Subject: [PATCH 8/8] Apply Rector changes (CI) --- src/Gii.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Gii.php b/src/Gii.php index 1ebee47b..755feec1 100644 --- a/src/Gii.php +++ b/src/Gii.php @@ -25,12 +25,9 @@ public function addGenerator(GeneratorInterface $generator): void public function getGenerator(string $id): GeneratorInterface { - if (isset($this->instances[$id])) { - return $this->instances[$id]; - } - return isset($this->proxies[$id]) + return $this->instances[$id] ?? (isset($this->proxies[$id]) ? $this->proxies[$id]->loadGenerator() - : throw new GeneratorNotFoundException('Generator "' . $id . '" not found'); + : throw new GeneratorNotFoundException('Generator "' . $id . '" not found')); } public function getGenerators(): array