From 1e78f6465ccbe94fefbf6d18ccdcdb4acadf4a7a Mon Sep 17 00:00:00 2001 From: david Date: Tue, 26 Mar 2024 13:58:48 +0100 Subject: [PATCH 01/15] #11 use nelmio/alice for data-faking --- composer.json | 3 +- docs/ComponentConfiguration.md | 67 ++++++ src/Component/ComponentItemFactory.php | 67 +++--- src/Component/Data/Faker.php | 203 ++++++++++++++++++ src/Component/Data/FixtureData.php | 19 ++ .../component/_invalid_component.html.twig | 2 +- .../Functional/Cache/ComponentsWarmerTest.php | 2 + .../Controller/TwigDocControllerTest.php | 2 + .../Service/ComponentItemFactoryTest.php | 47 ++++ .../Service/ComponentServiceTest.php | 2 + .../Functional/Twig/TwigDocExtensionTest.php | 2 + tests/TestApp/Entity/Car.php | 44 ++++ tests/TestApp/Entity/Manufacturer.php | 20 ++ .../Component/ComponentItemFactoryTest.php | 2 + tests/Unit/Component/Data/FakerTest.php | 98 +++++++++ 15 files changed, 548 insertions(+), 32 deletions(-) create mode 100644 src/Component/Data/Faker.php create mode 100644 src/Component/Data/FixtureData.php create mode 100644 tests/TestApp/Entity/Car.php create mode 100644 tests/TestApp/Entity/Manufacturer.php create mode 100644 tests/Unit/Component/Data/FakerTest.php diff --git a/composer.json b/composer.json index ca8b1bb..e51d88b 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,8 @@ "symfony/framework-bundle": "^6.4|^7.0", "symfony/validator": "^6.4|^7.0", "symfony/twig-bundle": "^6.4|^7.0", - "symfony/yaml": "^6.4|^7.0" + "symfony/yaml": "^6.4|^7.0", + "nelmio/alice": "^3.13" }, "require-dev": { "phpunit/phpunit": "^10.5", diff --git a/docs/ComponentConfiguration.md b/docs/ComponentConfiguration.md index 6b6b2cd..14ff761 100644 --- a/docs/ComponentConfiguration.md +++ b/docs/ComponentConfiguration.md @@ -1,5 +1,9 @@ ### Component Configuration +1. [In Template](#in-template) +2. [In Configuration File](#config-file) +3. [Template Parameters](#parameter-provision) + You have two possibilities to let the bundle know of your components: 1. Directly in the template of the component itself (you should stick to this) @@ -77,3 +81,66 @@ components: - name: Button path: '%twig.default_path%/snippets/FancyButton.html.twig' ``` + +### Parameter Provision + +You must provide the types of your template parameters in the configuration. +As twig templates are not aware of types, there is no other possibility at the moment. +As this bundle makes use of [Nelmio/Alice](https://github.com/nelmio/alice) and [FakerPhp](https://fakerphp.github.io), all you need to do is +define the types of your parameters in the component configuration. +The bundle will take care of creating a set of parameters for every component. + +E.g. when your template optionally requires a User object, you can say the template needs a parameter named user that is of type App\Entity\User: +```twig +{#TWIG_DOC + title: Fancy Button + description: This is a really fancy button + category: Buttons + tags: + - button + parameters: + type: String + text: String + user: App\Entity\User +#TWIG_DOC} + +{% if user %} + Hello {{ user.name }} +{% endif %} + +``` + +As we do not provide an explicit variation, the bundle creates a default variation for this component. +This default variation will contain a fixture for the user object, as well as random values for other parameters. +If the property "name" of the user object is writable, the bundle will also create a random text-value for the name. + +So, what to do if you want an example of both possibilities (user as object and as NULL)? Answer: provide variations for both cases: +```twig +{#TWIG_DOC + title: Fancy Button + description: This is a really fancy button + category: Buttons + tags: + - button + parameters: + user: App\Entity\User + type: String + text: String + variations: + logged-in: + user: + name: superadmin + type: primary + anonymous: + user: null + text: Button Text +#TWIG_DOC} + +{% if user %} + Hello {{ user.name }} +{% endif %} + +``` + +For all parameters that are missing from the variations configuration, the bundle will create random-values with FakerPHP. +It is possible to mix explicitly defined parameter-values and randomly created ones. diff --git a/src/Component/ComponentItemFactory.php b/src/Component/ComponentItemFactory.php index 146338c..cf8f64b 100644 --- a/src/Component/ComponentItemFactory.php +++ b/src/Component/ComponentItemFactory.php @@ -4,6 +4,7 @@ namespace Qossmic\TwigDocBundle\Component; +use Qossmic\TwigDocBundle\Component\Data\Faker; use Qossmic\TwigDocBundle\Exception\InvalidComponentConfigurationException; use Qossmic\TwigDocBundle\Service\CategoryService; use Symfony\Component\Validator\ConstraintViolationList; @@ -11,10 +12,16 @@ class ComponentItemFactory { + private Faker $faker; + public function __construct(private readonly ValidatorInterface $validator, private readonly CategoryService $categoryService) { + $this->faker = new Faker(); } + /** + * @throws InvalidComponentConfigurationException + */ public function create(array $data): ComponentItem { $item = $this->createItem($data); @@ -45,6 +52,9 @@ public function create(array $data): ComponentItem return $item; } + /** + * @throws InvalidComponentConfigurationException + */ private function createItem(array $data): ComponentItem { $item = new ComponentItem(); @@ -53,9 +63,9 @@ private function createItem(array $data): ComponentItem ->setDescription($data['description'] ?? '') ->setTags($data['tags'] ?? []) ->setParameters($data['parameters'] ?? []) - ->setVariations($data['variations'] ?? [ - 'default' => $this->createVariationParameters($data['parameters'] ?? []), - ]) + ->setVariations( + $this->parseVariations($data['variations'] ?? [], $data['parameters'] ?? []) + ) ->setProjectPath($data['path'] ?? '') ->setRenderPath($data['renderPath'] ?? ''); @@ -82,37 +92,34 @@ public function getParamsFromVariables(array $variables): array return $r; } - public function createVariationParameters(array $parameters): array + /** + * @throws InvalidComponentConfigurationException + */ + private function parseVariations(?array $variations, ?array $parameters): array { - $params = []; - foreach ($parameters as $name => $type) { - if (\is_array($type)) { - $paramValue = $this->createVariationParameters($type); - } else { - $paramValue = $this->createParamValue($type); - } - $params[$name] = $paramValue; + if (!$parameters) { + return ['default' => []]; } - return $params; - } + if (!$variations) { + return [ + 'default' => $this->faker->getFakeData($parameters) + ]; + } - private function createParamValue(string $type): bool|int|float|string|null - { - switch (strtolower($type)) { - default: - return null; - case 'string': - return 'Hello World'; - case 'int': - case 'integer': - return random_int(0, 100000); - case 'bool': - case 'boolean': - return [true, false][rand(0, 1)]; - case 'float': - case 'double': - return (float) rand(1, 1000) / 100; + $result = []; + + foreach ($variations as $variationName => $variationParams) { + if (!is_array($variationParams)) { + throw new InvalidComponentConfigurationException( + ConstraintViolationList::createFromMessage( + sprintf('A component variation must contain an array of parameters. Variation Name: %s', $variationName) + ) + ); + } + $result[$variationName] = $this->faker->getFakeData($parameters, $variationParams); } + + return $result; } } diff --git a/src/Component/Data/Faker.php b/src/Component/Data/Faker.php new file mode 100644 index 0000000..e0c273f --- /dev/null +++ b/src/Component/Data/Faker.php @@ -0,0 +1,203 @@ +loader = new NativeLoader(); + $reflectionExtractor = new ReflectionExtractor(); + $this->extractor = new PropertyInfoExtractor( + listExtractors: [$reflectionExtractor], + typeExtractors: [$reflectionExtractor], + accessExtractors: [$reflectionExtractor] + ); + $this->generator = Factory::create(); + } + + public function getFakeData(array $params, array $variation = []): array + { + return $this->build($params, $variation); + } + + private function collectClasses(array $params, array $variation = []): ?array + { + $classes = []; + foreach ($params as $name => $type) { + if (is_array($type)) { + $classes[$name] = $this->collectClasses($type, $variation[$name] ?? []); + } elseif (class_exists($type)) { + $propertyInfo = $this->getPropertyInfo($type); + $classes[$name] = new FixtureData( + $type, + $propertyInfo, + $variation[$name] ?? [] + ); + } + } + + return $classes; + } + + /** + * @param array $props + */ + private function getFixtureParams(string $className, array $props = [], array $params = []): array + { + foreach ($props as $prop => $type) { + if (!array_key_exists($prop, $params) && $this->extractor->isWritable($className, $prop)) { + $params[$prop] = $this->createParamValue($type->getBuiltinType()); + } + } + + return $params; + } + + private function getPropertyInfo(string $class): array + { + $properties = []; + + $props = $this->extractor->getProperties($class); + + foreach ($props as $propName) { + $types = $this->extractor->getTypes($class, $propName); + + // consider only the first type (PropertyInfo docs are wrong about only phpDocExtractor returning more than one type) + $type = $types[0] ?? null; + + if (!$type) { + // ignore untyped properties at the moment + continue; + } + $properties[$propName] = $type; + } + + return $properties; + } + + private function build(array $params, array $variation = []): array + { + $fixturesToBuild = $this->collectClasses($params, $variation); + $scalarParams = $this->createVariationParameters($this->arrayDiffKeyRecursive($params, $fixturesToBuild), $variation); + + $fixtures = $this->buildFixtures($fixturesToBuild); + + return array_merge_recursive($scalarParams, $fixtures); + } + + private function buildFixtures(array $fixtures): array + { + $result = []; + + foreach ($fixtures as $name => $data) { + if ($data instanceof FixtureData) { + $result[$name] = $this->getFixture($name, $data); + } else { + $result[$name] = $this->buildFixtures($data); + } + } + + return $result; + } + + private function getFixture(string $fixtureSetName, FixtureData $data): object + { + $otherFixtures = []; + $fixtureParams = $data->params; + + foreach ($data->properties as $prop => $type) { + if ($type->getBuiltinType() === Type::BUILTIN_TYPE_OBJECT) { + $otherFixtures[$type->getClassName()] = [ + $prop => array_merge( + $data->params[$prop] + ?? $this->getFixtureParams($type->getClassName(), $this->getPropertyInfo($type->getClassName())), + ['__construct' => false, ] + ) + ] ; + $fixtureParams[$prop] = sprintf('@%s', $prop); + } + } + + $fixtureData = array_merge($otherFixtures, [ + $data->className => [ + $fixtureSetName => array_merge($this->getFixtureParams($data->className, $data->properties, $fixtureParams), [ + // disable constructor until we have time to fake constructor arguments :-) + '__construct' => false, + ]), + ] + ]); + + return $this->loader->loadData($fixtureData)->getObjects()[$fixtureSetName]; + } + + public function createVariationParameters(array $parameters, array $variation): array + { + $params = []; + foreach ($parameters as $name => $type) { + if (\is_array($type)) { + $paramValue = $this->createVariationParameters($type, $variation[$name] ?? []); + } elseif (array_key_exists($name, $variation)) { + $paramValue = $variation[$name]; + } else { + $paramValue = $this->createParamValue($type); + } + $params[$name] = $paramValue; + } + + return $params; + } + + private function createParamValue(string $type): bool|int|float|string|null + { + switch (strtolower($type)) { + default: + return null; + case 'string': + return $this->generator->text(20); + case 'int': + case 'integer': + return $this->generator->numberBetween(0, 100000); + case 'bool': + case 'boolean': + return [true, false][rand(0, 1)]; + case 'float': + case 'double': + return $this->generator->randomFloat(); + } + } + + private function arrayDiffKeyRecursive(array $arr1, array $arr2): array + { + $diff = array_diff_key($arr1, $arr2); + $intersect = array_intersect_key($arr1, $arr2); + + foreach ($intersect as $k => $v) { + if (is_array($arr1[$k]) && is_array($arr2[$k])) { + $d = $this->arrayDiffKeyRecursive($arr1[$k], $arr2[$k]); + + if ($d) { + $diff[$k] = $d; + } + } + } + + return $diff; + } +} diff --git a/src/Component/Data/FixtureData.php b/src/Component/Data/FixtureData.php new file mode 100644 index 0000000..f526176 --- /dev/null +++ b/src/Component/Data/FixtureData.php @@ -0,0 +1,19 @@ + $properties */ + public readonly array $properties, + public readonly array $params = [] + ) { + } +} diff --git a/templates/component/_invalid_component.html.twig b/templates/component/_invalid_component.html.twig index 68dc9b5..5337dc5 100644 --- a/templates/component/_invalid_component.html.twig +++ b/templates/component/_invalid_component.html.twig @@ -31,7 +31,7 @@ {% endif %} {% endfor %}

