Completed
Push — master ( 9e9e7e...b5260b )
by Jesse
02:00
created

HasMany::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 2
1
<?php
2
declare(strict_types=1);
3
4
namespace Stratadox\TableLoader;
5
6
use function in_array;
7
use Stratadox\Hydrator\ArrayHydrator;
8
use Stratadox\Hydrator\CannotHydrate;
9
use Stratadox\Hydrator\Hydrates;
10
11
/**
12
 * Defines a has-many relationship.
13
 *
14
 * @author Stratadox
15
 */
16
final class HasMany implements MakesConnections
17
{
18
    private $property;
19
    private $collection;
20
21
    private function __construct(string $property, Hydrates $collection)
22
    {
23
        $this->property = $property;
24
        $this->collection = $collection;
25
    }
26
27
    /**
28
     * Makes a connector for a has-many type relationship.
29
     *
30
     * @param string        $property   The property to map.
31
     * @param Hydrates|null $collection The collection hydrator to use.
32
     * @return MakesConnections         The relationship connector.
33
     */
34
    public static function in(
35
        string $property,
36
        Hydrates $collection = null
37
    ): MakesConnections {
38
        return new self($property, $collection ?: ArrayHydrator::create());
39
    }
40
41
    /** @inheritdoc */
42
    public function load(
43
        KnowsWhereToLook $from,
44
        array $data,
45
        KnowsWhereToLook $to,
46
        ContainsResultingObjects $objects
47
    ): array {
48
        $related = [];
49
        foreach ($data as $row) {
50
            $object = $objects[$to->label()][$to->this($row)];
51
            if ($this->shouldAdd($object, $from->this($row), $related)) {
52
                $related[$from->this($row)][] = $object;
53
            }
54
        }
55
        return [$this->property => $this->makeCollections($from->label(), $related)];
56
    }
57
58
    /**
59
     * Checks if we should add the object to the relations collection.
60
     *
61
     * @param object $relation The related object.
62
     * @param string $from     The id of the object that holds the relationship.
63
     * @param array  $existing The map of existing relationships.
64
     * @return bool            Whether the object is new.
65
     */
66
    private function shouldAdd(
67
        object $relation,
68
        string $from,
69
        array $existing
70
    ): bool {
71
        return !isset($existing[$from])
72
            || !in_array($relation, $existing[$from], true);
73
    }
74
75
    /**
76
     * Makes collections for the relationship.
77
     *
78
     * @param string  $from The label of the entity we connect from.
79
     * @param array[] $many The objects to connect with.
80
     *
81
     * @return array        The collections as [string id => array|object collection]
82
     * @throws UnmappableRelationship
83
     */
84
    private function makeCollections(string $from, array $many): array
85
    {
86
        $collections = [];
87
        foreach ($many as $id => $relatedObjects) {
88
            try {
89
                $collections[$id] = $this->collection->fromArray($relatedObjects);
90
            } catch (CannotHydrate $exception) {
91
                throw UnmappableRelationship::encountered($exception, $this->property, $from, $id);
92
            }
93
        }
94
        return $collections;
95
    }
96
}
97