Passed
Push — transform-updates ( 4b889b )
by Alex
03:38
created

JsonApiTransforms::transformCollection()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 2
Metric Value
c 4
b 0
f 2
dl 0
loc 25
rs 8.5806
cc 4
eloc 15
nc 6
nop 3
1
<?php
2
3
namespace Huntie\JsonApi\Support;
4
5
use Illuminate\Database\Eloquent\Model;
6
use Illuminate\Pagination\LengthAwarePaginator;
7
use Illuminate\Support\Collection;
8
9
/**
10
 * Transform Eloquent models and collections into JSON API objects.
11
 */
12
trait JsonApiTransforms
13
{
14
    /**
15
     * Transform a model instance into a JSON API object.
16
     *
17
     * @param Model      $record
18
     * @param array|null $fields  Field subset to return
19
     * @param array|null $include Relations to include
20
     *
21
     * @return array
22
     */
23
    protected function transformRecord($record, array $fields = [], array $include = [])
24
    {
25
        $relations = array_unique(array_merge($record->getRelations(), $include));
26
        $record = $record->load($relations);
27
28
        $attributes = $record->toArray();
29
        $relationships = [];
30
        $included = collect([]);
31
32
        foreach ($relations as $relation) {
33
            $relationships[$relation] = $this->transformRelationship($record, $relation);
34
35
            if (in_array($relation, $include)) {
36
                if ($record->{$relation} instanceof Collection) {
37
                    $included->merge($this->transformCollectionSimple($record->{$relation})['data']);
38
                } else if ($record->{$relation} instanceof Model) {
39
                    $included->push($this->transformRecordSimple($record->{$relation})['data']);
40
                }
41
            }
42
        }
43
44
        array_forget($attributes, $relations);
45
        $included = array_filter($included->toArray());
46
47
        if (!empty($fields)) {
48
            $attributes = array_only($attributes, $fields);
49
        }
50
51
        $data = array_filter([
52
            'type' => str_slug($record->getTable()),
53
            'id' => $record->id,
54
            'attributes' => array_except($attributes, ['id']),
55
            'relationships' => $relationships,
56
        ]);
57
58
        return array_filter(compact('data', 'included'));
59
    }
60
61
    /**
62
     * Transform a model instance into a JSON API object without additonal data.
63
     *
64
     * @param Model $record
65
     *
66
     * @return array
67
     */
68
    protected function transformRecordSimple($record)
69
    {
70
        $attributes = array_diff_key($record->toArray(), $record->getRelations());
71
        $attributes = array_except($attributes, ['id']);
72
73
        return [
74
            'data' => [
75
                'type' => str_slug($record->getTable()),
76
                'id' => $record->id,
77
                'attributes' => $attributes,
78
            ]
79
        ];
80
    }
81
82
    /**
83
     * Transform a model instance into a JSON API resource identifier.
84
     *
85
     * @param Model $record
86
     *
87
     * @return array
88
     */
89
    protected function transformRecordIdentifier($record)
90
    {
91
        return [
92
            'data' => [
93
                'type' => str_slug($record->getTable()),
94
                'id' => $record->id,
95
            ]
96
        ];
97
    }
98
99
    /**
100
     * Transform a set of models into a JSON API collection.
101
     *
102
     * @param Collection|LengthAwarePaginator $records
103
     * @param array                           $fields
104
     * @param array|null                      $include
105
     *
106
     * @return array
107
     */
108
    protected function transformCollection($records, array $fields = [], array $include = [])
109
    {
110
        $data = [];
111
        $links = [];
112
        $included = [];
113
114
        foreach ($records as $record) {
115
            $object = $this->transformRecord($record, $fields, $include);
116
117
            if (isset($object['included'])) {
118
                $included = array_merge($included, $object['included']);
119
            }
120
121
            $data[] = $object['data'];
122
        }
123
124
        if ($records instanceof LengthAwarePaginator) {
125
            $links['first'] = $records->url(1);
126
            $links['last'] = $records->url($records->lastPage());
127
            $links['prev'] = $records->previousPageUrl();
128
            $links['next'] = $records->nextPageUrl();
129
        }
130
131
        return array_merge(compact('data'), array_filter(compact('links', 'included')));
132
    }
133
134
    /**
135
     * Transform a set of models into a JSON API collection without additional data.
136
     *
137
     * @param Collection $records
138
     *
139
     * @return array
140
     */
141
    protected function transformCollectionSimple($records)
142
    {
143
        $data = $records->map(function ($record) {
144
            return $this->transformRecordSimple($record)['data'];
145
        })->toArray();
146
147
        return compact('data');
148
    }
149
150
    /**
151
     * Transform a set of models into a collection of JSON API resource
152
     * identifier objects.
153
     *
154
     * @param Collection $records
155
     *
156
     * @return array
157
     */
158
    protected function transformCollectionIdentifiers($records)
159
    {
160
        $data = $records->map(function ($record) {
161
            return $this->transformRecordIdentifier($record)['data'];
162
        });
163
164
        return compact('data');
165
    }
166
167
    /**
168
     * Transform a model relationship into a single, or collection of, JSON API
169
     * resource identifier objects.
170
     *
171
     * @param Model  $record
172
     * @param string $relation
173
     *
174
     * @return array
175
     */
176
    protected function transformRelationship($record, $relation)
177
    {
178
        $data = null;
179
180
        if ($record->{$relation} instanceof Collection) {
181
            return $this->transformCollectionIdentifiers($record->{$relation});
182
        } else if ($record->{$relation} instanceof Model) {
183
            return $this->transformRecordIdentifier($record->{$relation});
184
        }
185
186
        return compact('data');
187
    }
188
}
189