Relationship::that()   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
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Stratadox\Hydration\Mapper\Instruction\Relation;
5
6
use Stratadox\Hydration\Mapper\Mapper;
7
use Stratadox\Hydration\Mapping\Property\Check;
8
use Stratadox\HydrationMapper\DefinesRelationships;
9
use Stratadox\HydrationMapper\FindsKeys;
10
use Stratadox\HydrationMapper\InstructsHowToMap;
11
use Stratadox\HydrationMapper\InvalidMapperConfiguration;
12
use Stratadox\HydrationMapper\RepresentsChoice;
13
use Stratadox\HydrationMapping\MapsProperty;
14
use Stratadox\Hydrator\Hydrates;
15
use Stratadox\Hydrator\OneOfTheseHydrators;
16
use Stratadox\Proxy\ProducesProxyLoaders;
17
use function assert;
18
use Stratadox\Specification\Contract\Satisfiable;
19
20
/**
21
 * Defines a relationship with another class.
22
 *
23
 * @package Stratadox\Hydrate
24
 * @author  Stratadox
25
 */
26
abstract class Relationship implements DefinesRelationships
27
{
28
    /** @var string */
29
    protected $class;
30
31
    /** @var FindsKeys|null */
32
    protected $key;
33
34
    /** @var string|null */
35
    protected $container;
36
37
    /** @var ProducesProxyLoaders|null */
38
    protected $loader;
39
40
    /** @var bool */
41
    protected $shouldNest = false;
42
43
    /** @var (InstructsHowToMap|null)[] */
44
    protected $properties = [];
45
46
    /** @var string|null */
47
    protected $decisionKey;
48
49
    /** @var RepresentsChoice[] */
50
    protected $choices = [];
51
52
    /** @var Satisfiable|null */
53
    protected $constraint;
54
55
    private function __construct(string $class, FindsKeys $key = null)
56
    {
57
        $this->class = $class;
58
        $this->key = $key;
59
    }
60
61
    /**
62
     * Defines a new relationship with another class.
63
     *
64
     * @param string         $class The fully qualified class name.
65
     * @param FindsKeys|null $key   The input array offset (optional)
66
     * @return DefinesRelationships The relationship definition.
67
     */
68
    public static function ofThe(
69
        string $class,
70
        FindsKeys $key = null
71
    ): DefinesRelationships {
72
        return new static($class, $key);
73
    }
74
75
    /** @inheritdoc */
76
    public function containedInA(string $container): DefinesRelationships
77
    {
78
        $inst = clone $this;
79
        $inst->container = $container;
80
        return $inst;
81
    }
82
83
    /** @inheritdoc */
84
    public function loadedBy(ProducesProxyLoaders $loader): DefinesRelationships
85
    {
86
        $inst = clone $this;
87
        $inst->loader = $loader;
88
        return $inst;
89
    }
90
91
    /** @inheritdoc */
92
    public function nested(): DefinesRelationships
93
    {
94
        $inst = clone $this;
95
        $inst->shouldNest = true;
96
        return $inst;
97
    }
98
99
    /** @inheritdoc */
100
    public function with(
101
        string $property,
102
        InstructsHowToMap $instruction = null
103
    ): DefinesRelationships {
104
        $inst = clone $this;
105
        $inst->properties += [$property => $instruction];
106
        return $inst;
107
    }
108
109
    /** @inheritdoc */
110
    public function selectBy(
111
        string $decisionKey,
112
        array $choices
113
    ): DefinesRelationships {
114
        $inst = clone $this;
115
        $inst->decisionKey = $decisionKey;
116
        $inst->choices = $choices;
117
        return $inst;
118
    }
119
120
    public function that(Satisfiable $constraint): InstructsHowToMap
121
    {
122
        $inst = clone $this;
123
        $inst->constraint = $constraint;
124
        return $inst;
125
    }
126
127
    /**
128
     * Returns the key if one was provided, defaulting to the property name.
129
     *
130
     * @param string $property The property name to use as fallback.
131
     * @return string          The key to use as offset for the input data.
132
     */
133
    protected function keyOr(string $property): string
134
    {
135
        return $this->key ? $this->key->find() : $property;
136
    }
137
138
    /**
139
     * Produces a mapped hydrator according to the relationship configuration.
140
     *
141
     * @return Hydrates The hydrator for the relationship mapping.
142
     * @throws InvalidMapperConfiguration
143
     */
144
    protected function hydrator(): Hydrates
145
    {
146
        if (isset($this->decisionKey)) {
147
            return $this->choiceHydrator();
148
        }
149
        $mapped = Mapper::forThe($this->class);
150
        foreach ($this->properties as $property => $instruction) {
151
            $mapped = $mapped->property($property, $instruction);
152
        }
153
        return $mapped->finish();
154
    }
155
156
    protected function addConstraintTo(MapsProperty $mapping): MapsProperty
157
    {
158
        if (isset($this->constraint)) {
159
            $mapping = Check::that($this->constraint, $mapping);
160
        }
161
        return $mapping;
162
    }
163
164
    /**
165
     * Produces a multiple-choice hydrator.
166
     *
167
     * @return Hydrates The adapter that selects the hydrator.
168
     * @throws InvalidMapperConfiguration
169
     */
170
    private function choiceHydrator(): Hydrates
171
    {
172
        assert(isset($this->decisionKey));
173
        return OneOfTheseHydrators::decideBasedOnThe(
174
            $this->decisionKey,
0 ignored issues
show
Bug introduced by
It seems like $this->decisionKey can also be of type null; however, parameter $key of Stratadox\Hydrator\OneOf...ors::decideBasedOnThe() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

174
            /** @scrutinizer ignore-type */ $this->decisionKey,
Loading history...
175
            array_map(function (RepresentsChoice $choice): Hydrates {
176
                return $choice->finish();
177
            }, $this->choices)
178
        );
179
    }
180
}
181