Passed
Push — serializer ( b735de...a94b6e )
by Alex
03:02
created

JsonApiSerializer::transformIncludedRelations()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 12
rs 9.4285
cc 3
eloc 7
nc 2
nop 0
1
<?php
2
3
namespace Huntie\JsonApi\Serializers;
4
5
use Illuminate\Database\Eloquent\Model;
6
use Illuminate\Support\Collection;
7
8
class JsonApiSerializer
9
{
10
    /**
11
     * The model instance to transform.
12
     *
13
     * @var \Illuminate\Database\Eloquent\Model
14
     */
15
    protected $record;
16
17
    /**
18
     * The relationships to return.
19
     *
20
     * @var array
21
     */
22
    protected $relationships;
23
24
    /**
25
     * The subset of record attributes to return.
26
     *
27
     * @var array
28
     */
29
    protected $fields;
30
31
    /**
32
     * The relationships to load and include.
33
     *
34
     * @var array
35
     */
36
    protected $include;
37
38
    /**
39
     * Meta information to include.
40
     *
41
     * @var \Illuminate\Support\Collection
42
     */
43
    protected $meta;
44
45
    /**
46
     * Resource links to include.
47
     *
48
     * @var \Illuminate\Support\Collection
49
     */
50
    protected $links;
51
52
    /**
53
     * Create a new JSON API resource serializer.
54
     *
55
     * @param Model      $record  The model instance to serialise
56
     * @param array|null $fields  Subset of fields to return
57
     * @param array|null $include Relations to include
58
     */
59
    public function __construct($record, array $fields = [], array $include = [])
60
    {
61
        $this->record = $record;
62
        $this->relationships = array_merge($record->getRelations(), $include);
63
        $this->fields = array_unique($fields);
64
        $this->include = array_unique($include);
65
        $this->meta = collect([]);
66
        $this->links = collect([]);
67
    }
68
69
    /**
70
     * Limit which relations can be included.
71
     *
72
     * @param array $include
73
     */
74
    public function scopeIncludes($include)
75
    {
76
        $this->include = $this->include->intersect($include);
0 ignored issues
show
Bug introduced by
The method intersect cannot be called on $this->include (of type array).

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...
77
    }
78
79
    /**
80
     * Add meta information to the returned object.
81
     *
82
     * @param string|array    $key
83
     * @param string|int|null $value
84
     */
85
    public function addMeta($key, $value = null)
86
    {
87
        $this->meta = $this->meta->merge(is_array($key) ? $key : [$key => $value]);
88
    }
89
90
    /**
91
     * Add one or more links to the returned object.
92
     *
93
     * @param string|array    $key
94
     * @param string|int|null $value
95
     */
96
    public function addLinks($key, $value = null)
97
    {
98
        $this->links = $this->links->merge(is_array($key) ? $key : [$key => $value]);
99
    }
100
101
    /**
102
     * Return a JSON API resource identifier object for the primary record.
103
     *
104
     * @return array
105
     */
106
    public function toResourceIdentifier()
107
    {
108
        return [
109
            'type' => $this->getRecordType(),
110
            'id' => $this->record->id,
111
        ];
112
    }
113
114
    /**
115
     * Return a JSON API resource object for the primary record.
116
     *
117
     * @return array
118
     */
119
    public function toResourceObject()
120
    {
121
        $this->record->load($this->relationships);
122
123
        return array_merge($this->toResourceIdentifier(), array_filter([
124
            'attributes' => $this->transformRecordAttributes(),
125
            'relationships' => $this->transformRecordRelations(),
126
        ]));
127
    }
128
129
    /**
130
     * Serialise complete JSON API document to an array.
131
     *
132
     * @return array
133
     */
134
    public function serialiseToObject()
135
    {
136
        return array_filter([
137
            'data' => $this->toResourceObject(),
138
            'included' => $this->transformIncludedRelations(),
139
            'links' => $this->links->toArray(),
140
            'meta' => $this->meta->toArray(),
141
        ]);
142
    }
143
144
    /**
145
     * Serialise complete JSON API document to a JSON string.
146
     *
147
     * @return array
148
     */
149
    public function serializeToJson()
150
    {
151
        return json_encode($this->serialiseToObject());
152
    }
153
154
    /**
155
     * Return the primary record type name.
156
     *
157
     * @return string
158
     */
159
    protected function getRecordType()
160
    {
161
        return str_slug(str_plural(get_class($this->record)));
162
    }
163
164
    /**
165
     * Return the attribute object data for the primary record.
166
     *
167
     * @return array
168
     */
169
    protected function transformRecordAttributes()
170
    {
171
        $attributes = array_diff_key($this->record->toArray(), $this->record->getRelations());
172
        $attributes = array_except($attributes, ['id']);
173
174
        if (!empty($this->fields)) {
175
            $attributes = array_only($attributes, $this->fields);
176
        }
177
178
        return $attributes;
179
    }
180
181
    /**
182
     * Return a collection of JSON API resource identifier objects by each
183
     * relation on the primary record.
184
     *
185
     * @return array
186
     */
187
    protected function transformRecordRelations()
188
    {
189
        $relationships = [];
190
191
        foreach ($this->relationships as $relation) {
192
            $data = [];
193
194
            if ($this->record->{$relation} instanceof Collection) {
195
                foreach ($this->record->{$relation} as $record) {
196
                    $data[] = (new static($record))->toResourceIdentifier();
197
                }
198
            } else if ($this->record->{$relation} instanceof Model) {
199
                $data = (new static($record))->toResourceIdentifier();
0 ignored issues
show
Bug introduced by
The variable $record seems to be defined by a foreach iteration on line 195. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
200
            }
201
202
            $relationships[$relation] = compact('data');
203
        }
204
205
        return $relationships;
206
    }
207
208
    /**
209
     * Return a collection of JSON API resource objects for each included
210
     * relationship.
211
     *
212
     * @return array
213
     */
214
    protected function transformIncludedRelations()
215
    {
216
        $included = collect([]);
217
218
        foreach ($this->include as $relation) {
219
            $included = $included->merge(array_map(function ($record) {
220
                return $record ? (new static($record))->toResourceObject() : null;
221
            }, (array) $this->record->{$relation}));
222
        }
223
224
        return array_filter($included->toArray());
225
    }
226
}
227