Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
65 / 65
100.00% covered (success)
100.00%
7 / 7
CRAP
100.00% covered (success)
100.00%
1 / 1
LeagueDefinitionFactory
100.00% covered (success)
100.00%
65 / 65
100.00% covered (success)
100.00%
7 / 7
20
100.00% covered (success)
100.00%
1 / 1
 makeAttributeDefinition
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
3
 isValTester
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 makeAttributeValueTesterDefinition
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 isArrayOfStrings
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 makeElementDefinition
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
5
 makeEventDefinition
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 makeOtherDefinition
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3/**
4 * @author: Doug Wilbourne (dougwilbourne@gmail.com)
5 */
6
7declare(strict_types=1);
8
9namespace pvc\html\htmlBuilder\definitions\implementations\league;
10
11use League\Container\Argument\LiteralArgument;
12use League\Container\Definition\Definition;
13use League\Container\Definition\DefinitionInterface;
14use pvc\html\err\DTOInvalidPropertyValueException;
15use pvc\html\err\DTOMissingPropertyException;
16use pvc\html\htmlBuilder\definitions\dto\AttributeDTO;
17use pvc\html\htmlBuilder\definitions\dto\AttributeValTesterDTO;
18use pvc\html\htmlBuilder\definitions\dto\ElementDTO;
19use pvc\html\htmlBuilder\definitions\dto\EventDTO;
20use pvc\html\htmlBuilder\definitions\dto\OtherDTO;
21use pvc\html\htmlBuilder\definitions\types\AttributeType;
22use pvc\html\htmlBuilder\definitions\types\ElementType;
23use pvc\html\htmlBuilder\definitions\types\EventType;
24use pvc\html\val_tester\EventScriptTester;
25use pvc\interfaces\html\htmlBuilder\definitions\DefinitionFactoryInterface;
26use pvc\interfaces\validator\ValTesterInterface;
27use Throwable;
28
29/**
30 * Class LeagueDefinitionFactory
31 *
32 * @phpstan-import-type DefArray from DefinitionFactoryInterface
33 * @implements DefinitionFactoryInterface<Definition>
34 */
35class LeagueDefinitionFactory implements DefinitionFactoryInterface
36{
37    /**
38     * makeAttributeDefinition
39     * @param DefArray $definitionArray
40     * @return DefinitionInterface
41     * @throws DTOMissingPropertyException
42     */
43    public function makeAttributeDefinition(array $definitionArray): mixed
44    {
45        $attributeDTO = new AttributeDTO();
46        $attributeDTO->permitExtraProperties();
47        $attributeDTO->hydrateFromArray($definitionArray);
48
49        if (!$class = AttributeType::getClass($attributeDTO->concrete)) {
50            throw new DTOInvalidPropertyValueException('concrete', $attributeDTO->concrete, 'Attribute');
51        }
52
53        $def = (new Definition($attributeDTO->defId, $class))
54            ->addMethodCall('setDefId', [new LiteralArgument($attributeDTO->defId)])
55            ->addMethodCall('setName', [new LiteralArgument($attributeDTO->name)])
56            ->addMethodCall('setGlobal', [$attributeDTO->global]);
57
58        if ($attributeDTO->valTester) {
59            $def->addMethodCall('setTester', [$attributeDTO->valTester])
60                ->addMethodCall('setCaseSensitive', [$attributeDTO->caseSensitive]);
61        }
62        return $def;
63    }
64
65    /**
66     * isValTester
67     * @param string $valTester
68     * @return bool
69     */
70    protected function isValTester(string $valTester): bool
71    {
72        try {
73            /** @phpstan-ignore argument.type */
74            $reflection = new \ReflectionClass($valTester);
75            if (!$reflection->implementsInterface(ValTesterInterface::class)) {
76                return false;
77            }
78        } catch (Throwable $e) {
79            return false;
80        }
81        return true;
82    }
83
84
85    /**
86     * makeAttributeValueTesterDefinition
87     * @param DefArray $definitionArray
88     * @return DefinitionInterface
89     */
90    public function makeAttributeValueTesterDefinition(array $definitionArray): mixed
91    {
92        $attributeValTesterDTO = new AttributeValTesterDTO();
93        $attributeValTesterDTO->permitExtraProperties();
94        $attributeValTesterDTO->hydrateFromArray($definitionArray);
95        
96        if (!$this->isValTester($attributeValTesterDTO->concrete)) {
97            throw new DTOInvalidPropertyValueException('valTester', $attributeValTesterDTO->concrete, 'AttributeValtesterDTO');
98        }
99
100        return (new Definition($attributeValTesterDTO->defId, $attributeValTesterDTO->concrete))
101            ->addArgument($attributeValTesterDTO->arg)
102            ->setShared(true);
103    }
104
105
106    /**
107     * isArrayOfStrings
108     * @param array<mixed> $array
109     * @return bool
110     */
111    protected function isArrayOfStrings(array $array): bool
112    {
113        $callback = function (bool $carry, mixed $x) {
114            return $carry && is_string($x);
115        };
116        return array_reduce($array, $callback, true);
117    }
118
119
120    /**
121     * makeElementDefinition
122     * @param DefArray $definitionArray
123     * @return DefinitionInterface
124     */
125    public function makeElementDefinition(array $definitionArray): mixed
126    {
127        $elementDTO = new ElementDTO();
128        $elementDTO->permitExtraProperties();
129        $elementDTO->hydrateFromArray($definitionArray);
130
131        if (!$class = ElementType::getClass($elementDTO->concrete)) {
132            throw new DTOInvalidPropertyValueException('concrete', $elementDTO->concrete, 'ElementDTO');
133        }
134
135        if (!$this->isArrayOfStrings($elementDTO->allowedAttributeDefIds)) {
136            $childDefIds = implode(',', $elementDTO->allowedAttributeDefIds);
137            throw new DTOInvalidPropertyValueException('allowedAttributeDefIds', $childDefIds, 'ElementDTO');
138        }
139
140        if (!$this->isArrayOfStrings($elementDTO->allowedChildDefIds)) {
141            throw new DTOInvalidPropertyValueException('allowedChildDefIds', $elementDTO->allowedChildDefIds, 'ElementDTO');
142        }
143
144        $def = (new Definition($elementDTO->defId, $class))
145            ->addMethodCall('setName', [new LiteralArgument($elementDTO->name)])
146            ->addMethodCall('setAllowedAttributeDefIds', [$elementDTO->allowedAttributeDefIds]);
147
148        /**
149         * child elements are only applicable to the Tag class (not TagVoid)
150         */
151        if ($elementDTO->concrete == 'Tag') {
152            $def->addMethodCall('setAllowedChildDefIds', [$elementDTO->allowedChildDefIds]);
153        }
154        return $def;
155    }
156
157    /**
158     * makeEventDefinition
159     * @param DefArray $definitionArray
160     * @return DefinitionInterface
161     */
162    public function makeEventDefinition(array $definitionArray): mixed
163    {
164        $eventDTO = new EventDTO();
165        $eventDTO->permitExtraProperties();
166        $eventDTO->hydrateFromArray($definitionArray);
167
168        if (!$class = EventType::getClass($eventDTO->concrete)) {
169            throw new DTOInvalidPropertyValueException('concrete', $eventDTO->concrete, 'EventDTO');
170        }
171
172        return (new Definition($eventDTO->defId, $class))
173            ->addArgument(EventScriptTester::class)
174            ->addMethodCall('setDefId', [new LiteralArgument($eventDTO->defId)]);
175    }
176
177    /**
178     * makeOtherSharedDefinition
179     * @param DefArray $definitionArray
180     * @return DefinitionInterface
181     */
182    public function makeOtherDefinition(array $definitionArray): mixed
183    {
184        $otherDTO = new OtherDTO();
185        $otherDTO->permitExtraProperties();
186        $otherDTO->hydrateFromArray($definitionArray);
187
188        if (!class_exists($otherDTO->concrete)) {
189            throw new DTOInvalidPropertyValueException('concrete', $otherDTO->concrete, 'OtherDTO');
190        }
191
192        $def = (new Definition($otherDTO->defId, $otherDTO->concrete))
193            ->setShared($otherDTO->shared);
194        /**
195         * not all the constructors have arguments....
196         */
197        if ($otherDTO->arg) {
198            $def->addArgument($otherDTO->arg);
199        }
200        return $def;
201    }
202}