Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.55% covered (success)
96.55%
56 / 58
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApieSingleInputComponentProvider
96.55% covered (success)
96.55%
56 / 58
75.00% covered (warning)
75.00%
3 / 4
16
0.00% covered (danger)
0.00%
0 / 1
 getSingleInputAttribute
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
5
 getMultipleInputAttributes
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
5
 supports
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 createComponentFor
89.47% covered (warning)
89.47%
17 / 19
0.00% covered (danger)
0.00%
0 / 1
3.01
1<?php
2namespace Apie\HtmlBuilders\Factories\Concrete;
3
4use Apie\Core\Attributes\CmsSingleInput;
5use Apie\Core\Attributes\CmsValidationCheck;
6use Apie\Core\Utils\ConverterUtils;
7use Apie\HtmlBuilders\Components\Forms\SingleInput;
8use Apie\HtmlBuilders\FormBuildContext;
9use Apie\HtmlBuilders\Interfaces\ComponentInterface;
10use Apie\HtmlBuilders\Interfaces\FormComponentProviderInterface;
11use ReflectionClass;
12use ReflectionType;
13
14class ApieSingleInputComponentProvider implements FormComponentProviderInterface
15{
16    /** @var array<class-string<object>, CmsSingleInput|null> $alreadyChecked */
17    private static array $alreadyChecked = [];
18    /** @var array<class-string<object>, (CmsValidationCheck|array<string, mixed>)[]> $alreadyCheckedValidation */
19    private static array $alreadyCheckedValidation = [];
20
21    /**
22     * @param ReflectionClass<object> $class
23     */
24    private function getSingleInputAttribute(ReflectionClass $class): ?CmsSingleInput
25    {
26        if (!isset(self::$alreadyChecked[$class->name])) {
27            self::$alreadyChecked[$class->name] = null;
28            foreach ($class->getAttributes(CmsSingleInput::class) as $input) {
29                return self::$alreadyChecked[$class->name] = $input->newInstance();
30            }
31            foreach ($class->getInterfaceNames() as $interfaceName) {
32                self::$alreadyChecked[$class->name] ??= $this->getSingleInputAttribute(
33                    new ReflectionClass($interfaceName)
34                );
35            }
36            foreach ($class->getTraitNames() as $traitName) {
37                self::$alreadyChecked[$class->name] ??= $this->getSingleInputAttribute(
38                    new ReflectionClass($traitName)
39                );
40            }
41        }
42        return self::$alreadyChecked[$class->name];
43    }
44
45    /**
46     * @param ReflectionClass<object> $class
47     * @param ReflectionClass<object> $mainClass
48     * @return (CmsValidationCheck|array<string, mixed>)[]
49     */
50    private function getMultipleInputAttributes(ReflectionClass $class, ReflectionClass $mainClass): array
51    {
52        if (!isset(self::$alreadyCheckedValidation[$class->name])) {
53            self::$alreadyCheckedValidation[$class->name] = [];
54            foreach ($class->getAttributes(CmsValidationCheck::class) as $input) {
55                self::$alreadyCheckedValidation[$class->name][] = $input->newInstance()->toArray($mainClass);
56            }
57            foreach ($class->getInterfaceNames() as $interfaceName) {
58                array_push(
59                    self::$alreadyCheckedValidation[$class->name],
60                    ...$this->getMultipleInputAttributes(
61                        new ReflectionClass($interfaceName),
62                        $mainClass
63                    )
64                );
65            }
66            foreach ($class->getTraitNames() as $traitName) {
67                array_push(
68                    self::$alreadyCheckedValidation[$class->name],
69                    ...$this->getMultipleInputAttributes(
70                        new ReflectionClass($traitName),
71                        $mainClass
72                    )
73                );
74            }
75        }
76        return self::$alreadyCheckedValidation[$class->name];
77    }
78
79    public function supports(ReflectionType $type, FormBuildContext $context): bool
80    {
81        $class = ConverterUtils::toReflectionClass($type);
82        if ($class === null) {
83            return false;
84        }
85        return (bool) $this->getSingleInputAttribute($class)
86            || !empty($this->getMultipleInputAttributes($class, $class));
87    }
88    public function createComponentFor(ReflectionType $type, FormBuildContext $context): ComponentInterface
89    {
90        $class = ConverterUtils::toReflectionClass($type);
91        $validationChecks = $this->getMultipleInputAttributes($class, $class);
92        $validationError = $context->getValidationError();
93        $value = $context->getFilledInValue();
94        if ($validationError !== null) {
95            $validationChecks[] = CmsValidationCheck::createFromStaticValue($validationError, $value);
96        }
97        return new SingleInput(
98            $context->getFormName(),
99            $value,
100            $context->createTranslationLabel(),
101            $type->allowsNull(),
102            $type,
103            $this->getSingleInputAttribute($class) ?? new CmsSingleInput(['text']),
104            array_map(function (CmsValidationCheck|array  $check) use ($class) {
105                if (is_array($check)) {
106                    return $check;
107                }
108                return $check->toArray($class);
109            }, $validationChecks)
110        );
111    }
112}