Completed
Pull Request — master (#104)
by Toby
63:48 queued 61:47
created

Resource   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 390
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 92.25%

Importance

Changes 0
Metric Value
wmc 45
lcom 1
cbo 6
dl 0
loc 390
ccs 119
cts 129
cp 0.9225
rs 8.3673
c 0
b 0
f 0

24 Methods

Rating   Name   Duplication   Size   Complexity  
A getType() 0 4 1
A getUnfilteredRelationships() 0 4 1
A getRelationshipsAsArray() 0 8 1
A convertRelationshipsToArray() 0 6 1
A getData() 0 4 1
A __construct() 0 5 1
A getResources() 0 4 1
F toArray() 0 40 9
A isIdentifier() 0 4 2
A toIdentifier() 0 17 3
A getId() 0 8 3
A getAttributes() 0 10 1
A getOwnFields() 0 8 2
A filterFields() 0 8 2
A mergeAttributes() 0 8 2
A getRelationships() 0 6 1
B buildRelationships() 0 25 5
A mergeRelationships() 0 8 2
A merge() 0 4 1
A with() 0 8 1
A fields() 0 6 1
A setData() 0 4 1
A getSerializer() 0 4 1
A setSerializer() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like Resource often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Resource, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * This file is part of JSON-API.
5
 *
6
 * (c) Toby Zerner <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Tobscure\JsonApi;
13
14
class Resource implements ElementInterface
15
{
16
    use LinksTrait;
17
    use MetaTrait;
18
19
    /**
20
     * @var mixed
21
     */
22
    protected $data;
23
24
    /**
25
     * @var \Tobscure\JsonApi\SerializerInterface
26
     */
27
    protected $serializer;
28
29
    /**
30
     * A list of relationships to include.
31
     *
32
     * @var array
33
     */
34
    protected $includes = [];
35
36
    /**
37
     * A list of fields to restrict to.
38
     *
39
     * @var array|null
40
     */
41
    protected $fields;
42
43
    /**
44
     * An array of Resources that should be merged into this one.
45
     *
46
     * @var \Tobscure\JsonApi\Resource[]
47
     */
48
    protected $merged = [];
49
50
    /**
51
     * @var \Tobscure\JsonApi\Relationship[]
52
     */
53
    private $relationships;
54
55
    /**
56
     * @param mixed $data
57
     * @param \Tobscure\JsonApi\SerializerInterface $serializer
58
     */
59 42
    public function __construct($data, SerializerInterface $serializer)
60
    {
61 42
        $this->data = $data;
62 42
        $this->serializer = $serializer;
63 42
    }
64
65
    /**
66
     * {@inheritdoc}
67
     */
68 6
    public function getResources()
69
    {
70 6
        return [$this];
71
    }
72
73
    /**
74
     * {@inheritdoc}
75
     */
76 30
    public function toArray()
77
    {
78 30
        $array = $this->toIdentifier();
79
80 30
        if (! $this->isIdentifier()) {
81 30
            $array['attributes'] = $this->getAttributes();
82 30
        }
83
84 30
        $relationships = $this->getRelationshipsAsArray();
85
86 30
        if (count($relationships)) {
87 12
            $array['relationships'] = $relationships;
88 12
        }
89
90 30
        $links = [];
91 30
        if (! empty($this->links)) {
92 3
            $links = $this->links;
93 3
        }
94 30
        $serializerLinks = $this->serializer->getLinks($this->data);
95 30
        if (! empty($serializerLinks)) {
96 9
            $links = array_merge($serializerLinks, $links);
97 9
        }
98 30
        if (! empty($links)) {
99 9
            $array['links'] = $links;
100 9
        }
101
102 30
        $meta = [];
103 30
        if (! empty($this->meta)) {
104 3
            $meta = $this->meta;
105 3
        }
106 30
        $serializerMeta = $this->serializer->getMeta($this->data);
107 30
        if (! empty($serializerMeta)) {
108 9
            $meta = array_merge($serializerMeta, $meta);
109 9
        }
110 30
        if (! empty($meta)) {
111 9
            $array['meta'] = $meta;
112 9
        }
113
114 30
        return $array;
115
    }
116
117
    /**
118
     * Check whether or not this resource is an identifier (i.e. does it have
119
     * any data attached?).
120
     *
121
     * @return bool
122
     */
123 30
    public function isIdentifier()
124
    {
125 30
        return ! is_object($this->data) && ! is_array($this->data);
126
    }
127
128
    /**
129
     * {@inheritdoc}
130
     */
131 36
    public function toIdentifier()
132
    {
133 36
        if (! $this->data) {
134 3
            return;
135
        }
136
137
        $array = [
138 36
            'type' => $this->getType(),
139 36
            'id' => $this->getId()
140 36
        ];
141
142 36
        if (! empty($this->meta)) {
143 6
            $array['meta'] = $this->meta;
144 6
        }
145
146 36
        return $array;
147
    }
148
149
    /**
150
     * Get the resource type.
151
     *
152
     * @return string
153
     */
154 36
    public function getType()
155
    {
156 36
        return $this->serializer->getType($this->data);
157
    }
158
159
    /**
160
     * Get the resource ID.
161
     *
162
     * @return string
163
     */
164 42
    public function getId()
165
    {
166 42
        if (! is_object($this->data) && ! is_array($this->data)) {
167 6
            return (string) $this->data;
168
        }
169
170 39
        return (string) $this->serializer->getId($this->data);
171
    }
172
173
    /**
174
     * Get the resource attributes.
175
     *
176
     * @return array
177
     */
178 30
    public function getAttributes()
179
    {
180 30
        $attributes = (array) $this->serializer->getAttributes($this->data, $this->getOwnFields());
181
182 30
        $attributes = $this->filterFields($attributes);
183
184 30
        $attributes = $this->mergeAttributes($attributes);
185
186 30
        return $attributes;
187
    }
188
189
    /**
190
     * Get the requested fields for this resource type.
191
     *
192
     * @return array|null
193
     */
194 30
    protected function getOwnFields()
195
    {
196 30
        $type = $this->getType();
197
198 30
        if (isset($this->fields[$type])) {
199 3
            return $this->fields[$type];
200
        }
201 27
    }
202
203
    /**
204
     * Filter the given fields array (attributes or relationships) according
205
     * to the requested fieldset.
206
     *
207
     * @param array $fields
208
     *
209
     * @return array
210
     */
211 30
    protected function filterFields(array $fields)
212
    {
213 30
        if ($requested = $this->getOwnFields()) {
214 3
            $fields = array_intersect_key($fields, array_flip($requested));
215 3
        }
216
217 30
        return $fields;
218
    }
219
220
    /**
221
     * Merge the attributes of merged resources into an array of attributes.
222
     *
223
     * @param array $attributes
224
     *
225
     * @return array
226
     */
227 30
    protected function mergeAttributes(array $attributes)
228
    {
229 30
        foreach ($this->merged as $resource) {
230 3
            $attributes = array_replace_recursive($attributes, $resource->getAttributes());
231 30
        }
232
233 30
        return $attributes;
234
    }
235
236
    /**
237
     * Get the resource relationships.
238
     *
239
     * @return \Tobscure\JsonApi\Relationship[]
240
     */
241 30
    public function getRelationships()
242
    {
243 30
        $relationships = $this->buildRelationships();
244
245 30
        return $this->filterFields($relationships);
246
    }
247
248
    /**
249
     * Get the resource relationships without considering requested ones.
250
     *
251
     * @return \Tobscure\JsonApi\Relationship[]
252
     */
253 6
    public function getUnfilteredRelationships()
254
    {
255 6
        return $this->buildRelationships();
256
    }
257
258
    /**
259
     * Get the resource relationships as an array.
260
     *
261
     * @return array
262
     */
263 30
    public function getRelationshipsAsArray()
264
    {
265 30
        $relationships = $this->getRelationships();
266
267 30
        $relationships = $this->convertRelationshipsToArray($relationships);
268
269 30
        return $this->mergeRelationships($relationships);
270
    }
271
272
    /**
273
     * Get an array of built relationships.
274
     *
275
     * @return \Tobscure\JsonApi\Relationship[]
276
     */
277 30
    protected function buildRelationships()
278
    {
279 30
        if (isset($this->relationships)) {
280 9
            return $this->relationships;
281
        }
282
283 30
        $paths = Util::parseRelationshipPaths($this->includes);
284
285 30
        $relationships = [];
286
287 30
        foreach ($paths as $name => $nested) {
288 12
            $relationship = $this->serializer->getRelationship($this->data, $name);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $relationship is correct as $this->serializer->getRe...hip($this->data, $name) (which targets Tobscure\JsonApi\Seriali...face::getRelationship()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
289
290 12
            if ($relationship) {
291 12
                $relationshipData = $relationship->getData();
292 12
                if ($relationshipData instanceof ElementInterface) {
293 12
                    $relationshipData->with($nested)->fields($this->fields);
294 12
                }
295
296 12
                $relationships[$name] = $relationship;
297 12
            }
298 30
        }
299
300 30
        return $this->relationships = $relationships;
301
    }
302
303
    /**
304
     * Merge the relationships of merged resources into an array of
305
     * relationships.
306
     *
307
     * @param array $relationships
308
     *
309
     * @return array
310
     */
311 30
    protected function mergeRelationships(array $relationships)
312
    {
313 30
        foreach ($this->merged as $resource) {
314 3
            $relationships = array_replace_recursive($relationships, $resource->getRelationshipsAsArray());
315 30
        }
316
317 30
        return $relationships;
318
    }
319
320
    /**
321
     * Convert the given array of Relationship objects into an array.
322
     *
323
     * @param \Tobscure\JsonApi\Relationship[] $relationships
324
     *
325
     * @return array
326
     */
327
    protected function convertRelationshipsToArray(array $relationships)
328
    {
329 30
        return array_map(function (Relationship $relationship) {
330 12
            return $relationship->toArray();
331 30
        }, $relationships);
332
    }
333
334
    /**
335
     * Merge a resource into this one.
336
     *
337
     * @param \Tobscure\JsonApi\Resource $resource
338
     *
339
     * @return void
340
     */
341 3
    public function merge(Resource $resource)
342
    {
343 3
        $this->merged[] = $resource;
344 3
    }
345
346
    /**
347
     * {@inheritdoc}
348
     */
349 12
    public function with($relationships)
350
    {
351 12
        $this->includes = array_unique(array_merge($this->includes, (array) $relationships));
352
353 12
        $this->relationships = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array<integer,object<Tob...\JsonApi\Relationship>> of property $relationships.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
354
355 12
        return $this;
356
    }
357
358
    /**
359
     * {@inheritdoc}
360
     */
361 12
    public function fields($fields)
362
    {
363 12
        $this->fields = $fields;
364
365 12
        return $this;
366
    }
367
368
    /**
369
     * @return mixed
370
     */
371
    public function getData()
372
    {
373
        return $this->data;
374
    }
375
376
    /**
377
     * @param mixed $data
378
     *
379
     * @return void
380
     */
381
    public function setData($data)
382
    {
383
        $this->data = $data;
384
    }
385
386
    /**
387
     * @return \Tobscure\JsonApi\SerializerInterface
388
     */
389
    public function getSerializer()
390
    {
391
        return $this->serializer;
392
    }
393
394
    /**
395
     * @param \Tobscure\JsonApi\SerializerInterface $serializer
396
     *
397
     * @return void
398
     */
399
    public function setSerializer(SerializerInterface $serializer)
400
    {
401
        $this->serializer = $serializer;
402
    }
403
}
404