FractalTransformFactory::parseOptions()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 2
dl 0
loc 18
ccs 9
cts 9
cp 1
crap 3
rs 9.6666
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 59
    public function __construct(Manager $manager)
33
    {
34 59
        $this->manager = $manager;
35 59
    }
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|null
44
     */
45 59
    public function make(ResourceInterface $resource, SerializerAbstract $serializer, array $options = [])
46
    {
47 59
        $options = $this->parseOptions($options, $resource);
48
49 58
        return $this->manager->setSerializer($serializer)
50 58
            ->parseIncludes($options['includes'])
51 58
            ->parseExcludes($options['excludes'])
52 58
            ->parseFieldsets($options['fieldsets'])
53 58
            ->createData($resource)
54 58
            ->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 59
    protected function parseOptions(array $options, ResourceInterface $resource): array
65
    {
66 59
        $options = array_merge([
67 59
            'includes' => [],
68
            'excludes' => [],
69
            'fieldsets' => [],
70 59
        ], $options);
71
72 59
        if (! empty($options['fieldsets'])) {
73 7
            if (is_null($resourceKey = $resource->getResourceKey())) {
74 1
                throw new LogicException('Filtering fields using sparse fieldsets require resource key to be set.');
75
            }
76
77 6
            $options['fieldsets'] = $this->parseFieldsets($options['fieldsets'], $resourceKey, $options['includes']);
78
        }
79
80 58
        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 6
    protected function parseFieldsets(array $fieldsets, string $resourceKey, array $includes): array
92
    {
93
        $includes = array_map(function ($include) use ($resourceKey) {
94 4
            return "$resourceKey.$include";
95 6
        }, $includes);
96
97 6
        foreach ($fieldsets as $key => $fields) {
98 6
            if (is_numeric($key)) {
99 2
                unset($fieldsets[$key]);
100 2
                $key = $resourceKey;
101
            }
102
103 6
            $fields = $this->parseFieldset($key, (array) $fields, $includes);
104 6
            $fieldsets[$key] = array_unique(array_merge(key_exists($key, $fieldsets) ? (array) $fieldsets[$key] : [], $fields));
105
        }
106
107
        return array_map(function ($fields) {
108 6
            return implode(',', $fields);
109 6
        }, $fieldsets);
110
    }
111
112
    /**
113
     * Parse the given fieldset and append any related resource keys.
114
     *
115
     * @param  string $key
116
     * @param  array  $fields
117
     * @param  array  $includes
118
     * @return array
119
     */
120 6
    protected function parseFieldset(string $key, array $fields, array $includes): array
121
    {
122
        $childIncludes = array_reduce($includes, function ($segments, $include) use ($key) {
123 4
            return array_merge($segments, $this->resolveChildIncludes($key, $include));
124 6
        }, []);
125
126 6
        return array_merge($fields, array_unique($childIncludes));
127
    }
128
129
    /**
130
     * Resolve included segments that are a direct child to the given resource key.
131
     *
132
     * @param  string $key
133
     * @param  string $include
134
     * @return array
135
     */
136 4
    protected function resolveChildIncludes($key, string $include): array
137
    {
138 4
        if (count($segments = explode('.', $include)) <= 1) {
139 4
            return [];
140
        }
141
142 4
        $relation = $key === array_shift($segments) ? [$segments[0]] : [];
143
144 4
        return array_merge($relation, $this->resolveChildIncludes($key, implode('.', $segments)));
145
    }
146
}