Passed
Push — serializer ( a94b6e...556ef8 )
by Alex
03:01
created

JsonApiSerializer::transformRecordRelations()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 21
rs 9.0534
cc 4
eloc 13
nc 4
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 = array_intersect($this->include, $include);
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
            $relation = $this->record->{$relation};
193
            $data = [];
194
195
            if ($relation instanceof Collection) {
196
                $data = array_map(function ($record) {
197
                    return (new static($record))->toResourceIdentifier();
198
                }, $relation);
199
            } else if ($relation instanceof Model) {
200
                $data = (new static($relation))->toResourceIdentifier();
201
            }
202
203
            $relationships[$relation] = compact('data');
204
        }
205
206
        return $relationships;
207
    }
208
209
    /**
210
     * Return a collection of JSON API resource objects for each included
211
     * relationship.
212
     *
213
     * @return array
214
     */
215
    protected function transformIncludedRelations()
216
    {
217
        $included = collect([]);
218
219
        foreach ($this->include as $relation) {
220
            $included = $included->merge(array_map(function ($record) {
221
                return $record ? (new static($record))->toResourceObject() : null;
222
            }, (array) $this->record->{$relation}));
223
        }
224
225
        return array_filter($included->toArray());
226
    }
227
}
228