Completed
Pull Request — MetadataImplementationStep (#116)
by Alex
01:49
created

EntityGubbins::getAssociations()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 1
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
3
namespace AlgoWeb\PODataLaravel\Models\ObjectMap\Entities;
4
5
use AlgoWeb\PODataLaravel\Models\ObjectMap\Entities\Associations\Association;
6
use AlgoWeb\PODataLaravel\Models\ObjectMap\Entities\Associations\AssociationMonomorphic;
7
use AlgoWeb\PODataLaravel\Models\ObjectMap\Entities\Associations\AssociationPolymorphic;
8
use AlgoWeb\PODataLaravel\Models\ObjectMap\Entities\Associations\AssociationStubBase;
9
use AlgoWeb\PODataLaravel\Models\ObjectMap\Entities\Associations\AssociationStubPolymorphic;
10
use POData\Providers\Metadata\ResourceEntityType;
11
12
class EntityGubbins
13
{
14
    /**
15
     * @var string
16
     */
17
    private $name;
18
19
    /**
20
     * @var string
21
     */
22
    private $className;
23
24
    /**
25
     * @var EntityField[]
26
     */
27
    private $keyFields;
28
29
    /**
30
     * @var EntityField[]
31
     */
32
    private $fields;
33
34
    /**
35
     * @var AssociationStubBase[]
36
     */
37
    private $stubs;
38
39
    /**
40
     * @var Association[]
41
     */
42
    private $associations;
43
    /**
44
     * @var ResourceEntityType
45
     */
46
    private $odataResourceType;
47
    /**
48
     * @var bool|null
49
     */
50
    private $isPolymorphicAffected = null;
51
52
    //TODO: move the checking part of this to the set stubs method.
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
53
    public function isPolymorphicAffected()
54
    {
55
        if (null !== $this->isPolymorphicAffected) {
56
            return $this->isPolymorphicAffected;
57
        }
58
        $this->isPolymorphicAffected = false;
59
        foreach ($this->stubs as $stub) {
60
            if (!$stub instanceof AssociationStubPolymorphic) {
61
                continue;
62
            }
63
            if (null !== $stub->getTargType()) {
64
                $this->isPolymorphicAffected = true;
65
                break;
66
            }
67
        }
68
        return $this->isPolymorphicAffected;
69
    }
70
71
    /**
72
     * @return ResourceEntityType
73
     */
74
    public function getOdataResourceType()
75
    {
76
        return $this->odataResourceType;
77
    }
78
79
    /**
80
     * @param ResourceEntityType $odataType
81
     */
82
    public function setOdataResourceType(ResourceEntityType $odataType)
83
    {
84
        if ($odataType->isAbstract()) {
85
            $msg = 'OData resource entity type must be concrete';
86
            throw new \InvalidArgumentException($msg);
87
        }
88
        $this->odataResourceType = $odataType;
89
    }
90
91
    /**
92
     * @return string
93
     */
94
    public function getName()
95
    {
96
        return $this->name;
97
    }
98
99
    /**
100
     * @param string $name
101
     */
102
    public function setName($name)
103
    {
104
        $this->name = $name;
105
    }
106
107
    /**
108
     * @return string
109
     */
110
    public function getClassName()
111
    {
112
        return $this->className;
113
    }
114
115
    /**
116
     * @param string $className
117
     */
118
    public function setClassName($className)
119
    {
120
        $this->className = $className;
121
    }
122
123
    /**
124
     * @return EntityField[]
125
     */
126
    public function getKeyFields()
127
    {
128
        return $this->keyFields;
129
    }
130
131
    /**
132
     * @return EntityField[]
133
     */
134
    public function getFields()
135
    {
136
        return $this->fields;
137
    }
138
139
    /**
140
     * @param EntityField[] $fields
141
     */
142
    public function setFields(array $fields)
143
    {
144
        if (0 == count($fields)) {
145
            $msg = 'Fields array must not be empty';
146
            throw new \Exception($msg);
147
        }
148
        $keys = [];
149
        foreach ($fields as $propName => $field) {
150
            if (!$field instanceof EntityField) {
151
                $msg = 'Fields array must only have EntityField objects';
152
                throw new \Exception($msg);
153
            }
154
            if ($field->getIsKeyField()) {
155
                $keys[$propName] = $field;
156
            }
157
        }
158
        if (0 == count($keys)) {
159
            $msg = 'No key field supplied in fields array';
160
            throw new \Exception($msg);
161
        }
162
        $this->fields = $fields;
163
        $this->keyFields = $keys;
164
    }
165
166
    /**
167
     * @return AssociationStubBase[]
168
     */
169
    public function getStubs()
170
    {
171
        return $this->stubs;
172
    }
173
174
    /**
175
     * @param AssociationStubBase[] $stubs
176
     */
177
    public function setStubs(array $stubs)
178
    {
179
        foreach ($stubs as $field) {
180
            if (!$field instanceof AssociationStubBase) {
181
                $msg = 'Stubs array must only have AssociationStubBase objects';
182
                throw new \Exception($msg);
183
            }
184
        }
185
        $this->stubs = $stubs;
186
    }
187
188
    /**
189
     * @param Association $association
190
     * @param bool        $isFirst
191
     */
192
    public function addAssociation(Association $association, $isFirst = true)
193
    {
194
        if ($association instanceof AssociationMonomorphic) {
195
            $stub = $isFirst ? $association->getFirst() : $association->getLast();
196
            if (null === $stub || !in_array($stub, $this->stubs)) {
197
                throw new \InvalidArgumentException('Association cannot be connected to this entity');
198
            }
199
            $propertyName = $stub->getRelationName();
200
        } elseif ($association instanceof AssociationPolymorphic) {
201
            if ($isFirst) {
202
                $stub = $association->getFirst();
203
                if (!in_array($stub, $this->stubs)) {
204
                    throw new \InvalidArgumentException('Association cannot be connected to this entity');
205
                }
206
            } else {
207
                $comp = function (AssociationStubBase $one, AssociationStubBase $two) {
208
                    return $one->compare($two);
209
                };
210
                $stubs = $association->getLast();
211
                assert(is_array($stubs));
212
                assert(is_array($this->stubs));
213
                $inter = array_uintersect(array_values($stubs), array_values($this->stubs), $comp);
214
                if (1 !== count($inter)) {
215
                    throw new \InvalidArgumentException('Association cannot be connected to this entity');
216
                }
217
                $stub = array_values($inter)[0];
218
            }
219
            $propertyName = $stub->getRelationName();
220
        }
221
        assert(isset($propertyName));
222
        $this->associations[$propertyName] = $association;
0 ignored issues
show
Bug introduced by
The variable $propertyName does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
223
    }
224
225
    /**
226
     * @return String[]
227
     */
228
    protected function getFieldNames()
229
    {
230
        $fieldNames = [];
231
        foreach ($this->fields as $field) {
232
            $fieldNames[] = $field->getName();
233
        }
234
        return $fieldNames;
235
    }
236
237
    /**
238
     * @return String[]
239
     */
240
    protected function getAssociationNames()
241
    {
242
        if (empty($this->stubs)) {
243
            return [];
244
        }
245
        $assocationNames = [];
246
        foreach ($this->stubs as $stub) {
247
            $assocationNames[] = $stub->getRelationName();
248
        }
249
        return $assocationNames;
250
    }
251
252
    /**
253
     * @return Associations\Association[]
254
     */
255
    public function getAssociations()
256
    {
257
        return $this->associations;
258
    }
259
260
    public function resolveAssociation($relName)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
261
    {
262
        $this->associations = is_array($this->associations) ? $this->associations : [];
263
        return array_key_exists($relName, $this->associations) ? $this->associations[$relName] : null;
264
    }
265
266
    /**
267
     * @return bool
268
     */
269
    public function isOK()
270
    {
271
        $fieldNames = $this->getFieldNames();
272
        $associationNames = $this->getAssociationNames();
273
        $intersection = array_intersect($fieldNames, $associationNames);
274
        return 0 === count($intersection);
275
    }
276
}
277