Passed
Push — v2 ( 692932...206d9a )
by Alexander
02:47
created

TransformBuilder::includeTransformerRelations()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 1
nop 1
dl 0
loc 11
ccs 8
cts 8
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Flugg\Responder;
4
5
use Flugg\Responder\Contracts\Pagination\PaginatorFactory;
6
use Flugg\Responder\Contracts\Resources\ResourceFactory;
7
use Flugg\Responder\Contracts\TransformFactory;
8
use Flugg\Responder\Exceptions\InvalidSerializerException;
9
use Flugg\Responder\Pagination\CursorPaginator;
10
use Flugg\Responder\Transformers\Transformer as BaseTransformer;
11
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
12
use Illuminate\Database\Eloquent\Collection;
13
use Illuminate\Database\Eloquent\Model;
14
use League\Fractal\Pagination\Cursor;
15
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
16
use League\Fractal\Resource\Collection as CollectionResource;
17
use League\Fractal\Resource\NullResource;
18
use League\Fractal\Serializer\SerializerAbstract;
19
20
/**
21
 * A builder class responsible for building transformed arrays.
22
 *
23
 * @package flugger/laravel-responder
24
 * @author  Alexander Tømmerås <[email protected]>
25
 * @license The MIT License
26
 */
27
class TransformBuilder
28
{
29
    /**
30
     * A factory class for making Fractal resources.
31
     *
32
     * @var \Flugg\Responder\Contracts\Resources\ResourceFactory
33
     */
34
    protected $resourceFactory;
35
36
    /**
37
     * A factory for making transformed arrays.
38
     *
39
     * @var \Flugg\Responder\Contracts\TransformFactory
40
     */
41
    private $transformFactory;
42
43
    /**
44
     * A factory used to build Fractal paginator adapters.
45
     *
46
     * @var \Flugg\Responder\Contracts\Pagination\PaginatorFactory
47
     */
48
    protected $paginatorFactory;
49
50
    /**
51
     * The resource that's being built.
52
     *
53
     * @var \League\Fractal\Resource\ResourceInterface
54
     */
55
    protected $resource;
56
57
    /**
58
     * A serializer for formatting data after transforming.
59
     *
60
     * @var \League\Fractal\Serializer\SerializerAbstract
61
     */
62
    protected $serializer;
63
64
    /**
65
     * A list of included relations.
66
     *
67
     * @var array
68
     */
69
    protected $with = [];
70
71
    /**
72
     * A list of excluded relations.
73
     *
74
     * @var array
75
     */
76
    protected $without = [];
77
78
    /**
79
     * A list of sparse fieldsets.
80
     *
81
     * @var array
82
     */
83
    protected $only = [];
84
85
    /**
86
     * Construct the builder class.
87
     *
88
     * @param \Flugg\Responder\Contracts\Resources\ResourceFactory   $resourceFactory
89
     * @param \Flugg\Responder\Contracts\TransformFactory            $transformFactory
90
     * @param \Flugg\Responder\Contracts\Pagination\PaginatorFactory $paginatorFactory
91
     */
92 17
    public function __construct(ResourceFactory $resourceFactory, TransformFactory $transformFactory, PaginatorFactory $paginatorFactory)
93
    {
94 17
        $this->resourceFactory = $resourceFactory;
95 17
        $this->transformFactory = $transformFactory;
96 17
        $this->paginatorFactory = $paginatorFactory;
97 17
    }
98
99
    /**
100
     * Make a resource from the given data and transformer and set the resource key.
101
     *
102
     * @param  mixed                                                          $data
103
     * @param  \Flugg\Responder\Transformers\Transformer|callable|string|null $transformer
104
     * @param  string|null                                                    $resourceKey
105
     * @return $this
106
     */
107 16
    public function resource($data = null, $transformer = null, string $resourceKey = null)
108
    {
109 16
        $this->resource = $this->resourceFactory->make($data, $transformer, $resourceKey);
110
111 16
        if ($data instanceof CursorPaginator) {
112 1
            $this->cursor($this->paginatorFactory->makeCursor($data));
113
        } elseif ($data instanceof LengthAwarePaginator) {
114 1
            $this->paginator($this->paginatorFactory->make($data));
0 ignored issues
show
Compatibility introduced by
$this->paginatorFactory->make($data) of type object<League\Fractal\Pa...ion\PaginatorInterface> is not a sub-type of object<League\Fractal\Pa...minatePaginatorAdapter>. It seems like you assume a concrete implementation of the interface League\Fractal\Pagination\PaginatorInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
115
        }
116
117 16
        return $this;
118
    }
119
120
    /**
121
     * Manually set the cursor on the resource.
122
     *
123
     * @param  \League\Fractal\Pagination\Cursor $cursor
124
     * @return $this
125
     */
126 2
    public function cursor(Cursor $cursor)
127
    {
128 2
        if ($this->resource instanceof CollectionResource) {
129 2
            $this->resource->setCursor($cursor);
130
        }
131
132 2
        return $this;
133
    }
134
135
    /**
136
     * Manually set the paginator on the resource.
137
     *
138
     * @param  \League\Fractal\Pagination\IlluminatePaginatorAdapter $paginator
139
     * @return $this
140
     */
141 2
    public function paginator(IlluminatePaginatorAdapter $paginator)
142
    {
143 2
        if ($this->resource instanceof CollectionResource) {
144 2
            $this->resource->setPaginator($paginator);
145
        }
146
147 2
        return $this;
148
    }
149
150
    /**
151
     * Add meta data appended to the response data.
152
     *
153
     * @param  array $data
154
     * @return $this
155
     */
156 1
    public function meta(array $data)
157
    {
158 1
        $this->resource->setMeta($data);
159
160 1
        return $this;
161
    }
162
163
    /**
164
     * Include relations to the transform.
165
     *
166
     * @param  string[]|string $relations
167
     * @return $this
168
     */
169 3
    public function with($relations)
170
    {
171 3
        $this->with = array_merge($this->with, is_array($relations) ? $relations : func_get_args());
172
173 3
        return $this;
174
    }
175
176
    /**
177
     * Exclude relations from the transform.
178
     *
179
     * @param  string[]|string $relations
180
     * @return $this
181
     */
182 2
    public function without($relations)
183
    {
184 2
        $this->without = array_merge($this->without, is_array($relations) ? $relations : func_get_args());
185
186 2
        return $this;
187
    }
188
189
    /**
190
     * Filter fields to output using sparse fieldsets.
191
     *
192
     * @param  string[]|string $fields
193
     * @return $this
194
     */
195 2
    public function only($fields)
196
    {
197 2
        $this->only = array_merge($this->only, is_array($fields) ? $fields : func_get_args());
198
199 2
        return $this;
200
    }
201
202
    /**
203
     * Set the serializer.
204
     *
205
     * @param  \League\Fractal\Serializer\SerializerAbstract|string $serializer
206
     * @return $this
207
     * @throws \Flugg\Responder\Exceptions\InvalidSerializerException
208
     */
209 17
    public function serializer($serializer)
210
    {
211 17
        if (is_string($serializer)) {
212 2
            $serializer = new $serializer;
213
        }
214
215 17
        if (! $serializer instanceof SerializerAbstract) {
216 1
            throw new InvalidSerializerException;
217
        }
218
219 17
        $this->serializer = $serializer;
220
221 17
        return $this;
222
    }
223
224
    /**
225
     * Transform and serialize the data and return the transformed array.
226
     *
227
     * @return array
228
     */
229 10
    public function transform(): array
230
    {
231 10
        $this->prepareRelations($this->resource->getData(), $this->resource->getTransformer());
232
233 10
        return $this->transformFactory->make($this->resource ?: new NullResource, $this->serializer, [
234 10
            'includes' => $this->with,
235 10
            'excludes' => $this->without,
236 10
            'fieldsets' => $this->only,
237
        ]);
238
    }
239
240
    /**
241
     * Prepare requested relations for the transformation.
242
     *
243
     * @param  mixed                                                          $data
244
     * @param  \Flugg\Responder\Transformers\Transformer|callable|string|null $transformer
245
     * @return void
246
     */
247 10
    protected function prepareRelations($data, $transformer)
248
    {
249 10
        if ($transformer instanceof BaseTransformer) {
250 1
            $this->includeTransformerRelations($transformer);
251
        }
252
253 10
        if ($data instanceof Model || $data instanceof Collection) {
254 1
            $data->load($this->with);
255
        }
256
257 10
        $this->with = $this->stripEagerLoadConstraints($this->with);
258 10
    }
259
260
    /**
261
     * Include default relationships and add eager load constraints from transformer.
262
     *
263
     * @param  \Flugg\Responder\Transformers\Transformer $transformer
264
     * @return void
265
     */
266
    protected function includeTransformerRelations(BaseTransformer $transformer)
267
    {
268 1
        $relations = array_filter(array_keys($this->with), function ($relation) {
269 1
            return ! is_numeric($relation);
270 1
        });
271
272 1
        $this->with(Collection::make($transformer->defaultRelations())
273 1
            ->filter(function ($constrain, $relation) use ($relations) {
274 1
                return ! in_array(is_numeric($relation) ? $constrain : $relation, $relations);
275 1
            })->all());
276 1
    }
277
278
    /**
279
     * Remove eager load constraint functions from the given relations.
280
     *
281
     * @param  array $relations
282
     * @return array
283
     */
284
    protected function stripEagerLoadConstraints(array $relations): array
285
    {
286 10
        return collect($relations)->map(function ($value, $key) {
287 3
            return is_numeric($key) ? $value : $key;
288 10
        })->values()->all();
289
    }
290
}