Completed
Push — master ( ae75f4...5b5380 )
by Toby
67:07
created

Resource::toArray()   B

Complexity

Conditions 5
Paths 16

Size

Total Lines 26
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 3
Metric Value
c 3
b 0
f 3
dl 0
loc 26
rs 8.439
cc 5
eloc 15
nc 16
nop 0
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 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 Resource[]
47
     */
48
    protected $merged = [];
49
50
    /**
51
     * @param mixed $data
52
     * @param SerializerInterface $serializer
53
     */
54
    public function __construct($data, SerializerInterface $serializer)
55
    {
56
        $this->data = $data;
57
        $this->serializer = $serializer;
58
    }
59
60
    /**
61
     * {@inheritdoc}
62
     */
63
    public function getResources()
64
    {
65
        return [$this];
66
    }
67
68
    /**
69
     * {@inheritdoc}
70
     */
71
    public function toArray()
72
    {
73
        $array = $this->toIdentifier();
74
75
        $array['attributes'] = $this->getAttributes();
76
77
        $relationships = $this->getRelationshipsAsArray();
78
79
        if (count($relationships)) {
80
            $array['relationships'] = $relationships;
81
        }
82
83
        $links = [];
84
        if (! empty($this->links)) {
85
            $links = $this->links;
86
        }
87
        $serializerLinks = $this->serializer->getLinks($this->data);
88
        if (! empty($serializerLinks)) {
89
            $links = array_merge($serializerLinks, $links);
90
        }
91
        if (! empty($links)) {
92
            $array['links'] = $links;
93
        }
94
95
        return $array;
96
    }
97
98
    /**
99
     * Check whether or not this resource is an identifier (i.e. does it have
100
     * any data attached?).
101
     *
102
     * @return bool
103
     */
104
    public function isIdentifier()
105
    {
106
        return ! is_object($this->data) && ! is_array($this->data);
107
    }
108
109
    /**
110
     * {@inheritdoc}
111
     */
112
    public function toIdentifier()
113
    {
114
        $array = [
115
            'type' => $this->getType(),
116
            'id' => $this->getId()
117
        ];
118
119
        if (! empty($this->meta)) {
120
            $array['meta'] = $this->meta;
121
        }
122
123
        return $array;
124
    }
125
126
    /**
127
     * Get the resource type.
128
     *
129
     * @return string
130
     */
131
    public function getType()
132
    {
133
        return $this->serializer->getType($this->data);
134
    }
135
136
    /**
137
     * Get the resource ID.
138
     *
139
     * @return string
140
     */
141
    public function getId()
142
    {
143
        if (! is_object($this->data) && ! is_array($this->data)) {
144
            return (string) $this->data;
145
        }
146
147
        return (string) $this->serializer->getId($this->data);
148
    }
149
150
    /**
151
     * Get the resource attributes.
152
     *
153
     * @return array
154
     */
155
    public function getAttributes()
156
    {
157
        $attributes = (array) $this->serializer->getAttributes($this->data, $this->getOwnFields());
158
159
        $attributes = $this->filterFields($attributes);
160
161
        $attributes = $this->mergeAttributes($attributes);
162
163
        return $attributes;
164
    }
165
166
    /**
167
     * Get the requested fields for this resource type.
168
     *
169
     * @return array|null
170
     */
171
    protected function getOwnFields()
172
    {
173
        $type = $this->getType();
174
175
        if (isset($this->fields[$type])) {
176
            return $this->fields[$type];
177
        }
178
    }
179
180
    /**
181
     * Filter the given fields array (attributes or relationships) according
182
     * to the requested fieldset.
183
     *
184
     * @param array $fields
185
     * @return array
186
     */
187
    protected function filterFields(array $fields)
188
    {
189
        if ($requested = $this->getOwnFields()) {
190
            $fields = array_intersect_key($fields, array_flip($requested));
191
        }
192
193
        return $fields;
194
    }
195
196
    /**
197
     * Merge the attributes of merged resources into an array of attributes.
198
     *
199
     * @param array $attributes
200
     * @return array
201
     */
