GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#20)
by
unknown
04:02
created

Fractal::parseFieldsets()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 6
nc 3
nop 1
1
<?php
2
3
namespace Spatie\Fractalistic;
4
5
use Traversable;
6
use JsonSerializable;
7
use League\Fractal\Manager;
8
use League\Fractal\Pagination\CursorInterface;
9
use League\Fractal\Pagination\PaginatorInterface;
10
use League\Fractal\Serializer\SerializerAbstract;
11
use Spatie\Fractalistic\Exceptions\InvalidTransformation;
12
use Spatie\Fractalistic\Exceptions\NoTransformerSpecified;
13
14
class Fractal implements JsonSerializable
15
{
16
    /** @var \League\Fractal\Manager */
17
    protected $manager;
18
19
    /** @var int */
20
    protected $recursionLimit = 10;
21
22
    /** @var \League\Fractal\Serializer\SerializerAbstract */
23
    protected $serializer;
24
25
    /** @var \League\Fractal\TransformerAbstract|callable */
26
    protected $transformer;
27
28
    /** @var \League\Fractal\Pagination\PaginatorInterface */
29
    protected $paginator;
30
31
    /** @var \League\Fractal\Pagination\CursorInterface */
32
    protected $cursor;
33
34
    /** @var array */
35
    protected $includes = [];
36
37
    /** @var array */
38
    protected $excludes = [];
39
40
    /** @var array */
41
    protected $fieldsets = [];
42
43
    /** @var string */
44
    protected $dataType;
45
46
    /** @var mixed */
47
    protected $data;
48
49
    /** @var string */
50
    protected $resourceName;
51
52
    /** @var array */
53
    protected $meta = [];
54
55
    /**
56
     * @param null|mixed $data
57
     * @param null|callable|\League\Fractal\TransformerAbstract $transformer
58
     * @param null|\League\Fractal\Serializer\SerializerAbstract $serializer
59
     *
60
     * @return \Spatie\Fractalistic\Fractal
61
     */
62
    public static function create($data = null, $transformer = null, $serializer = null)
63
    {
64
        $instance = new static(new Manager());
65
66
        $instance->data = $data ?: null;
67
        $instance->dataType = $data ? $instance->determineDataType($data) : null;
68
        $instance->transformer = $transformer ?: null;
69
        $instance->serializer = $serializer ?: null;
70
71
        return $instance;
72
    }
73
74
    /** @param \League\Fractal\Manager $manager */
75
    public function __construct(Manager $manager)
76
    {
77
        $this->manager = $manager;
78
    }
79
80
    /**
81
     * Set the collection data that must be transformed.
82
     *
83
     * @param mixed                                             $data
84
     * @param \League\Fractal\TransformerAbstract|callable|null $transformer
85
     * @param string|null                                       $resourceName
86
     *
87
     * @return $this
88
     */
89
    public function collection($data, $transformer = null, $resourceName = null)
90
    {
91
        $this->resourceName = $resourceName;
92
93
        return $this->data('collection', $data, $transformer);
94
    }
95
96
    /**
97
     * Set the item data that must be transformed.
98
     *
99
     * @param mixed                                             $data
100
     * @param \League\Fractal\TransformerAbstract|callable|null $transformer
101
     * @param string|null                                       $resourceName
102
     *
103
     * @return $this
104
     */
105
    public function item($data, $transformer = null, $resourceName = null)
106
    {
107
        $this->resourceName = $resourceName;
108
109
        return $this->data('item', $data, $transformer);
110
    }
111
112
    /**
113
     * Set the data that must be transformed.
114
     *
115
     * @param string                                            $dataType
116
     * @param mixed                                             $data
117
     * @param \League\Fractal\TransformerAbstract|callable|null $transformer
118
     *
119
     * @return $this
120
     */
121
    public function data($dataType, $data, $transformer = null)
122
    {
123
        $this->dataType = $dataType;
124
125
        $this->data = $data;
126
127
        if (! is_null($transformer)) {
128
            $this->transformer = $transformer;
129
        }
130
131
        return $this;
132
    }
133
134
    /**
135
     * @param mixed $data
136
     *
137
     * @return string
138
     */
139
    protected function determineDataType($data)
140
    {
141
        if (is_array($data)) {
142
            return 'collection';
143
        }
144
145
        if ($data instanceof Traversable) {
146
            return 'collection';
147
        }
148
149
        return 'item';
150
    }
151
152
    /**
153
     * Set the class or function that will perform the transform.
154
     *
155
     * @param \League\Fractal\TransformerAbstract|callable $transformer
156
     *
157
     * @return $this
158
     */
159
    public function transformWith($transformer)
160
    {
161
        if (is_string($transformer) && class_exists($transformer)) {
162
            $transformer = new $transformer;
163
        }
164
165
        $this->transformer = $transformer;
166
167
        return $this;
168
    }
169
170
    /**
171
     * Set the serializer to be used.
172
     *
173
     * @param \League\Fractal\Serializer\SerializerAbstract $serializer
174
     *
175
     * @return $this
176
     */
177
    public function serializeWith(SerializerAbstract $serializer)
178
    {
179
        $this->serializer = $serializer;
180
181
        return $this;
182
    }
183
184
    /**
185
     * Set a Fractal paginator for the data.
186
     *
187
     * @param \League\Fractal\Pagination\PaginatorInterface $paginator
188
     *
189
     * @return $this
190
     */
191
    public function paginateWith(PaginatorInterface $paginator)
192
    {
193
        $this->paginator = $paginator;
194
195
        return $this;
196
    }
197
198
    /**
199
     * Set a Fractal cursor for the data.
200
     *
201
     * @param \League\Fractal\Pagination\CursorInterface $cursor
202
     *
203
     * @return $this
204
     */
205
    public function withCursor(CursorInterface $cursor)
206
    {
207
        $this->cursor = $cursor;
208
209
        return $this;
210
    }
211
212
    /**
213
     * Specify the includes.
214
     *
215
     * @param array|string $includes Array or string of resources to include.
216
     *
217
     * @return $this
218
     */
219
    public function parseIncludes($includes)
220
    {
221
        $includes = $this->normalizeIncludesOrExcludes($includes);
222
223
        $this->includes = array_merge($this->includes, (array) $includes);
224
225
        return $this;
226
    }
227
228
    /**
229
     * Specify the excludes.
230
     *
231
     * @param array|string $excludes Array or string of resources to exclude.
232
     * @return $this
233
     */
234
    public function parseExcludes($excludes)
235
    {
236
        $excludes = $this->normalizeIncludesOrExcludes($excludes);
237
238
        $this->excludes = array_merge($this->excludes, (array) $excludes);
239
240
        return $this;
241
    }
242
243
    /**
244
     * Specify the fieldsets to include in the response.
245
     *
246
     * @param array|string $fieldsets array with key = resourceName and value = fields to include
247
     *                                (array or comma separated string with field names)
248
     *
249
     * @return $this
250
     */
251
    public function parseFieldsets($fieldsets){
252
      foreach ($fieldsets as $key => $fields) {
0 ignored issues
show
Bug introduced by
The expression $fieldsets of type array|string is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
253
        if (is_array($fields)) {
254
          $fieldsets[$key] = implode(',', $fields);
255
        }
256
      }
257
258
      $this->fieldsets = array_merge($this->fieldsets, $fieldsets);
259
260
      return $this;
261
    }
262
263
    /**
264
     * Normalize the includes an excludes.
265
     *
266
     * @param array|string $includesOrExcludes
267
     *
268
     * @return array|string
269
     */
270
    protected function normalizeIncludesOrExcludes($includesOrExcludes = '')
271
    {
272
        if (! is_string($includesOrExcludes)) {
273
            return $includesOrExcludes;
274
        }
275
276
        return array_map(function ($value) {
277
            return trim($value);
278
        }, explode(',', $includesOrExcludes));
279
    }
280
281
    /**
282
     * Set the meta data.
283
     *
284
     * @param $array,...
285
     *
286
     * @return $this
287
     */
288
    public function addMeta()
289
    {
290
        foreach (func_get_args() as $meta) {
291
            if (is_array($meta)) {
292
                $this->meta += $meta;
293
            }
294
        }
295
296
        return $this;
297
    }
298
299
    /**
300
     * Set the resource name, to replace 'data' as the root of the collection or item.
301
     *
302
     * @param string $resourceName
303
     *
304
     * @return $this
305
     */
306
    public function withResourceName($resourceName)
307
    {
308
        $this->resourceName = $resourceName;
309
310
        return $this;
311
    }
312
313
    /**
314
     * Upper limit to how many levels of included data are allowed.
315
     *
316
     * @param int $recursionLimit
317
     *
318
     * @return $this
319
     */
320
    public function limitRecursion(int $recursionLimit)
321
    {
322
        $this->recursionLimit = $recursionLimit;
323
324
        return $this;
325
    }
326
327
    /**
328
     * Perform the transformation to json.
329
     *
330
     * @return string
331
     */
332
    public function toJson()
333
    {
334
        return $this->createData()->toJson();
335
    }
336
337
    /**
338
     * Perform the transformation to array.
339
     *
340
     * @return array
341
     */
342
    public function toArray()
343
    {
344
        return $this->createData()->toArray();
345
    }
346
347
    /**
348
     * Create fractal data.
349
     *
350
     * @return \League\Fractal\Scope
351
     *
352
     * @throws \Spatie\Fractalistic\Exceptions\InvalidTransformation
353
     * @throws \Spatie\Fractalistic\Exceptions\NoTransformerSpecified
354
     */
355
    public function createData()
356
    {
357
        if (is_null($this->transformer)) {
358
            throw new NoTransformerSpecified();
359
        }
360
361
        if (! is_null($this->serializer)) {
362
            $this->manager->setSerializer($this->serializer);
363
        }
364
365
        $this->manager->setRecursionLimit($this->recursionLimit);
366
367
        if ((bool) $this->includes) {
368
          $this->manager->parseIncludes($this->includes);
369
        }
370
371
        if ((bool) $this->excludes) {
372
          $this->manager->parseExcludes($this->excludes);
373
        }
374
375
        if ((bool) $this->fieldsets) {
376
          $this->manager->parseFieldsets($this->fieldsets);
377
        }
378
379
        return $this->manager->createData($this->getResource());
380
    }
381
382
    /**
383
     * Get the resource.
384
     *
385
     * @return \League\Fractal\Resource\ResourceInterface
386
     *
387
     * @throws \Spatie\Fractalistic\Exceptions\InvalidTransformation
388
     */
389
    public function getResource()
390
    {
391
        $resourceClass = 'League\\Fractal\\Resource\\'.ucfirst($this->dataType);
392
393
        if (! class_exists($resourceClass)) {
394
            throw new InvalidTransformation();
395
        }
396
397
        $resource = new $resourceClass($this->data, $this->transformer, $this->resourceName);
398
399
        $resource->setMeta($this->meta);
400
401
        if (! is_null($this->paginator)) {
402
            $resource->setPaginator($this->paginator);
403
        }
404
405
        if (! is_null($this->cursor)) {
406
            $resource->setCursor($this->cursor);
407
        }
408
409
        return $resource;
410
    }
411
412
    /**
413
     * Convert the object into something JSON serializable.
414
     */
415
    public function jsonSerialize()
416
    {
417
        return $this->toArray();
418
    }
419
420
    /**
421
     * Support for magic methods to included data.
422
     *
423
     * @param string $name
424
     * @param array  $arguments
425
     *
426
     * @return $this
427
     */
428
    public function __call($name, array $arguments)
429
    {
430 View Code Duplication
        if ($this->startsWith($name, ['include'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
431
            $includeName = lcfirst(substr($name, strlen('include')));
432
433
            return $this->parseIncludes($includeName);
434
        }
435
436 View Code Duplication
        if ($this->startsWith($name, ['exclude'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
437
            $excludeName = lcfirst(substr($name, strlen('exclude')));
438
439
            return $this->parseExcludes($excludeName);
440
        }
441
442
        trigger_error('Call to undefined method '.__CLASS__.'::'.$name.'()', E_USER_ERROR);
443
    }
444
445
    /**
446
     * Determine if a given string starts with a given substring.
447
     *
448
     * @param  string  $haystack
449
     * @param  string|array  $needles
450
     * @return bool
451
     */
452
    protected function startsWith($haystack, $needles)
453
    {
454
        foreach ((array) $needles as $needle) {
455
            if ($needle != '' && substr($haystack, 0, strlen($needle)) === (string) $needle) {
456
                return true;
457
            }
458
        }
459
460
        return false;
461
    }
462
}
463