Viewing file: Manager.php (8.6 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php
/* * This file is part of the League\Fractal package. * * (c) Phil Sturgeon <me@philsturgeon.uk> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */
namespace League\Fractal;
use League\Fractal\Resource\ResourceInterface; use League\Fractal\Serializer\DataArraySerializer; use League\Fractal\Serializer\Serializer;
/** * Manager * * Not a wildly creative name, but the manager is what a Fractal user will interact * with the most. The manager has various configurable options, and allows users * to create the "root scope" easily. */ class Manager { /** * Array of scope identifiers for resources to include. */ protected array $requestedIncludes = [];
/** * Array of scope identifiers for resources to exclude. */ protected array $requestedExcludes = [];
/** * Array of requested fieldsets. */ protected array $requestedFieldsets = [];
/** * Array containing modifiers as keys and an array value of params. */ protected array $includeParams = [];
/** * The character used to separate modifier parameters. */ protected string $paramDelimiter = '|';
/** * Upper limit to how many levels of included data are allowed. */ protected int $recursionLimit = 10;
protected ?Serializer $serializer = null;
/** * Factory used to create new configured scopes. */ private ScopeFactoryInterface $scopeFactory;
public function __construct(ScopeFactoryInterface $scopeFactory = null) { $this->scopeFactory = $scopeFactory ?: new ScopeFactory(); }
/** * Main method to kick this all off. Make a resource then pass it over, and use toArray() */ public function createData( ResourceInterface $resource, ?string $scopeIdentifier = null, Scope $parentScopeInstance = null ): Scope { if ($parentScopeInstance !== null) { return $this->scopeFactory->createChildScopeFor($this, $parentScopeInstance, $resource, $scopeIdentifier); }
return $this->scopeFactory->createScopeFor($this, $resource, $scopeIdentifier); }
public function getIncludeParams(string $include): ParamBag { $params = isset($this->includeParams[$include]) ? $this->includeParams[$include] : [];
return new ParamBag($params); }
public function getRequestedIncludes(): array { return $this->requestedIncludes; }
public function getRequestedExcludes(): array { return $this->requestedExcludes; }
public function getSerializer(): Serializer { if (! $this->serializer) { $this->serializer = new DataArraySerializer(); }
return $this->serializer; }
/** * @param array|string $includes Array or csv string of resources to include */ public function parseIncludes($includes): self { // Wipe these before we go again $this->requestedIncludes = $this->includeParams = []; $subRelations = '';
if (is_string($includes)) { $includes = explode(',', $includes); }
if (! is_array($includes)) { throw new \InvalidArgumentException( 'The parseIncludes() method expects a string or an array. '.gettype($includes).' given' ); }
foreach ($includes as $include) { list($includeName, $allModifiersStr) = array_pad(explode(':', $include, 2), 2, ''); $a = $allModifiersStr ? explode('.', $allModifiersStr, 2) : ['']; list($allModifiersStr, $subRelations) = array_pad($a, 2, null);
// Trim it down to a cool level of recursion $includeName = $this->trimToAcceptableRecursionLevel($includeName);
if (in_array($includeName, $this->requestedIncludes)) { continue; } $this->requestedIncludes[] = $includeName;
// No Params? Bored if ($allModifiersStr === null) { continue; }
// Matches multiple instances of 'something(foo|bar|baz)' in the string // I guess it ignores : so you could use anything, but probably don't do that preg_match_all('/([\w]+)(\(([^\)]+)\))?/', $allModifiersStr, $allModifiersArr);
// [0] is full matched strings... $modifierCount = count($allModifiersArr[0]);
$modifierArr = [];
for ($modifierIt = 0; $modifierIt < $modifierCount; $modifierIt++) { // [1] is the modifier $modifierName = $allModifiersArr[1][$modifierIt];
// and [3] is delimited params $modifierParamStr = $allModifiersArr[3][$modifierIt];
// Make modifier array key with an array of params as the value $modifierArr[$modifierName] = explode($this->paramDelimiter, $modifierParamStr); }
$this->includeParams[$includeName] = $modifierArr;
if ($subRelations) { $this->requestedIncludes[] = $this->trimToAcceptableRecursionLevel($includeName . '.' . $subRelations); } }
// This should be optional and public someday, but without it includes would never show up $this->autoIncludeParents();
return $this; }
/** * Parse field parameter. * * @param array $fieldsets Array of fields to include. It must be an array whose keys * are resource types and values an array or a string * of the fields to return, separated by a comma */ public function parseFieldsets(array $fieldsets): self { $this->requestedFieldsets = []; foreach ($fieldsets as $type => $fields) { if (is_string($fields)) { $fields = explode(',', $fields); }
//Remove empty and repeated fields $this->requestedFieldsets[$type] = array_unique(array_filter($fields)); } return $this; } public function getRequestedFieldsets(): array { return $this->requestedFieldsets; }
/** * Get fieldset params for the specified type. */ public function getFieldset(string $type): ?ParamBag { return !isset($this->requestedFieldsets[$type]) ? null : new ParamBag($this->requestedFieldsets[$type]); }
/** * @param array|string $excludes Array or csv string of resources to exclude */ public function parseExcludes($excludes): self { $this->requestedExcludes = [];
if (is_string($excludes)) { $excludes = explode(',', $excludes); }
if (! is_array($excludes)) { throw new \InvalidArgumentException( 'The parseExcludes() method expects a string or an array. '.gettype($excludes).' given' ); }
foreach ($excludes as $excludeName) { $excludeName = $this->trimToAcceptableRecursionLevel($excludeName);
if (in_array($excludeName, $this->requestedExcludes)) { continue; }
$this->requestedExcludes[] = $excludeName; }
return $this; }
public function setRecursionLimit(int $recursionLimit): self { $this->recursionLimit = $recursionLimit;
return $this; }
public function setSerializer(Serializer $serializer): self { $this->serializer = $serializer;
return $this; }
/** * Look at the requested includes and automatically include the parents if they * are not explicitly requested. E.g: [foo, bar.baz] becomes [foo, bar, bar.baz] * * @internal */ protected function autoIncludeParents(): void { $parsed = [];
foreach ($this->requestedIncludes as $include) { $nested = explode('.', $include);
$part = array_shift($nested); $parsed[] = $part;
while (count($nested) > 0) { $part .= '.'.array_shift($nested); $parsed[] = $part; } }
$this->requestedIncludes = array_values(array_unique($parsed)); }
/** * Strip off any requested resources that are too many levels deep, to avoid DiCaprio being chased * by trains or whatever the hell that movie was about. * * @internal */ protected function trimToAcceptableRecursionLevel(string $includeName): string { return implode('.', array_slice(explode('.', $includeName), 0, $this->recursionLimit)); } }
|