Completed
Pull Request — master (#273)
by Gonçalo
04:11
created

Manager::getSerializer()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 8
ccs 5
cts 5
cp 1
rs 9.4285
cc 2
eloc 4
nc 2
nop 0
crap 2
1
<?php
2
3
/*
4
 * This file is part of the League\Fractal package.
5
 *
6
 * (c) Phil Sturgeon <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace League\Fractal;
13
14
use League\Fractal\Resource\ResourceInterface;
15
use League\Fractal\Serializer\DataArraySerializer;
16
use League\Fractal\Serializer\SerializerAbstract;
17
18
/**
19
 * Manager
20
 *
21
 * Not a wildly creative name, but the manager is what a Fractal user will interact
22
 * with the most. The manager has various configurable options, and allows users
23
 * to create the "root scope" easily.
24
 */
25
class Manager
26
{
27
    /**
28
     * Array of scope identifiers for resources to include.
29
     *
30
     * @var array
31
     */
32
    protected $requestedIncludes = [];
33
34
    /**
35
     * Array of scope identifiers for resources to exclude.
36
     *
37
     * @var array
38
     */
39
    protected $requestedExcludes = [];
40
41
    /**
42
     * Array of requested fieldsets.
43
     *
44
     * @var array
45
     */
46
    protected $requestedFieldsets = [];
47
48
    /**
49
     * Array containing modifiers as keys and an array value of params.
50
     *
51
     * @var array
52
     */
53
    protected $includeParams = [];
54
55
    /**
56
     * The character used to separate modifier parameters.
57
     *
58
     * @var string
59
     */
60
    protected $paramDelimiter = '|';
61
62
    /**
63
     * Upper limit to how many levels of included data are allowed.
64
     *
65
     * @var int
66
     */
67
    protected $recursionLimit = 10;
68
69
    /**
70
     * Serializer.
71
     *
72
     * @var SerializerAbstract
73
     */
74
    protected $serializer;
75
76
    /**
77
     * Create Data.
78
     *
79
     * Main method to kick this all off. Make a resource then pass it over, and use toArray()
80
     *
81
     * @param ResourceInterface $resource
82
     * @param string            $scopeIdentifier
83
     * @param Scope             $parentScopeInstance
84
     *
85
     * @return Scope
86
     */
87 36
    public function createData(ResourceInterface $resource, $scopeIdentifier = null, Scope $parentScopeInstance = null)
88
    {
89 36
        $scopeInstance = new Scope($this, $resource, $scopeIdentifier);
90
91
        // Update scope history
92 36
        if ($parentScopeInstance !== null) {
93
            // This will be the new children list of parents (parents parents, plus the parent)
94 31
            $scopeArray = $parentScopeInstance->getParentScopes();
95 31
            $scopeArray[] = $parentScopeInstance->getScopeIdentifier();
96
97 31
            $scopeInstance->setParentScopes($scopeArray);
98 31
        }
99
100 36
        return $scopeInstance;
101
    }
102
103
    /**
104
     * Get Include Params.
105
     *
106
     * @param string $include
107
     *
108
     * @return \League\Fractal\ParamBag|null
109
     */
110 27
    public function getIncludeParams($include)
111
    {
112 27
        if (! isset($this->includeParams[$include])) {
113 25
            return;
114
        }
115
116 2
        $params = $this->includeParams[$include];
117
118 2
        return new ParamBag($params);
119
    }
120
121
    /**
122
     * Get Requested Includes.
123
     *
124
     * @return array
125
     */
126 38
    public function getRequestedIncludes()
127
    {
128 38
        return $this->requestedIncludes;
129
    }
130
131
    /**
132
     * Get Requested Excludes.
133
     *
134
     * @return array
135
     */
136 28
    public function getRequestedExcludes()
137
    {
138 28
        return $this->requestedExcludes;
139
    }
140
141
    /**
142
     * Get Serializer.
143
     *
144
     * @return SerializerAbstract
145
     */
146 47
    public function getSerializer()
147
    {
148 47
        if (! $this->serializer) {
149 9
            $this->setSerializer(new DataArraySerializer());
150 9
        }
151
152 47
        return $this->serializer;
153
    }
154
155
    /**
156
     * Parse Include String.
157
     *
158
     * @param array|string $includes Array or csv string of resources to include
159
     *
160
     * @return $this
161
     */
162 41
    public function parseIncludes($includes)
163
    {
164
        // Wipe these before we go again
165 41
        $this->requestedIncludes = $this->includeParams = [];
166
167 41
        if (is_string($includes)) {
168 31
            $includes = explode(',', $includes);
169 31
        }
170
171 41
        if (! is_array($includes)) {
172 2
            throw new \InvalidArgumentException(
173 2
                'The parseIncludes() method expects a string or an array. '.gettype($includes).' given'
174 2
            );
175
        }
176
177 39
        foreach ($includes as $include) {
178 39
            list($includeName, $allModifiersStr) = array_pad(explode(':', $include, 2), 2, null);
179
180
            // Trim it down to a cool level of recursion
181 39
            $includeName = $this->trimToAcceptableRecursionLevel($includeName);
182
183 39
            if (in_array($includeName, $this->requestedIncludes)) {
184 1
                continue;
185
            }
186 39
            $this->requestedIncludes[] = $includeName;
187
188
            // No Params? Bored
189 39
            if ($allModifiersStr === null) {
190 38
                continue;
191
            }
192
193
            // Matches multiple instances of 'something(foo|bar|baz)' in the string
194
            // I guess it ignores : so you could use anything, but probably don't do that
195 2
            preg_match_all('/([\w]+)(\(([^\)]+)\))?/', $allModifiersStr, $allModifiersArr);
196
197
            // [0] is full matched strings...
198 2
            $modifierCount = count($allModifiersArr[0]);
199
200 2
            $modifierArr = [];
201
202 2
            for ($modifierIt = 0; $modifierIt < $modifierCount; $modifierIt++) {
203
                // [1] is the modifier
204 2
                $modifierName = $allModifiersArr[1][$modifierIt];
205
206
                // and [3] is delimited params
207 2
                $modifierParamStr = $allModifiersArr[3][$modifierIt];
208
209
                // Make modifier array key with an array of params as the value
210 2
                $modifierArr[$modifierName] = explode($this->paramDelimiter, $modifierParamStr);
211 2
            }
212
213 2
            $this->includeParams[$includeName] = $modifierArr;
214 39
        }
215
216
        // This should be optional and public someday, but without it includes would never show up
217 39
        $this->autoIncludeParents();
218
219 39
        return $this;
220
    }
221
222
    /**
223
     * Parse field parameter.
224
     *
225
     * @param array $fieldsets Array of fields to include. It must be an array
226
     *                         whose keys are resource types and values a string
227
     *                         of the fields to return, separated by a comma
228
     *
229
     * @return $this
230
     */
231 13
    public function parseFieldsets(array $fieldsets)
232
    {
233 13
        $this->requestedFieldsets = [];
234 13
        foreach ($fieldsets as $type => $fields) {
235
            //Remove empty and repeated fields
236 13
            $this->requestedFieldsets[$type] = array_unique(array_filter(explode(',', $fields)));
237 13
        }
238 13
        return $this;
239
    }
240
241
    /**
242
     * Get requested fieldsets.
243
     *
244
     * @return array
245
     */
246 1
    public function getRequestedFieldsets()
247
    {
248 1
        return $this->requestedFieldsets;
249
    }
250
251
    /**
252
     * Get fieldset params for the specified type.
253
     *
254
     * @param string $type
255
     *
256
     * @return \League\Fractal\ParamBag|null
257
     */
258 46
    public function getFieldset($type)
259
    {
260 46
        return !isset($this->requestedFieldsets[$type]) ?
261 46
            null :
262 46
            new ParamBag($this->requestedFieldsets[$type]);
263
    }
264
265
    /**
266
     * Parse Exclude String.
267
     *
268
     * @param array|string $excludes Array or csv string of resources to exclude
269
     *
270
     * @return $this
271
     */
272 5
    public function parseExcludes($excludes)
273
    {
274 5
        $this->requestedExcludes = [];
275
276 5
        if (is_string($excludes)) {
277 2
            $excludes = explode(',', $excludes);
278 2
        }
279
280 5
        if (! is_array($excludes)) {
281 2
            throw new \InvalidArgumentException(
282 2
                'The parseExcludes() method expects a string or an array. '.gettype($excludes).' given'
283 2
            );
284
        }
285
286 3
        foreach ($excludes as $excludeName) {
287 3
            $excludeName = $this->trimToAcceptableRecursionLevel($excludeName);
288
289 3
            if (in_array($excludeName, $this->requestedExcludes)) {
290 1
                continue;
291
            }
292
293 3
            $this->requestedExcludes[] = $excludeName;
294 3
        }
295
296 3
        return $this;
297
    }
298
299
    /**
300
     * Set Recursion Limit.
301
     *
302
     * @param int $recursionLimit
303
     *
304
     * @return $this
305
     */
306 1
    public function setRecursionLimit($recursionLimit)
307
    {
308 1
        $this->recursionLimit = $recursionLimit;
309
310 1
        return $this;
311
    }
312
313
    /**
314
     * Set Serializer
315
     *
316
     * @param SerializerAbstract $serializer
317
     *
318
     * @return $this
319
     */
320 47
    public function setSerializer(SerializerAbstract $serializer)
321
    {
322 47
        $this->serializer = $serializer;
323
324 47
        return $this;
325
    }
326
327
    /**
328
     * Auto-include Parents
329
     *
330
     * Look at the requested includes and automatically include the parents if they
331
     * are not explicitly requested. E.g: [foo, bar.baz] becomes [foo, bar, bar.baz]
332
     *
333
     * @internal
334
     *
335
     * @return void
336
     */
337 39
    protected function autoIncludeParents()
338
    {
339 39
        $parsed = [];
340
341 39
        foreach ($this->requestedIncludes as $include) {
342 39
            $nested = explode('.', $include);
343
344 39
            $part = array_shift($nested);
345 39
            $parsed[] = $part;
346
347 39
            while (count($nested) > 0) {
348 11
                $part .= '.'.array_shift($nested);
349 11
                $parsed[] = $part;
350 11
            }
351 39
        }
352
353 39
        $this->requestedIncludes = array_values(array_unique($parsed));
354 39
    }
355
356
    /**
357
     * Trim to Acceptable Recursion Level
358
     *
359
     * Strip off any requested resources that are too many levels deep, to avoid DiCaprio being chased
360
     * by trains or whatever the hell that movie was about.
361
     *
362
     * @internal
363
     *
364
     * @param string $includeName
365
     *
366
     * @return string
367
     */
368 41
    protected function trimToAcceptableRecursionLevel($includeName)
369
    {
370 41
        return implode('.', array_slice(explode('.', $includeName), 0, $this->recursionLimit));
371
    }
372
}
373