diff --git a/src/Cache/ComponentsWarmer.php b/src/Cache/ComponentsWarmer.php index 68068c2..1596ba7 100644 --- a/src/Cache/ComponentsWarmer.php +++ b/src/Cache/ComponentsWarmer.php @@ -1,14 +1,19 @@ container->get('twig_doc.service.component'); diff --git a/src/Component/ComponentInvalid.php b/src/Component/ComponentInvalid.php index 740e9eb..3395de4 100644 --- a/src/Component/ComponentInvalid.php +++ b/src/Component/ComponentInvalid.php @@ -9,11 +9,11 @@ /** * @codeCoverageIgnore */ -class ComponentInvalid +readonly class ComponentInvalid { public function __construct( - public readonly ConstraintViolationList $violationList, - public readonly array $originalConfig + public ConstraintViolationList $violationList, + public array $originalConfig ) { } } diff --git a/src/Component/ComponentItem.php b/src/Component/ComponentItem.php index 04fc317..9d529d1 100644 --- a/src/Component/ComponentItem.php +++ b/src/Component/ComponentItem.php @@ -13,21 +13,29 @@ class ComponentItem { #[Assert\NotBlank] private string $name; + #[Assert\NotBlank] private string $title; + #[Assert\NotBlank] private string $description; + #[Assert\Type('array')] private array $tags; + #[Assert\Type('array')] private array $parameters; + #[Assert\Type('array')] private array $variations; + #[Assert\Valid] private ComponentCategory $category; + #[Assert\Length(max: 4096)] #[Assert\NotBlank] private string $projectPath; + #[Assert\Length(max: 4096)] #[Assert\NotBlank] private string $renderPath; diff --git a/src/Component/ComponentItemFactory.php b/src/Component/ComponentItemFactory.php index 146338c..f584db0 100644 --- a/src/Component/ComponentItemFactory.php +++ b/src/Component/ComponentItemFactory.php @@ -9,12 +9,15 @@ use Symfony\Component\Validator\ConstraintViolationList; use Symfony\Component\Validator\Validator\ValidatorInterface; -class ComponentItemFactory +readonly class ComponentItemFactory { - public function __construct(private readonly ValidatorInterface $validator, private readonly CategoryService $categoryService) + public function __construct(private ValidatorInterface $validator, private CategoryService $categoryService) { } + /** + * @throws InvalidComponentConfigurationException + */ public function create(array $data): ComponentItem { $item = $this->createItem($data); @@ -28,7 +31,7 @@ public function create(array $data): ComponentItem isset($data['sub_category']) ? 'sub_category' : 'category', $data['sub_category'] ?? $data['category'], implode(', ', array_keys($this->categoryService->getCategories())), - implode(', ', array_map(fn (ComponentCategory $category) => $category->getName(), $this->categoryService->getSubCategories())) + implode(', ', array_map(static fn (ComponentCategory $category) => $category->getName(), $this->categoryService->getSubCategories())) ) ); throw new InvalidComponentConfigurationException($violations); @@ -68,12 +71,14 @@ public function getParamsFromVariables(array $variables): array foreach ($variables as $dotted) { $keys = explode('.', $dotted); $c = &$r[array_shift($keys)]; + foreach ($keys as $key) { if (isset($c[$key]) && $c[$key] === true) { $c[$key] = []; } $c = &$c[$key]; } + if ($c === null) { $c = 'Scalar'; } diff --git a/src/Component/ComponentItemList.php b/src/Component/ComponentItemList.php index 24de966..72fa073 100644 --- a/src/Component/ComponentItemList.php +++ b/src/Component/ComponentItemList.php @@ -1,5 +1,7 @@ sortableFields)) { + if (!\in_array($field, $this->sortableFields, true)) { throw new \InvalidArgumentException(sprintf('field "%s" is not sortable', $field)); } @@ -52,13 +54,15 @@ public function sort(string $field, string $direction = self::SORT_ASC): void public function filter(string $query, ?string $type): self { $components = []; + switch ($type) { case 'category': $components = array_filter( $this->getArrayCopy(), - function (ComponentItem $item) use ($query) { + static function (ComponentItem $item) use ($query) { $category = $item->getCategory()->getName(); $parent = $item->getCategory()->getParent(); + while ($parent !== null) { $category = $parent->getName(); $parent = $parent->getParent(); @@ -72,14 +76,14 @@ function (ComponentItem $item) use ($query) { case 'sub_category': $components = array_filter( $this->getArrayCopy(), - fn (ComponentItem $item) => $item->getCategory()->getParent() !== null + static fn (ComponentItem $item) => $item->getCategory()->getParent() !== null && strtolower($item->getCategory()->getName()) === strtolower($query) ); break; case 'tags': $tags = array_map('trim', explode(',', strtolower($query))); - $components = array_filter($this->getArrayCopy(), function (ComponentItem $item) use ($tags) { + $components = array_filter($this->getArrayCopy(), static function (ComponentItem $item) use ($tags) { return array_intersect($tags, array_map('strtolower', $item->getTags())) !== []; }); @@ -87,13 +91,13 @@ function (ComponentItem $item) use ($query) { case 'name': $components = array_filter( $this->getArrayCopy(), - fn (ComponentItem $item) => str_contains(strtolower($item->getName()), strtolower($query)) + static fn (ComponentItem $item) => str_contains(strtolower($item->getName()), strtolower($query)) ); break; default: - foreach (['category', 'sub_category', 'tags', 'name'] as $type) { - $components = array_merge($components, (array) $this->filter($query, $type)); + foreach (['category', 'sub_category', 'tags', 'name'] as $componentType) { + $components = array_merge($components, (array) $this->filter($query, $componentType)); } break; diff --git a/src/Configuration/ParserInterface.php b/src/Configuration/ParserInterface.php index 4288eff..a454a58 100644 --- a/src/Configuration/ParserInterface.php +++ b/src/Configuration/ParserInterface.php @@ -1,5 +1,7 @@ valid()) { $line = $fileObject->current(); + if (empty(trim($line))) { $fileObject->next(); continue; } + if ($firstLineDetected === false) { $firstLineDetected = true; // check for whitespaces at the beginning @@ -39,6 +42,7 @@ private function fixIndentation(string $content): string } $indentationWhitespace = $matches[1]; } + $line = substr($line, \strlen($indentationWhitespace)); $lines[] = $line; $fileObject->next(); diff --git a/src/Controller/TwigDocController.php b/src/Controller/TwigDocController.php index cbed517..b2e9694 100644 --- a/src/Controller/TwigDocController.php +++ b/src/Controller/TwigDocController.php @@ -11,12 +11,12 @@ use Symfony\Component\HttpKernel\Profiler\Profiler; use Twig\Environment; -class TwigDocController +readonly class TwigDocController { public function __construct( - private readonly Environment $twig, - private readonly ComponentService $componentService, - private readonly ?Profiler $profiler = null + private Environment $twig, + private ComponentService $componentService, + private ?Profiler $profiler = null ) { } diff --git a/src/DependencyInjection/Compiler/TwigDocCollectDocsPass.php b/src/DependencyInjection/Compiler/TwigDocCollectDocsPass.php index 7476460..a783adf 100644 --- a/src/DependencyInjection/Compiler/TwigDocCollectDocsPass.php +++ b/src/DependencyInjection/Compiler/TwigDocCollectDocsPass.php @@ -1,5 +1,7 @@ hasExtension('twig_doc')) { return; } + $config = $container->getParameter('twig_doc.config'); $directories = $this->resolveDirectories($container, $config['directories']); $container->getParameterBag()->remove('twig_doc.config'); @@ -51,9 +54,10 @@ public function process(ContainerBuilder $container): void $filename = $file->getFilename(); $componentName = substr($filename, 0, strpos($filename, '.')); - if (array_filter($componentConfig, fn (array $data) => $data['name'] === $componentName)) { - throw new InvalidConfigException(sprintf('component "%s" is configured twice, please configure either directly in the template or the general bundle configuration', $componentName)); + if (array_filter($componentConfig, static fn (array $data) => $data['name'] === $componentName)) { + throw new InvalidConfigException(sprintf('Component "%s" is configured twice, please configure either directly in the template or the general bundle configuration', $componentName)); } + $itemConfig = [ 'name' => $componentName, 'path' => str_replace($projectDir.'/', '', $file->getRealPath()), @@ -69,7 +73,6 @@ public function process(ContainerBuilder $container): void private function parseDoc(SplFileInfo $file, string $docIdentifier): ?array { $content = $file->getContents(); - $pattern = sprintf("/\{#%s\s(.*)%s#}/s", $docIdentifier, $docIdentifier); preg_match($pattern, $content, $matches); @@ -84,10 +87,10 @@ private function parseDoc(SplFileInfo $file, string $docIdentifier): ?array private function enrichComponentsConfig(ContainerBuilder $container, array $directories, array $components): array { foreach ($components as &$component) { - if (!isset($component['path'])) { - $component['path'] = str_replace($container->getParameter('kernel.project_dir').'/', '', $this->getTemplatePath($component['name'], $directories)); + if (!isset($component['path']) && $templatePath = $this->getTemplatePath($component['name'], $directories)) { + $component['path'] = str_replace($container->getParameter('kernel.project_dir').'/', '', $templatePath); } - if (!isset($component['renderPath'])) { + if (!isset($component['renderPath']) && isset($component['path'])) { $component['renderPath'] = str_replace($container->getParameter('twig.default_path').'/', '', $component['path']); } } @@ -98,8 +101,7 @@ private function enrichComponentsConfig(ContainerBuilder $container, array $dire private function resolveDirectories(ContainerBuilder $container, array $directories): array { $directories[] = $container->getParameter('twig.default_path').'/components'; - - $directories = array_map(fn (string $dir) => $container->getParameterBag()->resolveValue($dir), $directories); + $directories = array_map(static fn (string $dir) => $container->getParameterBag()->resolveValue($dir), $directories); foreach ($directories as $idx => $dir) { if (!is_dir($dir)) { @@ -113,9 +115,7 @@ private function resolveDirectories(ContainerBuilder $container, array $director private function getTemplatePath(string $name, array $directories): ?string { $template = sprintf('%s.html.twig', $name); - $finder = new Finder(); - $files = $finder->in($directories)->files()->filter(fn (SplFileInfo $file) => $file->getFilename() === $template); if ($files->count() > 1) { @@ -128,6 +128,6 @@ private function getTemplatePath(string $name, array $directories): ?string $files->getIterator()->rewind(); - return $files->getIterator()->current(); + return $files->getIterator()->current()?->__toString(); } } diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 14ead37..a21aeb8 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -1,5 +1,7 @@ subCategories, fn (ComponentCategory $category) => $category->getParent() === $mainCategory); + return array_filter($this->subCategories, static fn (ComponentCategory $category) => $category->getParent() === $mainCategory); } return $this->subCategories; diff --git a/src/Service/ComponentService.php b/src/Service/ComponentService.php index 0f7be91..f45505a 100644 --- a/src/Service/ComponentService.php +++ b/src/Service/ComponentService.php @@ -12,14 +12,14 @@ use Qossmic\TwigDocBundle\Exception\InvalidComponentConfigurationException; use Symfony\Contracts\Cache\CacheInterface; -class ComponentService +readonly class ComponentService { public function __construct( - private readonly ComponentItemFactory $itemFactory, - private readonly array $componentsConfig, - private readonly CacheInterface $cache, - private readonly array $breakpointConfig, - private readonly int $configReadTime = 0 + private ComponentItemFactory $itemFactory, + private array $componentsConfig, + private CacheInterface $cache, + private array $breakpointConfig, + private int $configReadTime = 0 ) { } @@ -94,7 +94,7 @@ public function getInvalidComponents(): array public function getComponent(string $name): ?ComponentItem { - return array_values(array_filter((array) $this->getComponents(), fn (ComponentItem $c) => $c->getName() === $name))[0] ?? null; + return array_values(array_filter((array) $this->getComponents(), static fn (ComponentItem $c) => $c->getName() === $name))[0] ?? null; } public function getBreakpoints(): array diff --git a/templates/blocks/page_blocks.html.twig b/templates/blocks/page_blocks.html.twig index 9951789..e44f0fc 100644 --- a/templates/blocks/page_blocks.html.twig +++ b/templates/blocks/page_blocks.html.twig @@ -37,7 +37,6 @@ {% block body %}
{{ component.originalConfig.path ?? 'UNKNOWN PATH' }}
-{{ component.violationList }}
@@ -24,20 +24,20 @@ {% for tag in component.originalConfig.tags %} {% if loop.first %}Variations:
{% for key, value in variation %} {% if loop.first %}