Completed
Push — master ( 8d5bbd...3b8b9e )
by Julián
05:58
created

AbstractDTOCollection::__unserialize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
c 0
b 0
f 0
dl 0
loc 5
rs 10
cc 1
nc 1
nop 1
1
<?php
2
3
/*
4
 * dto (https://github.com/phpgears/dto).
5
 * General purpose immutable Data Transfer Objects for PHP.
6
 *
7
 * @license MIT
8
 * @link https://github.com/phpgears/dto
9
 * @author Julián Gutiérrez <[email protected]>
10
 */
11
12
declare(strict_types=1);
13
14
namespace Gears\DTO;
15
16
use Gears\DTO\Exception\InvalidCollectionTypeException;
17
use Gears\DTO\Exception\InvalidParameterException;
18
use Gears\Immutability\ImmutabilityBehaviour;
19
20
/**
21
 * Abstract immutable Data Transfer Object collection.
22
 */
23
abstract class AbstractDTOCollection implements DTOCollection
24
{
25
    use ImmutabilityBehaviour, PayloadBehaviour {
26
        PayloadBehaviour::__call insteadof ImmutabilityBehaviour;
27
        __call as private payloadCall;
28
    }
29
30
    /**
31
     * DTOCollection constructor.
32
     *
33
     * @param array<string, mixed> $elements
34
     */
35
    final protected function __construct(array $elements)
36
    {
37
        $this->assertImmutable();
38
39
        $this->verifyElementsType($elements);
40
41
        $this->setPayload(['elements' => \array_values($elements)]);
42
    }
43
44
    /**
45
     * {@inheritdoc}
46
     */
47
    final public static function fromElements(array $elements): DTOCollection
48
    {
49
        return new static($elements);
50
    }
51
52
    /**
53
     * {@inheritdoc}
54
     */
55
    final public function getElements(): \Traversable
56
    {
57
        return $this->get('elements');
58
    }
59
60
    /**
61
     * {@inheritdoc}
62
     */
63
    final public function getIterator(): \Traversable
64
    {
65
        return $this->get('elements');
66
    }
67
68
    /**
69
     * @return mixed[]
70
     */
71
    final public function __sleep(): array
72
    {
73
        return ['payload'];
74
    }
75
76
    final public function __wakeup(): void
77
    {
78
        $this->assertImmutable();
79
    }
80
81
    /**
82
     * @return array<string, mixed>
83
     */
84
    final public function __serialize(): array
85
    {
86
        return ['payload' => $this->payload];
87
    }
88
89
    /**
90
     * @param array<string, mixed> $data
91
     *
92
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
93
     */
94
    final public function __unserialize(array $data): void
95
    {
96
        $this->assertImmutable();
97
98
        $this->setPayload($data['payload']);
99
    }
100
101
    /**
102
     * Verify collection elements type.
103
     *
104
     * @param mixed[] $elements
105
     *
106
     * @throws InvalidCollectionTypeException
107
     * @throws InvalidParameterException
108
     */
109
    private function verifyElementsType(array $elements): void
110
    {
111
        $allowedType = $this->getAllowedType();
112
        if ($allowedType !== DTO::class
113
            && (!\class_exists($allowedType) || !\in_array(DTO::class, \class_implements($allowedType), true))
114
        ) {
115
            throw new InvalidCollectionTypeException(\sprintf(
116
                'Allowed class type for "%s" should be a "%s", "%s" given',
117
                static::class,
118
                DTO::class,
119
                $allowedType
120
            ));
121
        }
122
123
        foreach ($elements as $element) {
124
            if (!\is_object($element) || !\is_a($element, $allowedType)) {
125
                throw new InvalidParameterException(\sprintf(
126
                    'All elements of "%s" should be instances of "%s", "%s" given',
127
                    static::class,
128
                    $allowedType,
129
                    \is_object($element) ? \get_class($element) : \gettype($element)
130
                ));
131
            }
132
        }
133
    }
134
135
    /**
136
     * Transform collection elements for output.
137
     *
138
     * @param mixed[] $elements
139
     *
140
     * @return \Traversable<mixed>
141
     */
142
    final protected function outputElements(array $elements): \Traversable
143
    {
144
        return new \ArrayIterator($elements);
145
    }
146
147
    /**
148
     * Get allowed DTO type for collection elements.
149
     *
150
     * @return string
151
     */
152
    abstract protected function getAllowedType(): string;
153
154
    /**
155
     * {@inheritdoc}
156
     *
157
     * @return string[]
158
     */
159
    final protected function getAllowedInterfaces(): array
160
    {
161
        return [DTOCollection::class, \Serializable::class];
162
    }
163
}
164