Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
87.50% covered (warning)
87.50%
14 / 16
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
MixedComponentProvider
87.50% covered (warning)
87.50%
14 / 16
50.00% covered (danger)
50.00%
1 / 2
6.07
0.00% covered (danger)
0.00%
0 / 1
 supports
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 createComponentFor
86.67% covered (warning)
86.67%
13 / 15
0.00% covered (danger)
0.00%
0 / 1
4.04
1<?php
2namespace Apie\HtmlBuilders\Factories\Concrete;
3
4use Apie\HtmlBuilders\FormBuildContext;
5use Apie\HtmlBuilders\Interfaces\ComponentInterface;
6use Apie\HtmlBuilders\Interfaces\FormComponentProviderInterface;
7use Apie\TypeConverter\ReflectionTypeFactory;
8use ReflectionNamedType;
9use ReflectionType;
10
11final class MixedComponentProvider implements FormComponentProviderInterface
12{
13    /** @var array<string, bool> */
14    private array $handled = [];
15
16    public function supports(ReflectionType $type, FormBuildContext $context): bool
17    {
18        return $type instanceof ReflectionNamedType && $type->getName() === 'mixed';
19    }
20    public function createComponentFor(ReflectionType $type, FormBuildContext $context): ComponentInterface
21    {
22        $formName = $context->getFormName();
23        $name = (string) $formName;
24        $typesAllowed = 'string|int|null|bool|float';
25        // avoid infinite recursion by only allowing array if we are not too many levels deep and
26        // storing the currently pending form fields.
27        if (count($formName->toNative()) < 6) {
28            $typesAllowed .= '|array';
29            
30            foreach (array_keys($this->handled) as $handledName) {
31                if (str_starts_with($handledName, $name)) {
32                    $typesAllowed = 'string|int|null|bool|float';
33                    break;
34                }
35            }
36        }
37        try {
38            $this->handled[$name] = true;
39            return $context->getComponentFactory()->createFromType(
40                ReflectionTypeFactory::createReflectionType($typesAllowed),
41                $context
42            );
43        } finally {
44            unset($this->handled[$name]);
45        }
46    }
47}