Completed
Push — master ( 1a176c...a7ce7c )
by ARCANEDEV
11s
created

src/Http/ApiResource.php (5 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php namespace Arcanedev\LaravelApiHelper\Http;
2
3
use ArrayAccess;
4
use Illuminate\Container\Container;
5
use Illuminate\Contracts\Routing\UrlRoutable;
6
use Illuminate\Contracts\Support\Arrayable;
7
use Illuminate\Contracts\Support\Responsable;
8
use Illuminate\Http\Resources\DelegatesToResource;
9
use Illuminate\Http\Resources\Json\PaginatedResourceResponse;
10
use Illuminate\Http\Resources\Json\ResourceResponse;
11
use Illuminate\Http\Resources\MergeValue;
12
use Illuminate\Http\Resources\MissingValue;
13
use Illuminate\Pagination\AbstractPaginator;
14
use Illuminate\Support\Arr;
15
use Illuminate\Support\Collection;
16
use JsonSerializable;
17
18
/**
19
 * Class     ApiResource
20
 *
21
 * @package  Arcanedev\LaravelApiHelper\Http
22
 * @author   ARCANEDEV <[email protected]>
23
 *
24
 * @property  mixed|null  pivot
25
 */
26
class ApiResource implements ArrayAccess, JsonSerializable, Responsable, UrlRoutable
27
{
28
    /* -----------------------------------------------------------------
29
     |  Traits
30
     | -----------------------------------------------------------------
31
     */
32
33
    use DelegatesToResource;
34
35
    /* -----------------------------------------------------------------
36
     |  Properties
37
     | -----------------------------------------------------------------
38
     */
39
40
    /**
41
     * The resource instance.
42
     *
43
     * @var mixed
44
     */
45
    public $resource;
46
47
    /**
48
     * The additional data that should be added to the top-level resource array.
49
     *
50
     * @var array
51
     */
52
    public $with = [];
53
54
    /**
55
     * The additional meta data that should be added to the resource response.
56
     *
57
     * Added during response construction by the developer.
58
     *
59
     * @var array
60
     */
61
    public $additional = [];
62
63
    /**
64
     * The "data" wrapper that should be applied.
65
     *
66
     * @var string
67
     */
68
    public static $wrap = 'data';
69
70
    /* -----------------------------------------------------------------
71
     |  Constructor
72
     | -----------------------------------------------------------------
73
     */
74
75
    /**
76
     * PostTransformer constructor.
77
     *
78
     * @param  mixed  $resource
79
     */
80 4
    public function __construct($resource)
81
    {
82 4
        $this->resource = $resource;
83 4
    }
84
85
    /**
86
     * Create a new resource instance.
87
     *
88
     * @param  mixed  $resource
89
     *
90
     * @return static
91
     */
92 4
    public static function make($resource)
93
    {
94 4
        return new static($resource);
95
    }
96
97
    /* -----------------------------------------------------------------
98
     |  Main Methods
99
     | -----------------------------------------------------------------
100
     */
101
102
    /**
103
     * Transform the resource into an array.
104
     *
105
     * @param  \Illuminate\Http\Request  $request
106
     *
107
     * @return array
108
     */
109
    public function toArray($request)
0 ignored issues
show
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
110
    {
111
        return $this->resource->toArray();
112
    }
113
114
    /**
115
     * Get any additional data that should be returned with the resource array.
116
     *
117
     * @param  \Illuminate\Http\Request  $request
118
     *
119
     * @return array
120
     */
121 4
    public function with($request)
0 ignored issues
show
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
122
    {
123 4
        return $this->with;
124
    }
125
126
    /**
127
     * Add additional meta data to the resource response.
128
     *
129
     * @param  array  $data
130
     *
131
     * @return $this
132
     */
133
    public function additional(array $data)
134
    {
135
        $this->additional = $data;
136
137
        return $this;
138
    }
139
140
    /**
141
     * Set the string that should wrap the outer-most resource array.
142
     *
143
     * @param  string  $value
144
     */
145
    public static function wrap($value)
146
    {
147
        static::$wrap = $value;
148
    }
149
150
    /**
151
     * Disable wrapping of the outer-most resource array.
152
     *
153
     * @return void
154
     */
155
    public static function withoutWrapping()
156
    {
157
        static::wrap(null);
158
    }
159
160
161
    /**
162
     * Customize the response for a request.
163
     *
164
     * @param  \Illuminate\Http\Request       $request
165
     * @param  \Illuminate\Http\JsonResponse  $response
166
     *
167
     * @return void
168
     */
169 4
    public function withResponse($request, $response)
0 ignored issues
show
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $response is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
170
    {
171
        //
172 4
    }
173
174
    /**
175
     * Merge the given attributes.
176
     *
177
     * @param  array  $attributes
178
     *
179
     * @return \Illuminate\Http\Resources\MergeValue
180
     */
181
    protected function attributes($attributes)
182
    {
183
        return new MergeValue(
184
            Arr::only($this->resource->toArray(), $attributes)
185
        );
186
    }
187
188
    /**
189
     * Retrieve a relationship if it has been loaded.
190
     *
191
     * @param  string  $relationship
192
     *
193
     * @return \Illuminate\Http\Resources\MissingValue|mixed
194
     */
195
    protected function whenLoaded($relationship)
196
    {
197
        return $this->resource->relationLoaded($relationship)
198
            ? $this->resource->{$relationship}
199
            : new MissingValue;
200
    }
201
202
    /**
203
     * Execute a callback if the given pivot table has been loaded.
204
     *
205
     * @param  string  $table
206
     * @param  mixed   $value
207
     * @param  mixed   $default
208
     *
209
     * @return \Illuminate\Http\Resources\MissingValue|mixed
210
     */
211
    protected function whenPivotLoaded($table, $value, $default = null)
212
    {
213
        if (func_num_args() === 2)
214
            $default = new MissingValue;
215
216
        return $this->when(
217
            $this->pivot && ($this->pivot instanceof $table || $this->pivot->getTable() === $table),
218
            ...[$value, $default]
219
        );
220
    }
221
222
    /**
223
     * Resolve the resource to an array.
224
     *
225
     * @param  \Illuminate\Http\Request|null  $request
226
     *
227
     * @return array
228
     */
229 4
    public function resolve($request = null)
230
    {
231 4
        $request = $request ?: Container::getInstance()->make('request');
232
233 4
        if ($this->resource instanceof Collection)
234
            $data = $this->resolveCollection($this->resource, $request);
235 4
        elseif ($this->resource instanceof AbstractPaginator)
236
            $data = $this->resolveCollection($this->resource->getCollection(), $request);
237
        else
238 4
            $data = $this->toArray($request);
239
240 4
        if ($data instanceof Arrayable)
241
            $data = $data->toArray();
242 4
        elseif ($data instanceof JsonSerializable)
243
            $data = $data->jsonSerialize();
244
245 4
        return $this->resolveNestedRelations((array) $data, $request);
246
    }
247
248
    /**
249
     * Resolve the nested resources to an array.
250
     *
251
     * @param  array                     $data
252
     * @param  \Illuminate\Http\Request  $request
253
     *
254
     * @return array
255
     */
256 4
    protected function resolveNestedRelations($data, $request)
257
    {
258 4
        foreach ($data as $key => $value) {
259 4
            if (is_array($value)) {
260
                $data[$key] = $this->resolveNestedRelations($value, $request);
261
            }
262 4
            elseif ($value instanceof static) {
263 3
                $data[$key] = $value->resolve($request);
264
            }
265
        }
266
267 4
        return $this->filter($data);
268
    }
269
270
    /**
271
     * Resolve the resource to an array.
272
     *
273
     * @param  \Illuminate\Support\Collection  $collection
274
     * @param  \Illuminate\Http\Request|null   $request
275
     *
276
     * @return array
277
     */
278
    public function resolveCollection($collection, $request = null)
279
    {
280
        return $collection->map(function ($item) use ($request) {
281
            return (new static($item))->toArray($request);
0 ignored issues
show
It seems like $request defined by parameter $request on line 278 can be null; however, Arcanedev\LaravelApiHelp...\ApiResource::toArray() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
282
        })->all();
283
    }
284
285
    /**
286
     * Transform the resource into an HTTP response.
287
     *
288
     * @param  \Illuminate\Http\Request|null  $request
289
     *
290
     * @return \Illuminate\Http\Response
291
     */
292 4
    public function response($request = null)
293
    {
294 4
        return $this->toResponse(
295 4
            $request ?: Container::getInstance()->make('request')
296
        );
297
    }
298
299
    /**
300
     * Create an HTTP response that represents the object.
301
     *
302
     * @param  \Illuminate\Http\Request  $request
303
     *
304
     * @return \Illuminate\Http\Response|mixed
305
     */
306 4
    public function toResponse($request)
307
    {
308
        return (
309 4
            $this->resource instanceof AbstractPaginator
310
                ? new PaginatedResourceResponse($this)
311 4
                : new ResourceResponse($this)
312 4
        )->toResponse($request);
313
    }
314
315
    /**
316
     * Retrieve a value based on a given condition.
317
     *
318
     * @param  bool   $condition
319
     * @param  mixed  $value
320
     * @param  mixed  $default
321
     *
322
     * @return \Illuminate\Http\Resources\MissingValue|mixed
323
     */
324
    protected function when($condition, $value, $default = null)
325
    {
326
        return $condition
327
            ? value($value)
328
            : (func_num_args() === 3 ? value($default) : new MissingValue);
329
    }
330
331
    /**
332
     * Filter the given data, removing any optional values.
333
     *
334
     * @param  array  $data
335
     *
336
     * @return array
337
     */
338 4
    protected function filter($data)
339
    {
340 4
        $index = -1;
341
342 4
        foreach ($data as $key => $value) {
343 4
            $index++;
344
345 4
            if (is_array($value)) {
346
                $data[$key] = $this->filter($value);
347
348
                continue;
349
            }
350
351 4
            if (is_numeric($key) && $value instanceof MergeValue) {
352
                return $this->merge($data, $index, $this->filter($value->data));
353
            }
354
355
            if (
356 4
                $value instanceof MissingValue ||
357 4
                ($value instanceof self && $value->resource instanceof MissingValue)
358
            ) {
359 3
                unset($data[$key]);
360
            }
361
        }
362
363 4
        return $data;
364
    }
365
366
    /**
367
     * Merge the given data in at the given index.
368
     *
369
     * @param  array  $data
370
     * @param  int    $index
371
     * @param  array  $merge
372
     *
373
     * @return array
374
     */
375
    protected function merge($data, $index, $merge)
376
    {
377
        if (array_values($data) === $data) {
378
            return array_merge(
379
                array_merge(array_slice($data, 0, $index, true), $merge),
380
                $this->filter(array_slice($data, $index + 1, null, true))
381
            );
382
        }
383
384
        return array_slice($data, 0, $index, true) +
385
            $merge +
386
            $this->filter(array_slice($data, $index + 1, null, true));
387
    }
388
389
    /**
390
     * Merge a value based on a given condition.
391
     *
392
     * @param  bool   $condition
393
     * @param  mixed  $value
394
     *
395
     * @return \Illuminate\Http\Resources\MissingValue|mixed
396
     */
397
    protected function mergeWhen($condition, $value)
398
    {
399
        return $condition ? new MergeValue(value($value)) : new MissingValue;
400
    }
401
402
    /**
403
     * Transform the given value if it is present.
404
     *
405
     * @param  mixed     $value
406
     * @param  callable  $callback
407
     * @param  mixed     $default
408
     *
409
     * @return mixed
410
     */
411
    protected function transform($value, callable $callback, $default = null)
412
    {
413
        return transform(
414
            $value, $callback, func_num_args() === 3 ? $default : new MissingValue
415
        );
416
    }
417
418
    /**
419
     * Prepare the resource for JSON serialization.
420
     *
421
     * @return array
422
     */
423
    public function jsonSerialize()
424
    {
425
        return $this->resolve(Container::getInstance()->make('request'));
426
    }
427
}
428