InCase::labeled()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace Stratadox\TableLoader\Builder;
5
6
use function array_merge;
7
use function count;
8
use function is_null;
9
use Stratadox\Hydration\Mapper\Mapper;
10
use Stratadox\Hydrator\ArrayHydrator;
11
use Stratadox\Hydrator\Hydrates;
12
use Stratadox\Hydrator\SimpleHydrator;
13
use Stratadox\Hydrator\VariadicConstructor;
14
use Stratadox\TableLoader\Loader\From;
15
use Stratadox\TableLoader\Loader\HasMany;
16
use Stratadox\TableLoader\Loader\HasOne;
17
use Stratadox\TableLoader\Loader\Identified;
18
use Stratadox\TableLoader\Loader\WiresObjects;
19
use Stratadox\TableLoader\Loader\To;
20
use Stratadox\TableLoader\Loader\Wire;
21
use Stratadox\TableLoader\Loader\Wired;
22
23
/**
24
 * Builds the required infrastructure to produce a particular subclass.
25
 * @see Decide
26
 *
27
 * @author Stratadox
28
 */
29
final class InCase implements LoadsWhenTriggered
30
{
31
    private $trigger;
32
    private $class;
33
    private $identityColumnsFor = [];
34
    private $properties = [];
35
    private $relation = [];
36
    private $label;
37
38
    private function __construct(string $trigger)
39
    {
40
        $this->trigger = $trigger;
41
    }
42
43
    public static function of(
44
        string $trigger
45
    ): LoadsWhenTriggered {
46
        return new self($trigger);
47
    }
48
49
    /** @inheritdoc */
50
    public function as(
51
        string $class,
52
        array $properties = []
53
    ): LoadsWhenTriggered {
54
        $new = clone $this;
55
        $new->class = $class;
56
        $new->properties = $properties;
57
        return $new;
58
    }
59
60
    /** @inheritdoc */
61
    public function with(array $properties): LoadsWhenTriggered
62
    {
63
        $new = clone $this;
64
        $new->properties = array_merge($this->properties, $properties);
65
        return $new;
66
    }
67
68
    /** @inheritdoc */
69
    public function havingOne(
70
        string $property,
71
        string $label = null
72
    ): LoadsWhenTriggered {
73
        $new = clone $this;
74
        $new->relation[$label ?: $property] = HasOne::in($property);
75
        return $new;
76
    }
77
78
    /** @inheritdoc */
79
    public function havingMany(
80
        string $property,
81
        string $label,
82
        string $collectionClass = null
83
    ): LoadsWhenTriggered {
84
        $hydrator = $collectionClass ?
85
            VariadicConstructor::forThe($collectionClass) :
86
            ArrayHydrator::create();
87
        $new = clone $this;
88
        $new->relation[$label] = HasMany::in($property, $hydrator);
89
        return $new;
90
    }
91
92
    /** @inheritdoc */
93
    public function identifying(
94
        string $label,
95
        string ...$columns
96
    ): LoadsWhenTriggered {
97
        $new = clone $this;
98
        $new->identityColumnsFor[$label] = $columns;
99
        return $new;
100
    }
101
102
    /** @inheritdoc */
103
    public function labeled(string $label): LoadsWhenTriggered
104
    {
105
        $new = clone $this;
106
        $new->label = $label;
107
        return $new;
108
    }
109
110
    /** @inheritdoc */
111
    public function decisionTrigger(): string
112
    {
113
        return $this->trigger;
114
    }
115
116
    /** @inheritdoc */
117
    public function hydrator(): Hydrates
118
    {
119
        if (empty($this->properties)) {
120
            return SimpleHydrator::forThe($this->class);
121
        }
122
        $mapper = Mapper::forThe($this->class);
123
        foreach ($this->properties as $name => $instruction) {
124
            $mapper = $mapper->property($name, $instruction);
125
        }
126
        return $mapper->finish();
127
    }
128
129
    /** @inheritdoc */
130
    public function wiring(): WiresObjects
131
    {
132
        $ownLabel = $this->label;
133
        if (is_null($ownLabel)) {
134
            throw CannotMakeMapping::missingTheLabelFor($this->trigger);
135
        }
136
        $ownId = $this->identityColumnsFor[$ownLabel];
137
        $wires = [];
138
        foreach ($this->relation as $otherLabel => $connectThem) {
139
            $this->mustKnowTheIdentityColumnsFor($otherLabel);
140
            $otherId = $this->identityColumnsFor[$otherLabel];
141
            $wires[] = Wire::it(
142
                From::onlyThe($this->class, $ownLabel, Identified::by(...$ownId)),
143
                To::the($otherLabel, Identified::by(...$otherId)),
144
                $connectThem
145
            );
146
        }
147
        if (count($wires) === 1) {
148
            return $wires[0];
149
        }
150
        return Wired::together(...$wires);
151
    }
152
153
    /** @throws CannotMakeTableMapping */
154
    private function mustKnowTheIdentityColumnsFor(string $label): void
155
    {
156
        if (!isset($this->identityColumnsFor[$label])) {
157
            throw CannotMakeMapping::missingTheIdentityColumns($label, $this->label);
158
        }
159
    }
160
}
161