Completed
Pull Request — master (#273)
by Gonçalo
03:51
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 32
    public function createData(ResourceInterface $resource, $scopeIdentifier = null, Scope $parentScopeInstance = null)
88
    {
89 32
        $scopeInstance = new Scope($this, $resource, $scopeIdentifier);
90
91
        // Update scope history
92 32
        if ($parentScopeInstance !== null) {
93
            // This will be the new children list of parents (parents parents, plus the parent)
94 27
            $scopeArray = $parentScopeInstance->getParentScopes();
95 27
            $scopeArray[] = $parentScopeInstance->getScopeIdentifier();
96
97 27
            $scopeInstance->setParentScopes($scopeArray);
98 27
        }
99
100 32
        return $scopeInstance;
101
    }
102
103
    /**
104
     * Get Include Params.
105
     *
106
     * @param string $include
107
     *
108
     * @return \League\Fractal\ParamBag|null
109
     */
110 23
    public function getIncludeParams($include)
111
    {
112 23
        if (! isset($this->includeParams[$include])) {
113 21
            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 34
    public function getRequestedIncludes()
127
    {
128 34
        return $this->requestedIncludes;
129
    }
130
131
    /**
132
     * Get Requested Excludes.
133
     *
134
     * @return array
135
     */
136 24
    public function getRequestedExcludes()
137
    {
138 24
        return $this->requestedExcludes;
139
    }
140
141
    /**
142
     * Get Serializer.
143
     *
144
     * @return SerializerAbstract
145
     */
146 39
    public function getSerializer()
147
    {
148 39
        if (! $this->serializer) {
149 7
            $this->setSerializer(new DataArraySerializer());
150 7
        }
151
152 39
        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 33
    public function parseIncludes($includes)
163
    {
164
        // Wipe these before we go again
165 33
        $this->requestedIncludes = $this->includeParams = [];
166
167 33
        if (is_string($includes)) {
168 27
            $includes = explode(',', $includes);
169 27
        }
170
171 33
        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 31
        foreach ($includes as $include) {
178 31
            list($includeName, $allModifiersStr) = array_pad(explode(':', $include, 2), 2, null);
179
180
            // Trim it down to a cool level of recursion
181 31
            $includeName = $this->trimToAcceptableRecursionLevel($includeName);
182
183 31
            if (in_array($includeName, $this->requestedIncludes)) {
184 1
                continue;
185
            }
186 31
            $this->requestedIncludes[] = $includeName;
187
188
            // No Params? Bored
189 31
            if ($allModifiersStr === null) {
190 30
                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 31
        }
215
216
        // This should be optional and public someday, but without it includes would never show up
217 31
        $this->autoIncludeParents();
218
219 31
        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
    public function parseFieldsets(array $fieldsets)
232
    {
233
        foreach ($fieldsets as $type => $fields) {
234
            $this->requestedFieldsets[$type] = explode(',', $fields);
235
        }
236
        return $this;
237
    }
238
239
    /**
240
     * Get requested fieldsets.
241
     *
242
     * @return array
243
     */
244
    public function getRequestedFieldsets()
245
    {
246
        return $this->requestedFieldsets;
247
    }
248
249
    /**
250
     * Get fieldset params for the specified type.
251
     *
252
     * @param string $type
253
     *
254
     * @return \League\Fractal\ParamBag|null
255
     */
256 39
    public function getFieldset($type)
257
    {
258 39
        return !isset($this->requestedFieldsets[$type]) ?
259 39
            null :
260 39
            new ParamBag($this->requestedFieldsets[$type]);
261
    }
262
263
    /**
264
     * Parse Exclude String.
265
     *
266
     * @param array|string $excludes Array or csv string of resources to exclude
267
     *
268
     * @return $this
269
     */
270 5
    public function parseExcludes($excludes)
271
    {
272 5
        $this->requestedExcludes = [];
273
274 5
        if (is_string($excludes)) {
275 2
            $excludes = explode(',', $excludes);
276 2
        }
277
278 5
        if (! is_array($excludes)) {
279 2
            throw new \InvalidArgumentException(
280 2
                'The parseExcludes() method expects a string or an array. '.gettype($excludes).' given'
281 2
            );
282
        }
283
284 3
        foreach ($excludes as $excludeName) {
285 3
            $excludeName = $this->trimToAcceptableRecursionLevel($excludeName);
286
287 3
            if (in_array($excludeName, $this->requestedExcludes)) {
288 1
                continue;
289
            }
290
291 3
            $this->requestedExcludes[] = $excludeName;
292 3
        }
293
294 3
        return $this;
295
    }
296
297
    /**
298
     * Set Recursion Limit.
299
     *
300
     * @param int $recursionLimit
301
     *
302
     * @return $this
303
     */
304 1
    public function setRecursionLimit($recursionLimit)
305
    {
306 1
        $this->recursionLimit = $recursionLimit;
307
308 1
        return $this;
309
    }
310
311
    /**
312
     * Set Serializer
313
     *
314
     * @param SerializerAbstract $serializer
315
     *
316
     * @return $this
317
     */
318 39
    public function setSerializer(SerializerAbstract $serializer)
319
    {
320 39
        $this->serializer = $serializer;
321
322 39
        return $this;
323
    }
324
325
    /**
326
     * Auto-include Parents
327
     *
328
     * Look at the requested includes and automatically include the parents if they
329
     * are not explicitly requested. E.g: [foo, bar.baz] becomes [foo, bar, bar.baz]
330
     *
331
     * @internal
332
     *
333
     * @return void
334
     */
335 31
    protected function autoIncludeParents()
336
    {
337 31
        $parsed = [];
338
339 31
        foreach ($this->requestedIncludes as $include) {
340 31
            $nested = explode('.', $include);
341
342 31
            $part = array_shift($nested);
343 31
            $parsed[] = $part;
344
345 31
            while (count($nested) > 0) {
346 7
                $part .= '.'.array_shift($nested);
347 7
                $parsed[] = $part;
348 7
            }
349 31
        }
350
351 31
        $this->requestedIncludes = array_values(array_unique($parsed));
352 31
    }
353
354
    /**
355
     * Trim to Acceptable Recursion Level
356
     *
357
     * Strip off any requested resources that are too many levels deep, to avoid DiCaprio being chased
358
     * by trains or whatever the hell that movie was about.
359
     *
360
     * @internal
361
     *
362
     * @param string $includeName
363
     *
364
     * @return string
365
     */
366 33
    protected function trimToAcceptableRecursionLevel($includeName)
367
    {
368 33
        return implode('.', array_slice(explode('.', $includeName), 0, $this->recursionLimit));
369
    }
370
}
371