Variations:

- {% for key, value in variation %} + {% for key, value in component.originalConfig.variations ?? [] %} {% if loop.first %} {% endif %} {% endfor %}

Variations:

{% for key, value in component.originalConfig.variations ?? [] %} {% if loop.first %} + {% endif %} {% endfor %} diff --git a/templates/component/_parameter.html.twig b/templates/component/_parameter.html.twig index 074cc2c..a6f1a6f 100644 --- a/templates/component/_parameter.html.twig +++ b/templates/component/_parameter.html.twig @@ -1,7 +1,7 @@ {% if parameter is iterable %} {% else %} diff --git a/templates/component/_viewport.html.twig b/templates/component/_viewport.html.twig index e24cbd5..2c2b5a4 100644 --- a/templates/component/_viewport.html.twig +++ b/templates/component/_viewport.html.twig @@ -1,6 +1,7 @@
-
diff --git a/templates/pages/invalid_components.html.twig b/templates/pages/invalid_components.html.twig index f05bd7e..eb13d41 100644 --- a/templates/pages/invalid_components.html.twig +++ b/templates/pages/invalid_components.html.twig @@ -1,4 +1,4 @@ -{% extends'@TwigDoc/documentation.html.twig' %} +{% extends '@TwigDoc/documentation.html.twig' %} {% block body %}

