Completed
Push — master ( 78bf9a...d3bc1d )
by Jesse
06:57
created

CollectionDeserializer::forMutable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
c 0
b 0
f 0
dl 0
loc 5
rs 10
cc 1
nc 1
nop 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Stratadox\Deserializer;
5
6
use Stratadox\Hydrator\ImmutableCollectionHydrator;
7
use Stratadox\Hydrator\MutableCollectionHydrator;
8
use function is_iterable;
9
use function is_string;
10
use Stratadox\Hydrator\HydrationFailure;
11
use Stratadox\Hydrator\Hydrator;
12
use Stratadox\Instantiator\InstantiationFailure;
13
use Stratadox\Instantiator\Instantiator;
14
use Stratadox\Instantiator\ObjectInstantiator;
15
16
/**
17
 * Deserializes the input array into collection objects.
18
 *
19
 * @author Stratadox
20
 */
21
final class CollectionDeserializer implements Deserializer
22
{
23
    /** @var Instantiator */
24
    private $make;
25
    /** @var Hydrator */
26
    private $hydrator;
27
28
    private function __construct(Instantiator $instance, Hydrator $hydrate)
29
    {
30
        $this->make = $instance;
31
        $this->hydrator = $hydrate;
32
    }
33
34
    /**
35
     * Makes a new deserializer for an immutable collection class.
36
     *
37
     * @param string $class The fully qualified collection class name.
38
     * @return Deserializer The collection deserializer.
39
     * @throws InstantiationFailure
40
     */
41
    public static function forImmutable(string $class): Deserializer
42
    {
43
        return new CollectionDeserializer(
44
            ObjectInstantiator::forThe($class),
45
            ImmutableCollectionHydrator::default()
46
        );
47
    }
48
49
    /**
50
     * Makes a new deserializer for a mutable collection class.
51
     *
52
     * @param string $class The fully qualified collection class name.
53
     * @return Deserializer The collection deserializer.
54
     * @throws InstantiationFailure
55
     */
56
    public static function forMutable(string $class): Deserializer
57
    {
58
        return new CollectionDeserializer(
59
            ObjectInstantiator::forThe($class),
60
            MutableCollectionHydrator::default()
61
        );
62
    }
63
64
    /**
65
     * Makes a new deserializer for the collection class, using custom
66
     * instantiator and hydrator.
67
     *
68
     * @param Instantiator $instantiator The object that produces instances.
69
     * @param Hydrator     $hydrator     The object that writes properties.
70
     * @return Deserializer              The collection deserializer.
71
     */
72
    public static function using(
73
        Instantiator $instantiator,
74
        Hydrator $hydrator
75
    ): Deserializer {
76
        return new CollectionDeserializer($instantiator, $hydrator);
77
    }
78
79
    /** @inheritdoc */
80
    public function from(array $input): iterable
81
    {
82
        $collection = $this->make->instance();
83
        $this->mustBeValid($collection, $input);
84
        try {
85
            $this->hydrator->writeTo($collection, $input);
86
        } catch (HydrationFailure $exception) {
87
            throw FailedToDeserializeTheCollection::encountered($exception);
88
        }
89
        if (is_iterable($collection)) {
90
            /** @var iterable $collection */
91
            return $collection;
92
        }
93
        throw NonIterableCollection::invalid($collection);
94
    }
95
96
    /** @inheritdoc */
97
    public function typeFor(array $input): string
98
    {
99
        return $this->make->class();
100
    }
101
102
    /** @throws DeserializationFailure */
103
    private function mustBeValid(object $collection, array $input): void
104
    {
105
        foreach ($input as $key => $value) {
106
            if (is_string($key)) {
107
                throw IllegalInputKey::illegal($collection, $key, $input);
108
            }
109
        }
110
    }
111
}
112