Completed
Push — master ( 0d47c0...ecf131 )
by Jesse
05:02
created

HasManyNested::mustHaveTheKeyInThe()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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