Passed
Push — master ( 43c74d...df9319 )
by Jesse
02:15
created

HasManyNested::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 4
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stratadox\Hydration\Mapping\Property\Relationship;
6
7
use Stratadox\Hydration\Mapping\Property\MissingTheKey;
8
use Stratadox\HydrationMapping\ExposesDataKey;
9
use Stratadox\Hydrator\Hydrates;
10
use Throwable;
11
12
/**
13
 * Maps a nested data structure to a collection in an object property.
14
 *
15
 * @package Stratadox\Hydrate
16
 * @author Stratadox
17
 */
18
final class HasManyNested implements ExposesDataKey
19
{
20
    private $name;
21
    private $key;
22
    private $collection;
23
    private $item;
24
25
    private function __construct(
26
        string $name,
27
        string $dataKey,
28
        Hydrates $collection,
29
        Hydrates $item
30
    ) {
31
        $this->name = $name;
32
        $this->key = $dataKey;
33
        $this->collection = $collection;
34
        $this->item = $item;
35
    }
36
37
    /**
38
     * Create a new nested has-many mapping.
39
     *
40
     * @param string   $name       The name of both the key and the property.
41
     * @param Hydrates $collection The hydrator for the collection.
42
     * @param Hydrates $item       The hydrator for the individual items.
43
     * @return self                The nested has-many mapping.
44
     */
45
    public static function inProperty(
46
        string $name,
47
        Hydrates $collection,
48
        Hydrates $item
49
    ): self {
50
        return new self($name, $name, $collection, $item);
51
    }
52
53
    /**
54
     * Create a new nested has-many mapping, using the data from a specific key.
55
     *
56
     * @param string   $name       The name of the property.
57
     * @param string   $key        The name of the key.
58
     * @param Hydrates $collection The hydrator for the collection.
59
     * @param Hydrates $item       The hydrator for the individual items.
60
     * @return self                The nested has-many mapping.
61
     */
62
    public static function inPropertyWithDifferentKey(
63
        string $name,
64
        string $key,
65
        Hydrates $collection,
66
        Hydrates $item
67
    ): self {
68
        return new self($name, $key, $collection, $item);
69
    }
70
71
    public function name() : string
72
    {
73
        return $this->name;
74
    }
75
76
    public function key() : string
77
    {
78
        return $this->key;
79
    }
80
81
    public function value(array $data, $owner = null)
82
    {
83
        $this->mustHaveTheKeyInThe($data);
84
        try {
85
            $objects = $this->itemsFromArray($data);
86
        } catch (Throwable $exception) {
87
            throw CollectionMappingFailed::tryingToMapItem($this, $exception);
88
        }
89
        try {
90
            return $this->collection->fromArray($objects);
91
        } catch (Throwable $exception) {
92
            throw CollectionMappingFailed::tryingToMapCollection($this, $exception);
93
        }
94
    }
95
96
    private function itemsFromArray(array $data): array
97
    {
98
        $objects = [];
99
        foreach ($data[$this->key()] as $objectData) {
100
            $objects[] = $this->item->fromArray($objectData);
101
        }
102
        return $objects;
103
    }
104
105
    private function mustHaveTheKeyInThe(array $data): void
106
    {
107
        if (!array_key_exists($this->key(), $data)) {
108
            throw MissingTheKey::inTheInput($data, $this, $this->key());
109
        }
110
    }
111
}
112