Completed
Push — master ( c2d23a...f43081 )
by Jesse
02:42
created

MappedHydrator::makeFrom()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 7
nc 2
nop 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Stratadox\Hydrator;
5
6
use Closure;
7
use Stratadox\HydrationMapping\MapsProperties;
8
use Stratadox\HydrationMapping\UnmappableInput;
9
use Stratadox\Instantiator\CannotInstantiateThis;
10
use Stratadox\Instantiator\Instantiator;
11
use Stratadox\Instantiator\ProvidesInstances;
12
use Throwable;
13
14
/**
15
 * Hydrates an object from mapped array input.
16
 *
17
 * @package Stratadox\Hydrate
18
 * @author  Stratadox
19
 */
20
final class MappedHydrator implements Hydrates
21
{
22
    private $make;
23
    private $properties;
24
    private $setter;
25
    private $observer;
26
27
    private function __construct(
28
        ProvidesInstances $instances,
29
        MapsProperties $mapped,
30
        ObservesHydration $observer,
31
        ?Closure $setter
32
    ) {
33
        $this->make = $instances;
34
        $this->properties = $mapped;
35
        $this->observer = $observer;
36
        $this->setter = $setter ?: function (string $attribute, $value) {
37
            $this->$attribute = $value;
38
        };
39
    }
40
41
    /**
42
     * Creates a new mapped hydrator for a class.
43
     *
44
     * @param string                 $class    The class to hydrate.
45
     * @param MapsProperties         $mapped   The mappings for the properties.
46
     * @param Closure|null           $setter   The closure that writes the values.
47
     * @param ObservesHydration|null $observer Object that gets updated with the
48
     *                                         hydrating instance.
49
     * @return Hydrates                        The mapped hydrator.
50
     * @throws CannotInstantiateThis           When the class is not instantiable.
51
     */
52
    public static function forThe(
53
        string $class,
54
        MapsProperties $mapped,
55
        Closure $setter = null,
56
        ObservesHydration $observer = null
57
    ): Hydrates {
58
        return new self(
59
            Instantiator::forThe($class),
60
            $mapped,
61
            $observer ?: BlindObserver::asDefault(),
62
            $setter
63
        );
64
    }
65
66
    /**
67
     * Creates a new mapped hydrator with an instantiator.
68
     *
69
     * @param ProvidesInstances      $instantiator The instance provider to use.
70
     * @param MapsProperties         $mapped       The mappings for the properties.
71
     * @param Closure|null           $setter       The closure that writes the values.
72
     * @param ObservesHydration|null $observer     Object that gets updated with the
73
     *                                             hydrating instance.
74
     * @return Hydrates                            The mapped hydrator.
75
     */
76
    public static function withInstantiator(
77
        ProvidesInstances $instantiator,
78
        MapsProperties $mapped,
79
        Closure $setter = null,
80
        ObservesHydration $observer = null
81
    ): Hydrates {
82
        return new self(
83
            $instantiator,
84
            $mapped,
85
            $observer ?: BlindObserver::asDefault(),
86
            $setter
87
        );
88
    }
89
90
    /** @inheritdoc */
91
    public function fromArray(array $data)
92
    {
93
        try {
94
            return $this->makeFrom($data);
95
        } catch (Throwable $exception) {
96
            throw HydrationFailed::encountered($exception, $this->make->class());
97
        }
98
    }
99
100
    /** @inheritdoc */
101
    public function classFor(array $input): string
102
    {
103
        return $this->make->class();
104
    }
105
106
    /**
107
     * Produces the hydrated instance.
108
     *
109
     * @param array $data   The input data.
110
     * @return mixed|object The hydrated instance.
111
     * @throws CannotInstantiateThis
112
     * @throws UnmappableInput
113
     */
114
    private function makeFrom(array $data)
115
    {
116
        $object = $this->make->instance();
117
        $this->observer->hydrating($object);
118
        foreach ($this->properties as $property) {
119
            $this->setter->call($object,
120
                $property->name(),
121
                $property->value($data, $object)
122
            );
123
        }
124
        return $object;
125
    }
126
}
127