Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
DTOTrait
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
4 / 4
10
100.00% covered (success)
100.00%
1 / 1
 permitExtraProperties
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 extraPropertiesPermitted
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hydrateFromArray
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
7
 toArray
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3/**
4 * @author: Doug Wilbourne (dougwilbourne@gmail.com)
5 */
6declare(strict_types=1);
7
8namespace pvc\html\htmlBuilder\definitions\dto;
9
10use pvc\html\err\DTOExtraPropertyException;
11use pvc\html\err\DTOInvalidPropertyValueException;
12use pvc\html\err\DTOMissingPropertyException;
13use ReflectionClass;
14use ReflectionProperty;
15use Stringable;
16use Throwable;
17
18/**
19 * Class DTOTrait
20 */
21trait DTOTrait
22{
23    private readonly bool $extraPropertiesPermitted;
24
25    public function permitExtraProperties(): void
26    {
27        $this->extraPropertiesPermitted = true;
28    }
29
30    public function extraPropertiesPermitted(): bool
31    {
32        return $this->extraPropertiesPermitted ?? false;
33    }
34
35    /**
36     * @param array<string, mixed> $constructorProperties
37     * @throws DTOExtraPropertyException
38     * @throws DTOMissingPropertyException
39     * @throws DTOInvalidPropertyValueException
40     */
41    public function hydrateFromArray(array $constructorProperties): void
42    {
43        $reflection = new ReflectionClass(static::class);
44
45        $className = $reflection->getName();
46
47        $requiredProperties = array_map(
48            function (ReflectionProperty $value): string {
49                return $value->getName();
50            },
51            $reflection->getProperties(ReflectionProperty::IS_PUBLIC)
52        );
53
54        $missingProperties = array_diff($requiredProperties, array_keys($constructorProperties));
55        if ($missingProperties) {
56            throw new DTOMissingPropertyException(implode(',', $missingProperties), $className);
57        }
58
59        $extraProperties = array_diff(array_keys($constructorProperties), $requiredProperties);
60        if ($extraProperties && !$this->extraPropertiesPermitted()) {
61            throw new DTOExtraPropertyException(implode(',', $extraProperties), $className);
62        }
63
64        foreach ($constructorProperties as $propertyName => $propertyValue) {
65            if (in_array($propertyName, $requiredProperties)) {
66                try {
67                    $this->{$propertyName} = $propertyValue;
68                } catch (Throwable $e) {
69                    throw new DTOInvalidPropertyValueException($propertyName, $propertyValue, $className);
70                }
71            }
72        }
73    }
74
75    /**
76     * toArray
77     * @return array<string, mixed>
78     */
79    public function toArray(): array
80    {
81        return (array) $this;
82    }
83}