Invalid Components

diff --git a/tests/Functional/Cache/ComponentsWarmerTest.php b/tests/Functional/Cache/ComponentsWarmerTest.php index bd0d25f..71a7a4d 100644 --- a/tests/Functional/Cache/ComponentsWarmerTest.php +++ b/tests/Functional/Cache/ComponentsWarmerTest.php @@ -1,5 +1,7 @@ createMock(ContainerInterface::class)); static::assertTrue($warmer->isOptional()); } diff --git a/tests/Functional/Controller/TwigDocControllerTest.php b/tests/Functional/Controller/TwigDocControllerTest.php index 1dafae9..b87fbfe 100644 --- a/tests/Functional/Controller/TwigDocControllerTest.php +++ b/tests/Functional/Controller/TwigDocControllerTest.php @@ -1,5 +1,7 @@ get(ComponentItemFactory::class); - self::expectException($expectedExceptionClass); + $this->expectException($expectedExceptionClass); $service->create($componentData); } diff --git a/tests/Functional/Service/ComponentServiceTest.php b/tests/Functional/Service/ComponentServiceTest.php index 86aa46b..9cf267a 100644 --- a/tests/Functional/Service/ComponentServiceTest.php +++ b/tests/Functional/Service/ComponentServiceTest.php @@ -1,5 +1,7 @@ get(ComponentService::class); diff --git a/tests/Functional/Twig/TwigDocExtensionTest.php b/tests/Functional/Twig/TwigDocExtensionTest.php index 10d045e..14b2ebb 100644 --- a/tests/Functional/Twig/TwigDocExtensionTest.php +++ b/tests/Functional/Twig/TwigDocExtensionTest.php @@ -1,5 +1,7 @@ getComponentCategoryMock($componentData['category'], $componentData['sub_category'] ?? null); - $categoryServiceMock = static::createMock(CategoryService::class); + $categoryServiceMock = $this->createMock(CategoryService::class); $categoryServiceMock ->method('getCategory') ->with($componentData['category']) ->willReturn($componentCategoryMock); - $validatorMock = static::createMock(ValidatorInterface::class); + $validatorMock = $this->createMock(ValidatorInterface::class); $validatorMock->method('validate') ->willReturn(new ConstraintViolationList()); @@ -47,13 +49,13 @@ public function testValidComponent(array $componentData): void public function testInvalidCategory() { - static::expectException(InvalidComponentConfigurationException::class); + $this->expectException(InvalidComponentConfigurationException::class); - $categoryServiceMock = static::createMock(CategoryService::class); + $categoryServiceMock = $this->createMock(CategoryService::class); $categoryServiceMock ->method('getCategory') ->willReturn(null); - $validatorMock = static::createMock(ValidatorInterface::class); + $validatorMock = $this->createMock(ValidatorInterface::class); $componentItemFactory = new ComponentItemFactory($validatorMock, $categoryServiceMock, static::createMock(Faker::class)); @@ -69,8 +71,8 @@ public function testGetParamsFromVariables(): void ]; $componentItemFactory = new ComponentItemFactory( - static::createMock(ValidatorInterface::class), - $this->createMockCategoryService::class), + $this->createMock(ValidatorInterface::class), + $this->createMock(CategoryService::class), $this->createMock(Faker::class) ); @@ -123,14 +125,17 @@ public static function getValidComponents(): iterable private function getComponentCategoryMock(string $category, ?string $subCategory = null): ComponentCategory { - $componentCategoryMock = static::createMock(ComponentCategory::class); + $componentCategoryMock = $this->createMock(ComponentCategory::class); $componentCategoryMock->method('getName') ->willReturn($subCategory ?? $category); + $parentMock = null; + if ($subCategory) { - $parentMock = static::createMock(ComponentCategory::class); + $parentMock = $this->createMock(ComponentCategory::class); $parentMock->method('getName')->willReturn($category); } + $componentCategoryMock->method('getParent') ->willReturn($parentMock); diff --git a/tests/Unit/Component/ComponentItemListTest.php b/tests/Unit/Component/ComponentItemListTest.php index dce80e4..88ccc28 100644 --- a/tests/Unit/Component/ComponentItemListTest.php +++ b/tests/Unit/Component/ComponentItemListTest.php @@ -1,5 +1,7 @@ expectException(\InvalidArgumentException::class); $list = new ComponentItemList([]); diff --git a/tests/Unit/Configuration/YamlParserTest.php b/tests/Unit/Configuration/YamlParserTest.php index 5a76102..6345914 100644 --- a/tests/Unit/Configuration/YamlParserTest.php +++ b/tests/Unit/Configuration/YamlParserTest.php @@ -1,5 +1,7 @@ expectException(ParseException::class); $yaml = " key: \nyaml ain't markup language"; $parser = new YamlParser(); - $parser->parse($yaml); } diff --git a/tests/Unit/DependencyInjection/Compiler/TwigDocCollectDocsPassTest.php b/tests/Unit/DependencyInjection/Compiler/TwigDocCollectDocsPassTest.php index 8bacbfc..7572243 100644 --- a/tests/Unit/DependencyInjection/Compiler/TwigDocCollectDocsPassTest.php +++ b/tests/Unit/DependencyInjection/Compiler/TwigDocCollectDocsPassTest.php @@ -1,5 +1,7 @@ process($container); static::assertTrue(true); @@ -40,7 +41,7 @@ public function testProcess(): void static::assertCount(2, $service->getArgument('$componentsConfig')); } - public function testProcessNotEnrichingPathsForMissingTemplate() + public function testProcessNotEnrichingPathsForMissingTemplate(): void { $container = $this->getContainer(componentsConfig: [ [ @@ -49,7 +50,6 @@ public function testProcessNotEnrichingPathsForMissingTemplate() ]); $pass = new TwigDocCollectDocsPass(new YamlParser()); - $pass->process($container); $definition = $container->getDefinition('twig_doc.service.component'); @@ -58,7 +58,7 @@ public function testProcessNotEnrichingPathsForMissingTemplate() static::assertEmpty($definition->getArgument('$componentsConfig')[0]['renderPath']); } - public function testProcessNotEnrichingPathsForAmbiguousTemplate() + public function testProcessNotEnrichingPathsForAmbiguousTemplate(): void { $container = $this->getContainer(componentsConfig: [ [ @@ -72,7 +72,6 @@ public function testProcessNotEnrichingPathsForAmbiguousTemplate() ]); $pass = new TwigDocCollectDocsPass(new YamlParser()); - $pass->process($container); $definition = $container->getDefinition('twig_doc.service.component'); @@ -83,10 +82,11 @@ public function testProcessNotEnrichingPathsForAmbiguousTemplate() static::assertEmpty($definition->getArgument('$componentsConfig')[1]['renderPath']); } - public function testProcessThrowsExceptionForInvalidConfiguration() + public function testProcessThrowsExceptionForInvalidConfiguration(): void { - static::expectException(InvalidConfigException::class); - static::expectExceptionMessage(sprintf('component "%s" is configured twice, please configure either directly in the template or the general bundle configuration', 'Button')); + $this->expectException(InvalidConfigException::class); + $this->expectExceptionMessage(sprintf('Component "%s" is configured twice, please configure either directly in the template or the general bundle configuration', 'Button')); + $container = $this->getContainer([ [ 'name' => 'Button', diff --git a/tests/Unit/DependencyInjection/ConfigurationTest.php b/tests/Unit/DependencyInjection/ConfigurationTest.php index c6d9776..fff3fd9 100644 --- a/tests/Unit/DependencyInjection/ConfigurationTest.php +++ b/tests/Unit/DependencyInjection/ConfigurationTest.php @@ -1,5 +1,7 @@ expectException(InvalidConfigException::class); new CategoryService($config); } - public function testGetCategories() + public function testGetCategories(): void { $service = new CategoryService([['name' => 'Category']]); @@ -56,7 +58,7 @@ public function testGetCategories() static::assertContainsOnlyInstancesOf(ComponentCategory::class, $categories); } - public function testGetCategoryReturnsNullForUnknownCategory() + public function testGetCategoryReturnsNullForUnknownCategory(): void { $service = new CategoryService([['name' => 'Category']]); From f83d7a5148e94081e2e0c897fc8386ca8f7749f2 Mon Sep 17 00:00:00 2001 From: david Date: Thu, 4 Apr 2024 09:24:19 +0200 Subject: [PATCH 12/15] merge update --- tests/Unit/Component/ComponentItemFactoryTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Unit/Component/ComponentItemFactoryTest.php b/tests/Unit/Component/ComponentItemFactoryTest.php index 6da3ab6..3116346 100644 --- a/tests/Unit/Component/ComponentItemFactoryTest.php +++ b/tests/Unit/Component/ComponentItemFactoryTest.php @@ -57,7 +57,7 @@ public function testInvalidCategory() ->willReturn(null); $validatorMock = $this->createMock(ValidatorInterface::class); - $componentItemFactory = new ComponentItemFactory($validatorMock, $categoryServiceMock, static::createMock(Faker::class)); + $componentItemFactory = new ComponentItemFactory($validatorMock, $categoryServiceMock, $this->createMock(Faker::class)); $componentItemFactory->create(['category' => 'Category']); } From 5c1aa72885ae77e25867831f86475367282e3cea Mon Sep 17 00:00:00 2001 From: david Date: Thu, 4 Apr 2024 09:13:08 +0200 Subject: [PATCH 13/15] add class usages --- tests/Functional/Cache/ComponentsWarmerTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/Functional/Cache/ComponentsWarmerTest.php b/tests/Functional/Cache/ComponentsWarmerTest.php index 71a7a4d..02450de 100644 --- a/tests/Functional/Cache/ComponentsWarmerTest.php +++ b/tests/Functional/Cache/ComponentsWarmerTest.php @@ -11,6 +11,9 @@ use Qossmic\TwigDocBundle\Component\ComponentItemFactory; use Qossmic\TwigDocBundle\Component\ComponentItemList; use Qossmic\TwigDocBundle\Component\Data\Faker; +use Qossmic\TwigDocBundle\Component\Data\Generator\FixtureGenerator; +use Qossmic\TwigDocBundle\Component\Data\Generator\NullGenerator; +use Qossmic\TwigDocBundle\Component\Data\Generator\ScalarGenerator; use Qossmic\TwigDocBundle\Service\CategoryService; use Qossmic\TwigDocBundle\Service\ComponentService; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; @@ -21,6 +24,9 @@ #[UsesClass(CategoryService::class)] #[UsesClass(ComponentItemList::class)] #[UsesClass(Faker::class)] +#[UsesClass(ScalarGenerator::class)] +#[UsesClass(FixtureGenerator::class)] +#[UsesClass(NullGenerator::class)] class ComponentsWarmerTest extends KernelTestCase { public function testWarmUp(): void From 4351e75d33558c887d906d62e6982927948e83c4 Mon Sep 17 00:00:00 2001 From: david Date: Thu, 4 Apr 2024 09:38:16 +0200 Subject: [PATCH 14/15] #11 code review changes - added cs-fixer rule for strict types --- .php-cs-fixer.dist.php | 1 + config/documentation.php | 11 +++++++++-- src/Component/ComponentItemList.php | 4 +--- src/Component/Data/Faker.php | 2 ++ src/Component/Data/FixtureData.php | 2 ++ src/Component/Data/Generator/FixtureGenerator.php | 2 ++ src/Component/Data/Generator/NullGenerator.php | 2 ++ src/Component/Data/Generator/ScalarGenerator.php | 4 +++- src/Component/Data/GeneratorInterface.php | 2 ++ src/Service/ComponentService.php | 4 +--- .../Component/Data/Generator/CustomGenerator.php | 2 ++ tests/TestApp/Entity/Car.php | 2 ++ tests/TestApp/Entity/Manufacturer.php | 2 ++ tests/TestApp/Entity/Special.php | 2 ++ tests/TestApp/config/packages/framework.php | 2 ++ tests/TestApp/config/packages/twig.php | 2 ++ tests/TestApp/config/packages/twig_doc.php | 2 ++ tests/TestApp/config/services.php | 4 +++- tests/Unit/Component/ComponentItemFactoryTest.php | 2 +- tests/Unit/Component/Data/FakerTest.php | 2 ++ .../Component/Data/Generator/FixtureGeneratorTest.php | 2 ++ .../Component/Data/Generator/NullGeneratorTest.php | 2 ++ .../Component/Data/Generator/ScalarGeneratorTest.php | 4 +++- tests/bootstrap.php | 2 ++ 24 files changed, 54 insertions(+), 12 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 912d733..353af29 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -10,6 +10,7 @@ ->setRules([ '@Symfony' => true, '@Symfony:risky' => true, + '@PHP80Migration:risky' => true, 'array_syntax' => ['syntax' => 'short'], 'yoda_style' => false, ]) diff --git a/config/documentation.php b/config/documentation.php index 2491412..b3edc9f 100644 --- a/config/documentation.php +++ b/config/documentation.php @@ -15,25 +15,30 @@ use Qossmic\TwigDocBundle\Service\ComponentService; use Qossmic\TwigDocBundle\Twig\TwigDocExtension; -return static function (ContainerConfigurator $container) { - $container->services()->set('twig_doc.controller.documentation', TwigDocController::class) +return static function (ContainerConfigurator $container): void { + $container->services() + ->set('twig_doc.controller.documentation', TwigDocController::class) ->public() ->arg('$twig', service('twig')) ->arg('$componentService', service('twig_doc.service.component')) ->arg('$profiler', service('profiler')->nullOnInvalid()) + ->set('twig_doc.service.category', CategoryService::class) ->alias(CategoryService::class, 'twig_doc.service.category') + ->set('twig_doc.service.component_factory', ComponentItemFactory::class) ->public() ->arg('$validator', service('validator')) ->arg('$categoryService', service('twig_doc.service.category')) ->arg('$faker', service('twig_doc.service.faker')) ->alias(ComponentItemFactory::class, 'twig_doc.service.component_factory') + ->set('twig_doc.service.component', ComponentService::class) ->public() ->arg('$itemFactory', service('twig_doc.service.component_factory')) ->arg('$cache', service('cache.app')) ->alias(ComponentService::class, 'twig_doc.service.component') + ->set('twig_doc.twig.extension', TwigDocExtension::class) ->public() ->arg('$componentRenderer', service('ux.twig_component.component_renderer')->nullOnInvalid()) @@ -42,6 +47,7 @@ ->arg('$twig', service('twig')) ->tag('twig.extension') ->alias(TwigDocExtension::class, 'twig_doc.twig.extension') + ->set('twig_doc.cache_warmer', ComponentsWarmer::class) ->arg('$container', service('service_container')) ->tag('kernel.cache_warmer') @@ -54,6 +60,7 @@ ->set('twig_doc.data_generator.scalar', ScalarGenerator::class) ->public() ->tag('twig_doc.data_generator', ['priority' => -5]) + ->set('twig_doc.data_generator.fixture', FixtureGenerator::class) ->public() ->tag('twig_doc.data_generator', ['priority' => -10]) diff --git a/src/Component/ComponentItemList.php b/src/Component/ComponentItemList.php index 72fa073..1ce805a 100644 --- a/src/Component/ComponentItemList.php +++ b/src/Component/ComponentItemList.php @@ -83,9 +83,7 @@ static function (ComponentItem $item) use ($query) { break; case 'tags': $tags = array_map('trim', explode(',', strtolower($query))); - $components = array_filter($this->getArrayCopy(), static function (ComponentItem $item) use ($tags) { - return array_intersect($tags, array_map('strtolower', $item->getTags())) !== []; - }); + $components = array_filter($this->getArrayCopy(), static fn (ComponentItem $item) => array_intersect($tags, array_map('strtolower', $item->getTags())) !== []); break; case 'name': diff --git a/src/Component/Data/Faker.php b/src/Component/Data/Faker.php index 17174f4..b951d1e 100644 --- a/src/Component/Data/Faker.php +++ b/src/Component/Data/Faker.php @@ -1,5 +1,7 @@ generator->numberBetween(0, 100000); case 'bool': case 'boolean': - return [true, false][rand(0, 1)]; + return [true, false][random_int(0, 1)]; case 'float': case 'double': return $this->generator->randomFloat(); diff --git a/src/Component/Data/GeneratorInterface.php b/src/Component/Data/GeneratorInterface.php index 479a6d9..4543b0a 100644 --- a/src/Component/Data/GeneratorInterface.php +++ b/src/Component/Data/GeneratorInterface.php @@ -1,5 +1,7 @@ configReadTime); - return $this->cache->get($hash, function () use ($filterQuery, $filterType) { - return $this->getComponents()->filter($filterQuery, $filterType); - }); + return $this->cache->get($hash, fn () => $this->getComponents()->filter($filterQuery, $filterType)); } /** diff --git a/tests/TestApp/Component/Data/Generator/CustomGenerator.php b/tests/TestApp/Component/Data/Generator/CustomGenerator.php index 4c8c7df..d423e9e 100644 --- a/tests/TestApp/Component/Data/Generator/CustomGenerator.php +++ b/tests/TestApp/Component/Data/Generator/CustomGenerator.php @@ -1,5 +1,7 @@ 'F00', 'session' => [ diff --git a/tests/TestApp/config/packages/twig.php b/tests/TestApp/config/packages/twig.php index 21ee1a3..13302b7 100644 --- a/tests/TestApp/config/packages/twig.php +++ b/tests/TestApp/config/packages/twig.php @@ -1,5 +1,7 @@ loadFromExtension('twig', [ 'default_path' => '%kernel.project_dir%/tests/TestApp/templates', ]); diff --git a/tests/TestApp/config/packages/twig_doc.php b/tests/TestApp/config/packages/twig_doc.php index bb5f475..dc86e55 100644 --- a/tests/TestApp/config/packages/twig_doc.php +++ b/tests/TestApp/config/packages/twig_doc.php @@ -1,5 +1,7 @@ [ '%twig.default_path%/snippets', diff --git a/tests/TestApp/config/services.php b/tests/TestApp/config/services.php index 044edda..cd00b51 100644 --- a/tests/TestApp/config/services.php +++ b/tests/TestApp/config/services.php @@ -1,9 +1,11 @@ services() ->defaults() ->autowire() diff --git a/tests/Unit/Component/ComponentItemFactoryTest.php b/tests/Unit/Component/ComponentItemFactoryTest.php index 3116346..fd6a77b 100644 --- a/tests/Unit/Component/ComponentItemFactoryTest.php +++ b/tests/Unit/Component/ComponentItemFactoryTest.php @@ -47,7 +47,7 @@ public function testValidComponent(array $componentData): void static::assertInstanceOf(ComponentCategory::class, $item->getCategory()); } - public function testInvalidCategory() + public function testInvalidCategory(): void { $this->expectException(InvalidComponentConfigurationException::class); diff --git a/tests/Unit/Component/Data/FakerTest.php b/tests/Unit/Component/Data/FakerTest.php index 035df74..b0ad5be 100644 --- a/tests/Unit/Component/Data/FakerTest.php +++ b/tests/Unit/Component/Data/FakerTest.php @@ -1,5 +1,7 @@ Date: Thu, 4 Apr 2024 09:51:18 +0200 Subject: [PATCH 15/15] #11 code review changes --- src/Component/Data/FixtureData.php | 8 ++++---- src/Component/Data/Generator/ScalarGenerator.php | 6 +++--- tests/Unit/Component/ComponentItemFactoryTest.php | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Component/Data/FixtureData.php b/src/Component/Data/FixtureData.php index f417219..498c2c5 100644 --- a/src/Component/Data/FixtureData.php +++ b/src/Component/Data/FixtureData.php @@ -9,13 +9,13 @@ /** * @codeCoverageIgnore */ -class FixtureData +readonly class FixtureData { public function __construct( - public readonly string $className, + public string $className, /** @param array $properties */ - public readonly array $properties, - public readonly array $params = [] + public array $properties, + public array $params = [] ) { } } diff --git a/src/Component/Data/Generator/ScalarGenerator.php b/src/Component/Data/Generator/ScalarGenerator.php index dd0fcd9..64f68c6 100644 --- a/src/Component/Data/Generator/ScalarGenerator.php +++ b/src/Component/Data/Generator/ScalarGenerator.php @@ -30,7 +30,7 @@ public function supports(string $type, mixed $context = null): bool 'integer', 'double', 'boolean', - ]); + ], true); } public function generate(string $type, mixed $context = null): float|object|bool|int|string|null @@ -41,8 +41,6 @@ public function generate(string $type, mixed $context = null): float|object|bool public function createParamValue(string $type): bool|int|float|string|null { switch (strtolower($type)) { - default: - return null; case 'string': return $this->generator->text(20); case 'int': @@ -54,6 +52,8 @@ public function createParamValue(string $type): bool|int|float|string|null case 'float': case 'double': return $this->generator->randomFloat(); + default: + return null; } } } diff --git a/tests/Unit/Component/ComponentItemFactoryTest.php b/tests/Unit/Component/ComponentItemFactoryTest.php index fd6a77b..44fd8c8 100644 --- a/tests/Unit/Component/ComponentItemFactoryTest.php +++ b/tests/Unit/Component/ComponentItemFactoryTest.php @@ -38,13 +38,13 @@ public function testValidComponent(array $componentData): void $componentItemFactory = new ComponentItemFactory( $validatorMock, $categoryServiceMock, - static::createMock(Faker::class) + $this->createMock(Faker::class) ); $item = $componentItemFactory->create($componentData); - static::assertInstanceOf(ComponentItem::class, $item); - static::assertInstanceOf(ComponentCategory::class, $item->getCategory()); + $this->assertInstanceOf(ComponentItem::class, $item); + $this->assertInstanceOf(ComponentCategory::class, $item->getCategory()); } public function testInvalidCategory(): void @@ -78,7 +78,7 @@ public function testGetParamsFromVariables(): void $result = $componentItemFactory->getParamsFromVariables($variables); - static::assertEquals([ + $this->assertEquals([ 'var' => [ 'separated' => [ 'by' => [