Passed
Push — v2 ( b247ab...8c624d )
by Alexander
02:21
created

FractalTransformFactory::parseFieldset()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 3
dl 0
loc 8
ccs 0
cts 3
cp 0
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Flugg\Responder;
4
5
use Flugg\Responder\Contracts\TransformFactory;
6
use League\Fractal\Manager;
7
use League\Fractal\Resource\ResourceInterface;
8
use League\Fractal\Serializer\SerializerAbstract;
9
use LogicException;
10
11
/**
12
 * A factory class responsible for transforming and serializing data utilizing Fractal.
13
 *
14
 * @package flugger/laravel-responder
15
 * @author  Alexander Tømmerås <[email protected]>
16
 * @license The MIT License
17
 */
18
class FractalTransformFactory implements TransformFactory
19
{
20
    /**
21
     * A manager for executing transforms.
22
     *
23
     * @var \League\Fractal\Manager
24
     */
25
    protected $manager;
26
27
    /**
28
     * Construct the factory class.
29
     *
30
     * @param \League\Fractal\Manager $manager
31
     */
32 1
    public function __construct(Manager $manager)
33
    {
34 1
        $this->manager = $manager;
35 1
    }
36
37
    /**
38
     * Transform the given resource, and serialize the data with the given serializer.
39
     *
40
     * @param  \League\Fractal\Resource\ResourceInterface    $resource
41
     * @param  \League\Fractal\Serializer\SerializerAbstract $serializer
42
     * @param  array                                         $options
43
     * @return array
44
     */
45 1
    public function make(ResourceInterface $resource, SerializerAbstract $serializer, array $options = []): array
46
    {
47 1
        $options = $this->parseOptions($options, $resource);
48
49 1
        return $this->manager->setSerializer($serializer)
50 1
            ->parseIncludes($options['includes'])
51 1
            ->parseExcludes($options['excludes'])
52 1
            ->parseFieldsets($options['fieldsets'])
53 1
            ->createData($resource)
54 1
            ->toArray();
55
    }
56
57
    /**
58
     * Parse the transformation options.
59
     *
60
     * @param  array                                      $options
61
     * @param  \League\Fractal\Resource\ResourceInterface $resource
62
     * @return array
63
     */
64 1
    protected function parseOptions(array $options, ResourceInterface $resource): array
65
    {
66 1
        $options = array_merge([
67 1
            'includes' => [],
68
            'excludes' => [],
69
            'fieldsets' => [],
70
        ], $options);
71
72 1
        if (! empty($options['fieldsets'])) {
73
            if (is_null($resourceKey = $resource->getResourceKey())) {
74
                throw new LogicException('Filtering fields using sparse fieldsets require resource key to be set.');
75
            }
76
77
            $options['fieldsets'] = $this->parseFieldsets($options['fieldsets'], $resourceKey, $options['includes']);
78
        }
79
80 1
        return $options;
81
    }
82
83
    /**
84
     * Parse the fieldsets for Fractal.
85
     *
86
     * @param  array  $fieldsets
87
     * @param  string $resourceKey
88
     * @param  array  $includes
89
     * @return array
90
     */
91
    protected function parseFieldsets(array $fieldsets, string $resourceKey, array $includes): array
92
    {
93
        $includes = array_map(function ($include) use ($resourceKey) {
94
            return "$resourceKey.$include";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $resourceKey instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $include instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
95
        }, $includes);
96
97
        foreach ($fieldsets as $key => $fields) {
98
            if (is_numeric($key)) {
99
                unset($fieldsets[$key]);
100
                $key = $resourceKey;
101
            }
102
103
            $fieldsets[$key] = $this->parseFieldset($key, (array) $fields, $includes);
104
        }
105
106
        return $fieldsets;
107
    }
108
109
    /**
110
     * Parse the given fieldset and append any related resource keys.
111
     *
112
     * @param  string $key
113
     * @param  array  $fields
114
     * @param  array  $includes
115
     * @return string
116
     */
117
    protected function parseFieldset(string $key, array $fields, array $includes): string
118
    {
119
        $childIncludes = array_reduce($includes, function ($segments, $include) use ($key) {
120
            return array_merge($segments, $this->resolveChildIncludes($key, $include));
121
        }, []);
122
123
        return implode(',', array_merge($fields, array_unique($childIncludes)));
124
    }
125
126
    /**
127
     * Resolve included segments that are a direct child to the given resource key.
128
     *
129
     * @param  string $key
130
     * @param  string $include
131
     * @return array
132
     */
133
    protected function resolveChildIncludes($key, string $include): array
134
    {
135
        if (count($segments = explode('.', $include)) <= 1) {
136
            return [];
137
        }
138
139
        $relation = $key === array_shift($segments) ? [$segments[0]] : [];
140
141
        return array_merge($relation, $this->resolveChildIncludes($key, implode('.', $segments)));
142
    }
143
}