202
    protected function mergeAttributes(array $attributes)
203
    {
204
        foreach ($this->merged as $resource) {
205
            $attributes = array_replace_recursive($attributes, $resource->getAttributes());
0 ignored issues
show
Bug introduced by
The method getAttributes cannot be called on $resource (of type resource).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
206
        }
207
208
        return $attributes;
209
    }
210
211
    /**
212
     * Get the resource relationships.
213
     *
214
     * @return Relationship[]
215
     */
216
    public function getRelationships()
217
    {
218
        $relationships = $this->buildRelationships();
219
220
        return $this->filterFields($relationships);
221
    }
222
223
    /**
224
     * Get the resource relationships without considering requested ones.
225
     *
226
     * @return Relationship[]
227
     */
228
    public function getUnfilteredRelationships()
229
    {
230
        return $this->buildRelationships();
231
    }
232
233
    /**
234
     * Get the resource relationships as an array.
235
     *
236
     * @return array
237
     */
238
    public function getRelationshipsAsArray()
239
    {
240
        $relationships = $this->getRelationships();
241
242
        $relationships = $this->convertRelationshipsToArray($relationships);
243
244
        return $this->mergeRelationships($relationships);
245
    }
246
247
    /**
248
     * Get an array of built relationships.
249
     *
250
     * @return Relationship[]
251
     */
252
    protected function buildRelationships()
253
    {
254
        $paths = Util::parseRelationshipPaths($this->includes);
255
256
        $relationships = [];
257
258
        foreach ($paths as $name => $nested) {
259
            $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...
260
261
            if ($relationship) {
262
                $relationship->getData()->with($nested)->fields($this->fields);
263
264
                $relationships[$name] = $relationship;
265
            }
266
        }
267
268
        return $relationships;
269
    }
270
271
    /**
272
     * Merge the relationships of merged resources into an array of
273
     * relationships.
274
     *
275
     * @param array $relationships
276
     * @return array
277
     */
278
    protected function mergeRelationships(array $relationships)
279
    {
280
        foreach ($this->merged as $resource) {
281
            $relationships = array_replace_recursive($relationships, $resource->getRelationshipsAsArray());
0 ignored issues
show
Bug introduced by
The method getRelationshipsAsArray cannot be called on $resource (of type resource).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
282
        }
283
284
        return $relationships;
285
    }
286
287
    /**
288
     * Convert the given array of Relationship objects into an array.
289
     *
290
     * @param Relationship[] $relationships
291
     * @return array
292
     */
293
    protected function convertRelationshipsToArray(array $relationships)
294
    {
295
        return array_map(function (Relationship $relationship) {
296
            return $relationship->toArray();
297
        }, $relationships);
298
    }
299
300
    /**
301
     * Merge a resource into this one.
302
     *
303
     * @param Resource $resource
304
     */
305
    public function merge(Resource $resource)
306
    {
307
        $this->merged[] = $resource;
308
    }
309
310
    /**
311
     * {@inheritdoc}
312
     */
313
    public function with($relationships)
314
    {
315
        $this->includes = array_unique(array_merge($this->includes, (array) $relationships));
316
317
        return $this;
318
    }
319
320
    /**
321
     * {@inheritdoc}
322
     */
323
    public function fields($fields)
324
    {
325
        $this->fields = $fields;
326
327
        return $this;
328
    }
329
330
    /**
331
     * @return mixed
332
     */
333
    public function getData()
334
    {
335
        return $this->data;
336
    }
337
338
    /**
339
     * @param mixed $data
340
     */
341
    public function setData($data)
342
    {
343
        $this->data = $data;
344
    }
345
346
    /**
347
     * @return SerializerInterface
348
     */
349
    public function getSerializer()
350
    {
351
        return $this->serializer;
352
    }
353
354
    /**
355
     * @param SerializerInterface $serializer
356
     */
357
    public function setSerializer(SerializerInterface $serializer)
358
    {
359
        $this->serializer = $serializer;
360
    }
361
}
362