├── src ├── Bundle │ ├── JdeniauApiPlatformFilterValidatorBundle.php │ ├── DependencyInjection │ │ ├── Configuration.php │ │ └── JdeniauApiPlatformFilterValidatorExtension.php │ └── Resources │ │ └── config │ │ └── services.xml └── FilterValidator │ ├── Filter │ ├── Validator │ │ ├── ValidatorInterface.php │ │ ├── Enum.php │ │ ├── Pattern.php │ │ ├── MultipleOf.php │ │ ├── Length.php │ │ ├── Bounds.php │ │ ├── ArrayItems.php │ │ └── Required.php │ └── QueryParameterValidator.php │ └── EventListener │ └── QueryParameterValidateListener.php ├── README.md ├── composer.json ├── Makefile ├── .gitignore ├── LICENSE └── composer.lock /src/Bundle/JdeniauApiPlatformFilterValidatorBundle.php: -------------------------------------------------------------------------------- 1 | 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 | declare(strict_types=1); 13 | 14 | namespace ApiPlatformFilterValidator\ApiPlatform\Core\Filter\Validator; 15 | 16 | use Symfony\Component\HttpFoundation\Request; 17 | 18 | interface ValidatorInterface 19 | { 20 | public function validate(string $name, array $filterDescription, Request $request): array; 21 | } 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jdeniau/api-platform-filter-validator", 3 | "description": "Validate APIPlatform filter values, waiting https://github.com/api-platform/core/pull/1723 to be merged", 4 | "type": "symfony-bundle", 5 | "require": { 6 | "api-platform/core": "^2.3" 7 | }, 8 | "license": "MIT", 9 | "authors": [ 10 | { 11 | "name": "Julien Deniau", 12 | "email": "julien.deniau@gmail.com" 13 | } 14 | ], 15 | "autoload": { 16 | "psr-4": { 17 | "ApiPlatformFilterValidator\\ApiPlatform\\Core\\": "src/FilterValidator/", 18 | "Jdeniau\\ApiPlatformFilterValidatorBundle\\": "src/Bundle/" 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: clone extract change-namespace 2 | 3 | clean: 4 | rm -rf api-platform-core 5 | rm -rf src/FilterValidator/* 6 | 7 | clone: 8 | git clone git@github.com:jdeniau/api-platform-core.git api-platform-core --branch jd-feat-moreQueryParameterValidation 9 | 10 | extract: 11 | cd api-platform-core; \ 12 | git remote add upstream git@github.com:api-platform/core; \ 13 | git fetch upstream; \ 14 | git diff --name-only --diff-filter=d upstream/master..HEAD src | grep -v '\.xml' | xargs -I '{}' cp --parents '{}' ../src/FilterValidator/ 15 | mv src/FilterValidator/src/* src/FilterValidator 16 | rmdir src/FilterValidator/src/ 17 | 18 | change-namespace: 19 | find src -type f -name '*.php' -exec sed -i 's/namespace ApiPlatform/namespace ApiPlatformFilterValidator\\ApiPlatform/g' {} \; 20 | find src -type f -name '*.php' -exec sed -i 's/use ApiPlatform/use ApiPlatformFilterValidator\\ApiPlatform/g' {} \; 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Cache and logs (Symfony2) 2 | /app/cache/* 3 | /app/logs/* 4 | !app/cache/.gitkeep 5 | !app/logs/.gitkeep 6 | 7 | # Email spool folder 8 | /app/spool/* 9 | 10 | # Cache, session files and logs (Symfony3) 11 | /var/cache/* 12 | /var/logs/* 13 | /var/sessions/* 14 | !var/cache/.gitkeep 15 | !var/logs/.gitkeep 16 | !var/sessions/.gitkeep 17 | 18 | # Parameters 19 | /app/config/parameters.yml 20 | /app/config/parameters.ini 21 | 22 | # Managed by Composer 23 | /app/bootstrap.php.cache 24 | /var/bootstrap.php.cache 25 | /bin/* 26 | !bin/console 27 | !bin/symfony_requirements 28 | /vendor/ 29 | 30 | # Assets and user uploads 31 | /web/bundles/ 32 | /web/uploads/ 33 | 34 | # PHPUnit 35 | /app/phpunit.xml 36 | /phpunit.xml 37 | 38 | # Build data 39 | /build/ 40 | 41 | # Composer PHAR 42 | /composer.phar 43 | 44 | # Backup entities generated with doctrine:generate:entities command 45 | **/Entity/*~ 46 | 47 | # Embedded web-server pid file 48 | /.web-server-pid 49 | 50 | /api-platform-core/ 51 | -------------------------------------------------------------------------------- /src/Bundle/DependencyInjection/Configuration.php: -------------------------------------------------------------------------------- 1 | root('jdeniau_api_platform_filter_validator'); 22 | 23 | // Here you should define the parameters that are allowed to 24 | // configure your bundle. See the documentation linked above for 25 | // more information on that topic. 26 | 27 | return $treeBuilder; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Bundle/DependencyInjection/JdeniauApiPlatformFilterValidatorExtension.php: -------------------------------------------------------------------------------- 1 | processConfiguration($configuration, $configs); 24 | 25 | $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 26 | $loader->load('services.xml'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Julien Deniau 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/FilterValidator/Filter/Validator/Enum.php: -------------------------------------------------------------------------------- 1 | 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 | declare(strict_types=1); 13 | 14 | namespace ApiPlatformFilterValidator\ApiPlatform\Core\Filter\Validator; 15 | 16 | use Symfony\Component\HttpFoundation\Request; 17 | 18 | class Enum implements ValidatorInterface 19 | { 20 | public function validate(string $name, array $filterDescription, Request $request): array 21 | { 22 | $value = $request->query->get($name); 23 | if (empty($value) && '0' !== $value || !\is_string($value)) { 24 | return []; 25 | } 26 | 27 | $enum = $filterDescription['swagger']['enum'] ?? null; 28 | 29 | if (null !== $enum && !\in_array($value, $enum, true)) { 30 | return [ 31 | \sprintf('Query parameter "%s" must be one of "%s"', $name, implode(', ', $enum)), 32 | ]; 33 | } 34 | 35 | return []; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Bundle/Resources/config/services.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/FilterValidator/Filter/Validator/Pattern.php: -------------------------------------------------------------------------------- 1 | 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 | declare(strict_types=1); 13 | 14 | namespace ApiPlatformFilterValidator\ApiPlatform\Core\Filter\Validator; 15 | 16 | use Symfony\Component\HttpFoundation\Request; 17 | 18 | class Pattern implements ValidatorInterface 19 | { 20 | public function validate(string $name, array $filterDescription, Request $request): array 21 | { 22 | $value = $request->query->get($name); 23 | if (empty($value) && '0' !== $value || !\is_string($value)) { 24 | return []; 25 | } 26 | 27 | $pattern = $filterDescription['swagger']['pattern'] ?? null; 28 | 29 | if (null !== $pattern && !preg_match($pattern, $value)) { 30 | return [ 31 | \sprintf('Query parameter "%s" must match pattern %s', $name, $pattern), 32 | ]; 33 | } 34 | 35 | return []; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/FilterValidator/Filter/Validator/MultipleOf.php: -------------------------------------------------------------------------------- 1 | 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 | declare(strict_types=1); 13 | 14 | namespace ApiPlatformFilterValidator\ApiPlatform\Core\Filter\Validator; 15 | 16 | use Symfony\Component\HttpFoundation\Request; 17 | 18 | class MultipleOf implements ValidatorInterface 19 | { 20 | public function validate(string $name, array $filterDescription, Request $request): array 21 | { 22 | $value = $request->query->get($name); 23 | if (empty($value) && '0' !== $value || !\is_string($value)) { 24 | return []; 25 | } 26 | 27 | $multipleOf = $filterDescription['swagger']['multipleOf'] ?? null; 28 | 29 | if (null !== $multipleOf && 0 !== ($value % $multipleOf)) { 30 | return [ 31 | \sprintf('Query parameter "%s" must multiple of %s', $name, $multipleOf), 32 | ]; 33 | } 34 | 35 | return []; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/FilterValidator/Filter/Validator/Length.php: -------------------------------------------------------------------------------- 1 | 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 | declare(strict_types=1); 13 | 14 | namespace ApiPlatformFilterValidator\ApiPlatform\Core\Filter\Validator; 15 | 16 | use Symfony\Component\HttpFoundation\Request; 17 | 18 | class Length implements ValidatorInterface 19 | { 20 | public function validate(string $name, array $filterDescription, Request $request): array 21 | { 22 | $maxLength = $filterDescription['swagger']['maxLength'] ?? null; 23 | $minLength = $filterDescription['swagger']['minLength'] ?? null; 24 | 25 | $value = $request->query->get($name); 26 | if (empty($value) && '0' !== $value || !\is_string($value)) { 27 | return []; 28 | } 29 | 30 | $errorList = []; 31 | 32 | if (null !== $maxLength && mb_strlen($value) > $maxLength) { 33 | $errorList[] = \sprintf('Query parameter "%s" length must be lower than or equal to %s', $name, $maxLength); 34 | } 35 | 36 | if (null !== $minLength && mb_strlen($value) < $minLength) { 37 | $errorList[] = \sprintf('Query parameter "%s" length must be greater than or equal to %s', $name, $minLength); 38 | } 39 | 40 | return $errorList; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/FilterValidator/Filter/Validator/Bounds.php: -------------------------------------------------------------------------------- 1 | 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 | declare(strict_types=1); 13 | 14 | namespace ApiPlatformFilterValidator\ApiPlatform\Core\Filter\Validator; 15 | 16 | use Symfony\Component\HttpFoundation\Request; 17 | 18 | class Bounds implements ValidatorInterface 19 | { 20 | public function validate(string $name, array $filterDescription, Request $request): array 21 | { 22 | $value = $request->query->get($name); 23 | if (empty($value) && '0' !== $value) { 24 | return []; 25 | } 26 | 27 | $maximum = $filterDescription['swagger']['maximum'] ?? null; 28 | $minimum = $filterDescription['swagger']['minimum'] ?? null; 29 | 30 | $errorList = []; 31 | 32 | if (null !== $maximum) { 33 | if (($filterDescription['swagger']['exclusiveMaximum'] ?? false) && $value >= $maximum) { 34 | $errorList[] = \sprintf('Query parameter "%s" must be less than %s', $name, $maximum); 35 | } elseif ($value > $maximum) { 36 | $errorList[] = \sprintf('Query parameter "%s" must be less than or equal to %s', $name, $maximum); 37 | } 38 | } 39 | 40 | if (null !== $minimum) { 41 | if (($filterDescription['swagger']['exclusiveMinimum'] ?? false) && $value <= $minimum) { 42 | $errorList[] = \sprintf('Query parameter "%s" must be greater than %s', $name, $minimum); 43 | } elseif ($value < $minimum) { 44 | $errorList[] = \sprintf('Query parameter "%s" must be greater than or equal to %s', $name, $minimum); 45 | } 46 | } 47 | 48 | return $errorList; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/FilterValidator/Filter/QueryParameterValidator.php: -------------------------------------------------------------------------------- 1 | 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 | declare(strict_types=1); 13 | 14 | namespace ApiPlatformFilterValidator\ApiPlatform\Core\Filter; 15 | 16 | use ApiPlatform\Core\Api\FilterLocatorTrait; 17 | use ApiPlatform\Core\Exception\FilterValidationException; 18 | use Psr\Container\ContainerInterface; 19 | use Symfony\Component\HttpFoundation\Request; 20 | 21 | /** 22 | * Validates query parameters depending on filter description. 23 | * 24 | * @author Julien Deniau 25 | */ 26 | class QueryParameterValidator 27 | { 28 | use FilterLocatorTrait; 29 | 30 | private $validators; 31 | 32 | public function __construct(ContainerInterface $filterLocator) 33 | { 34 | $this->setFilterLocator($filterLocator); 35 | 36 | $this->validators = [ 37 | new Validator\ArrayItems(), 38 | new Validator\Bounds(), 39 | new Validator\Enum(), 40 | new Validator\Length(), 41 | new Validator\MultipleOf(), 42 | new Validator\Pattern(), 43 | new Validator\Required(), 44 | ]; 45 | } 46 | 47 | public function validateFilters(string $resourceClass, array $resourceFilters, Request $request) 48 | { 49 | $errorList = []; 50 | foreach ($resourceFilters as $filterId) { 51 | if (!$filter = $this->getFilter($filterId)) { 52 | continue; 53 | } 54 | 55 | foreach ($filter->getDescription($resourceClass) as $name => $data) { 56 | foreach ($this->validators as $validator) { 57 | $errorList = \array_merge($errorList, $validator->validate($name, $data, $request)); 58 | } 59 | } 60 | } 61 | 62 | if ($errorList) { 63 | throw new FilterValidationException($errorList); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/FilterValidator/EventListener/QueryParameterValidateListener.php: -------------------------------------------------------------------------------- 1 | 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 | declare(strict_types=1); 13 | 14 | namespace ApiPlatformFilterValidator\ApiPlatform\Core\EventListener; 15 | 16 | use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface; 17 | use ApiPlatform\Core\Util\RequestAttributesExtractor; 18 | use ApiPlatformFilterValidator\ApiPlatform\Core\Filter\QueryParameterValidator; 19 | use Symfony\Component\HttpKernel\Event\GetResponseEvent; 20 | 21 | /** 22 | * Validates query parameters depending on filter description. 23 | * 24 | * @author Julien Deniau 25 | */ 26 | final class QueryParameterValidateListener 27 | { 28 | private $resourceMetadataFactory; 29 | 30 | private $queryParameterValidator; 31 | 32 | public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactory, QueryParameterValidator $queryParameterValidator) 33 | { 34 | $this->resourceMetadataFactory = $resourceMetadataFactory; 35 | $this->queryParameterValidator = $queryParameterValidator; 36 | } 37 | 38 | public function onKernelRequest(GetResponseEvent $event) 39 | { 40 | $request = $event->getRequest(); 41 | if ( 42 | !$request->isMethodSafe(false) 43 | || !($attributes = RequestAttributesExtractor::extractAttributes($request)) 44 | || !isset($attributes['collection_operation_name']) 45 | || !($operationName = $attributes['collection_operation_name']) 46 | || $request->getMethod() != 'GET' 47 | ) { 48 | return; 49 | } 50 | 51 | $resourceMetadata = $this->resourceMetadataFactory->create($attributes['resource_class']); 52 | $resourceFilters = $resourceMetadata->getCollectionOperationAttribute($operationName, 'filters', [], true); 53 | 54 | $this->queryParameterValidator->validateFilters($attributes['resource_class'], $resourceFilters, $request); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/FilterValidator/Filter/Validator/ArrayItems.php: -------------------------------------------------------------------------------- 1 | 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 | declare(strict_types=1); 13 | 14 | namespace ApiPlatformFilterValidator\ApiPlatform\Core\Filter\Validator; 15 | 16 | use Symfony\Component\HttpFoundation\Request; 17 | 18 | class ArrayItems implements ValidatorInterface 19 | { 20 | public function validate(string $name, array $filterDescription, Request $request): array 21 | { 22 | if (!$request->query->has($name)) { 23 | return []; 24 | } 25 | 26 | $maxItems = $filterDescription['swagger']['maxItems'] ?? null; 27 | $minItems = $filterDescription['swagger']['minItems'] ?? null; 28 | $uniqueItems = $filterDescription['swagger']['uniqueItems'] ?? false; 29 | 30 | $errorList = []; 31 | 32 | $value = $this->getValue($name, $filterDescription, $request); 33 | $nbItems = \count($value); 34 | 35 | if (null !== $maxItems && $nbItems > $maxItems) { 36 | $errorList[] = \sprintf('Query parameter "%s" must contain less than %d values', $name, $maxItems); 37 | } 38 | 39 | if (null !== $minItems && $nbItems < $minItems) { 40 | $errorList[] = \sprintf('Query parameter "%s" must contain more than %d values', $name, $minItems); 41 | } 42 | 43 | if (true === $uniqueItems && $nbItems > \count(array_unique($value))) { 44 | $errorList[] = \sprintf('Query parameter "%s" must contain unique values', $name); 45 | } 46 | 47 | return $errorList; 48 | } 49 | 50 | private function getValue(string $name, array $filterDescription, Request $request): array 51 | { 52 | $value = $request->query->get($name); 53 | 54 | if (empty($value) && '0' !== $value) { 55 | return []; 56 | } 57 | 58 | if (\is_array($value)) { 59 | return $value; 60 | } 61 | 62 | $collectionFormat = $filterDescription['swagger']['collectionFormat'] ?? 'csv'; 63 | 64 | return explode(self::getSeparator($collectionFormat), $value) ?: []; 65 | } 66 | 67 | private static function getSeparator(string $collectionFormat): string 68 | { 69 | switch ($collectionFormat) { 70 | case 'csv': 71 | return ','; 72 | case 'ssv': 73 | return ' '; 74 | case 'tsv': 75 | return '\t'; 76 | case 'pipes': 77 | return '|'; 78 | default: 79 | throw new \InvalidArgumentException(sprintf('Unknown collection format %s', $collectionFormat)); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/FilterValidator/Filter/Validator/Required.php: -------------------------------------------------------------------------------- 1 | 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 | declare(strict_types=1); 13 | 14 | namespace ApiPlatformFilterValidator\ApiPlatform\Core\Filter\Validator; 15 | 16 | use Symfony\Component\HttpFoundation\Request; 17 | 18 | class Required implements ValidatorInterface 19 | { 20 | public function validate(string $name, array $filterDescription, Request $request): array 21 | { 22 | // filter is not required, the `checkRequired` method can not break 23 | if (!($filterDescription['required'] ?? false)) { 24 | return []; 25 | } 26 | 27 | // if query param is not given, then break 28 | if (!$this->requestHasQueryParameter($request, $name)) { 29 | return [ 30 | \sprintf('Query parameter "%s" is required', $name), 31 | ]; 32 | } 33 | 34 | // if query param is empty and the configuration does not allow it 35 | if (!($filterDescription['swagger']['allowEmptyValue'] ?? false) && empty($this->requestGetQueryParameter($request, $name))) { 36 | return [ 37 | \sprintf('Query parameter "%s" does not allow empty value', $name), 38 | ]; 39 | } 40 | 41 | return []; 42 | } 43 | 44 | /** 45 | * Test if request has required parameter. 46 | */ 47 | private function requestHasQueryParameter(Request $request, string $name): bool 48 | { 49 | $matches = []; 50 | parse_str($name, $matches); 51 | if (!$matches) { 52 | return false; 53 | } 54 | 55 | $rootName = \array_keys($matches)[0] ?? ''; 56 | if (!$rootName) { 57 | return false; 58 | } 59 | 60 | if (\is_array($matches[$rootName])) { 61 | $keyName = \array_keys($matches[$rootName])[0]; 62 | 63 | $queryParameter = $request->query->get((string) $rootName); 64 | 65 | return \is_array($queryParameter) && isset($queryParameter[$keyName]); 66 | } 67 | 68 | return $request->query->has((string) $rootName); 69 | } 70 | 71 | /** 72 | * Test if required filter is valid. It validates array notation too like "required[bar]". 73 | */ 74 | private function requestGetQueryParameter(Request $request, string $name) 75 | { 76 | $matches = []; 77 | \parse_str($name, $matches); 78 | if (empty($matches)) { 79 | return null; 80 | } 81 | 82 | $rootName = \array_keys($matches)[0] ?? ''; 83 | if (!$rootName) { 84 | return null; 85 | } 86 | 87 | if (\is_array($matches[$rootName])) { 88 | $keyName = \array_keys($matches[$rootName])[0]; 89 | 90 | $queryParameter = $request->query->get((string) $rootName); 91 | 92 | if (\is_array($queryParameter) && isset($queryParameter[$keyName])) { 93 | return $queryParameter[$keyName]; 94 | } 95 | 96 | return null; 97 | } 98 | 99 | return $request->query->get((string) $rootName); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "915c8d21de95f2e873a3ce5be8b1a6f9", 8 | "packages": [ 9 | { 10 | "name": "api-platform/core", 11 | "version": "v2.3.6", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/api-platform/core.git", 15 | "reference": "f12aa2ae9ee67e7c948cd3161ad980d35210bed7" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/api-platform/core/zipball/f12aa2ae9ee67e7c948cd3161ad980d35210bed7", 20 | "reference": "f12aa2ae9ee67e7c948cd3161ad980d35210bed7", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "doctrine/inflector": "^1.0", 25 | "php": ">=7.1", 26 | "psr/cache": "^1.0", 27 | "psr/container": "^1.0", 28 | "symfony/http-foundation": "^3.4 || ^4.0", 29 | "symfony/http-kernel": "^3.4 || ^4.0", 30 | "symfony/property-access": "^3.4 || ^4.0", 31 | "symfony/property-info": "^3.4 || ^4.0", 32 | "symfony/serializer": "^4.1", 33 | "willdurand/negotiation": "^2.0.3" 34 | }, 35 | "conflict": { 36 | "doctrine/common": "<2.7" 37 | }, 38 | "require-dev": { 39 | "behat/behat": "^3.1", 40 | "behat/mink": "^1.7", 41 | "behat/mink-browserkit-driver": "^1.3.1", 42 | "behat/mink-extension": "^2.2", 43 | "behat/symfony2-extension": "^2.1.1", 44 | "behatch/contexts": "3.1.0", 45 | "doctrine/annotations": "^1.2", 46 | "doctrine/doctrine-bundle": "^1.8", 47 | "doctrine/orm": "^2.6.3", 48 | "friendsofsymfony/user-bundle": "^2.1", 49 | "guzzlehttp/guzzle": "^6.0", 50 | "justinrainbow/json-schema": "^5.0", 51 | "nelmio/api-doc-bundle": "^2.13.3", 52 | "php-mock/php-mock-phpunit": "^2.0", 53 | "phpdocumentor/reflection-docblock": "^3.0 || ^4.0", 54 | "phpdocumentor/type-resolver": "^0.3 || ^0.4", 55 | "phpunit/phpunit": "^6.1", 56 | "psr/log": "^1.0", 57 | "ramsey/uuid": "^3.7", 58 | "ramsey/uuid-doctrine": "^1.4", 59 | "symfony/asset": "^3.4 || ^4.0", 60 | "symfony/cache": "^3.4 || ^4.0", 61 | "symfony/config": "^3.4 || ^4.0", 62 | "symfony/console": "^3.4 || ^4.0", 63 | "symfony/debug": "^3.4 || ^4.0", 64 | "symfony/dependency-injection": "^3.4 || ^4.0", 65 | "symfony/doctrine-bridge": "^3.4 || ^4.0", 66 | "symfony/event-dispatcher": "^3.4 || ^4.0", 67 | "symfony/expression-language": "^3.4 || ^4.0", 68 | "symfony/finder": "^3.4 || ^4.0", 69 | "symfony/form": "^3.4 || ^4.0", 70 | "symfony/framework-bundle": "^3.4 || ^4.0", 71 | "symfony/phpunit-bridge": "^3.4 || ^4.0", 72 | "symfony/routing": "^3.4 || ^4.0", 73 | "symfony/security": "^3.4 || ^4.0", 74 | "symfony/security-bundle": "^3.4 || ^4.0", 75 | "symfony/twig-bundle": "^3.4 || ^4.0", 76 | "symfony/validator": "^3.4 || ^4.0", 77 | "symfony/web-profiler-bundle": "^3.4 || ^4.0", 78 | "symfony/yaml": "^3.4 || ^4.0", 79 | "webonyx/graphql-php": ">=0.13 <1.0" 80 | }, 81 | "suggest": { 82 | "friendsofsymfony/user-bundle": "To use the FOSUserBundle bridge.", 83 | "guzzlehttp/guzzle": "To use the HTTP cache invalidation system.", 84 | "phpdocumentor/reflection-docblock": "To support extracting metadata from PHPDoc.", 85 | "psr/cache-implementation": "To use metadata caching.", 86 | "ramsey/uuid": "To support Ramsey's UUID identifiers.", 87 | "symfony/cache": "To have metadata caching when using Symfony integration.", 88 | "symfony/config": "To load XML configuration files.", 89 | "symfony/expression-language": "To use authorization features.", 90 | "symfony/security": "To use authorization features.", 91 | "symfony/twig-bundle": "To use the Swagger UI integration.", 92 | "symfony/web-profiler-bundle": "To use the data collector.", 93 | "webonyx/graphql-php": "To support GraphQL." 94 | }, 95 | "type": "library", 96 | "extra": { 97 | "branch-alias": { 98 | "dev-master": "2.3.x-dev" 99 | } 100 | }, 101 | "autoload": { 102 | "psr-4": { 103 | "ApiPlatform\\Core\\": "src/" 104 | } 105 | }, 106 | "notification-url": "https://packagist.org/downloads/", 107 | "license": [ 108 | "MIT" 109 | ], 110 | "authors": [ 111 | { 112 | "name": "Kévin Dunglas", 113 | "email": "dunglas@gmail.com", 114 | "homepage": "https://dunglas.fr" 115 | } 116 | ], 117 | "description": "Build a fully-featured hypermedia or GraphQL API in minutes", 118 | "homepage": "https://api-platform.com", 119 | "keywords": [ 120 | "Hydra", 121 | "JSON-LD", 122 | "api", 123 | "graphql", 124 | "hal", 125 | "jsonapi", 126 | "openapi", 127 | "rest", 128 | "swagger" 129 | ], 130 | "time": "2019-01-15T16:10:35+00:00" 131 | }, 132 | { 133 | "name": "doctrine/inflector", 134 | "version": "v1.3.0", 135 | "source": { 136 | "type": "git", 137 | "url": "https://github.com/doctrine/inflector.git", 138 | "reference": "5527a48b7313d15261292c149e55e26eae771b0a" 139 | }, 140 | "dist": { 141 | "type": "zip", 142 | "url": "https://api.github.com/repos/doctrine/inflector/zipball/5527a48b7313d15261292c149e55e26eae771b0a", 143 | "reference": "5527a48b7313d15261292c149e55e26eae771b0a", 144 | "shasum": "" 145 | }, 146 | "require": { 147 | "php": "^7.1" 148 | }, 149 | "require-dev": { 150 | "phpunit/phpunit": "^6.2" 151 | }, 152 | "type": "library", 153 | "extra": { 154 | "branch-alias": { 155 | "dev-master": "1.3.x-dev" 156 | } 157 | }, 158 | "autoload": { 159 | "psr-4": { 160 | "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector" 161 | } 162 | }, 163 | "notification-url": "https://packagist.org/downloads/", 164 | "license": [ 165 | "MIT" 166 | ], 167 | "authors": [ 168 | { 169 | "name": "Roman Borschel", 170 | "email": "roman@code-factory.org" 171 | }, 172 | { 173 | "name": "Benjamin Eberlei", 174 | "email": "kontakt@beberlei.de" 175 | }, 176 | { 177 | "name": "Guilherme Blanco", 178 | "email": "guilhermeblanco@gmail.com" 179 | }, 180 | { 181 | "name": "Jonathan Wage", 182 | "email": "jonwage@gmail.com" 183 | }, 184 | { 185 | "name": "Johannes Schmitt", 186 | "email": "schmittjoh@gmail.com" 187 | } 188 | ], 189 | "description": "Common String Manipulations with regard to casing and singular/plural rules.", 190 | "homepage": "http://www.doctrine-project.org", 191 | "keywords": [ 192 | "inflection", 193 | "pluralize", 194 | "singularize", 195 | "string" 196 | ], 197 | "time": "2018-01-09T20:05:19+00:00" 198 | }, 199 | { 200 | "name": "psr/cache", 201 | "version": "1.0.1", 202 | "source": { 203 | "type": "git", 204 | "url": "https://github.com/php-fig/cache.git", 205 | "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" 206 | }, 207 | "dist": { 208 | "type": "zip", 209 | "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", 210 | "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", 211 | "shasum": "" 212 | }, 213 | "require": { 214 | "php": ">=5.3.0" 215 | }, 216 | "type": "library", 217 | "extra": { 218 | "branch-alias": { 219 | "dev-master": "1.0.x-dev" 220 | } 221 | }, 222 | "autoload": { 223 | "psr-4": { 224 | "Psr\\Cache\\": "src/" 225 | } 226 | }, 227 | "notification-url": "https://packagist.org/downloads/", 228 | "license": [ 229 | "MIT" 230 | ], 231 | "authors": [ 232 | { 233 | "name": "PHP-FIG", 234 | "homepage": "http://www.php-fig.org/" 235 | } 236 | ], 237 | "description": "Common interface for caching libraries", 238 | "keywords": [ 239 | "cache", 240 | "psr", 241 | "psr-6" 242 | ], 243 | "time": "2016-08-06T20:24:11+00:00" 244 | }, 245 | { 246 | "name": "psr/container", 247 | "version": "1.0.0", 248 | "source": { 249 | "type": "git", 250 | "url": "https://github.com/php-fig/container.git", 251 | "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" 252 | }, 253 | "dist": { 254 | "type": "zip", 255 | "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", 256 | "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", 257 | "shasum": "" 258 | }, 259 | "require": { 260 | "php": ">=5.3.0" 261 | }, 262 | "type": "library", 263 | "extra": { 264 | "branch-alias": { 265 | "dev-master": "1.0.x-dev" 266 | } 267 | }, 268 | "autoload": { 269 | "psr-4": { 270 | "Psr\\Container\\": "src/" 271 | } 272 | }, 273 | "notification-url": "https://packagist.org/downloads/", 274 | "license": [ 275 | "MIT" 276 | ], 277 | "authors": [ 278 | { 279 | "name": "PHP-FIG", 280 | "homepage": "http://www.php-fig.org/" 281 | } 282 | ], 283 | "description": "Common Container Interface (PHP FIG PSR-11)", 284 | "homepage": "https://github.com/php-fig/container", 285 | "keywords": [ 286 | "PSR-11", 287 | "container", 288 | "container-interface", 289 | "container-interop", 290 | "psr" 291 | ], 292 | "time": "2017-02-14T16:28:37+00:00" 293 | }, 294 | { 295 | "name": "psr/log", 296 | "version": "1.1.0", 297 | "source": { 298 | "type": "git", 299 | "url": "https://github.com/php-fig/log.git", 300 | "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd" 301 | }, 302 | "dist": { 303 | "type": "zip", 304 | "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", 305 | "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", 306 | "shasum": "" 307 | }, 308 | "require": { 309 | "php": ">=5.3.0" 310 | }, 311 | "type": "library", 312 | "extra": { 313 | "branch-alias": { 314 | "dev-master": "1.0.x-dev" 315 | } 316 | }, 317 | "autoload": { 318 | "psr-4": { 319 | "Psr\\Log\\": "Psr/Log/" 320 | } 321 | }, 322 | "notification-url": "https://packagist.org/downloads/", 323 | "license": [ 324 | "MIT" 325 | ], 326 | "authors": [ 327 | { 328 | "name": "PHP-FIG", 329 | "homepage": "http://www.php-fig.org/" 330 | } 331 | ], 332 | "description": "Common interface for logging libraries", 333 | "homepage": "https://github.com/php-fig/log", 334 | "keywords": [ 335 | "log", 336 | "psr", 337 | "psr-3" 338 | ], 339 | "time": "2018-11-20T15:27:04+00:00" 340 | }, 341 | { 342 | "name": "symfony/contracts", 343 | "version": "v1.0.2", 344 | "source": { 345 | "type": "git", 346 | "url": "https://github.com/symfony/contracts.git", 347 | "reference": "1aa7ab2429c3d594dd70689604b5cf7421254cdf" 348 | }, 349 | "dist": { 350 | "type": "zip", 351 | "url": "https://api.github.com/repos/symfony/contracts/zipball/1aa7ab2429c3d594dd70689604b5cf7421254cdf", 352 | "reference": "1aa7ab2429c3d594dd70689604b5cf7421254cdf", 353 | "shasum": "" 354 | }, 355 | "require": { 356 | "php": "^7.1.3" 357 | }, 358 | "require-dev": { 359 | "psr/cache": "^1.0", 360 | "psr/container": "^1.0" 361 | }, 362 | "suggest": { 363 | "psr/cache": "When using the Cache contracts", 364 | "psr/container": "When using the Service contracts", 365 | "symfony/cache-contracts-implementation": "", 366 | "symfony/service-contracts-implementation": "", 367 | "symfony/translation-contracts-implementation": "" 368 | }, 369 | "type": "library", 370 | "extra": { 371 | "branch-alias": { 372 | "dev-master": "1.0-dev" 373 | } 374 | }, 375 | "autoload": { 376 | "psr-4": { 377 | "Symfony\\Contracts\\": "" 378 | }, 379 | "exclude-from-classmap": [ 380 | "**/Tests/" 381 | ] 382 | }, 383 | "notification-url": "https://packagist.org/downloads/", 384 | "license": [ 385 | "MIT" 386 | ], 387 | "authors": [ 388 | { 389 | "name": "Nicolas Grekas", 390 | "email": "p@tchwork.com" 391 | }, 392 | { 393 | "name": "Symfony Community", 394 | "homepage": "https://symfony.com/contributors" 395 | } 396 | ], 397 | "description": "A set of abstractions extracted out of the Symfony components", 398 | "homepage": "https://symfony.com", 399 | "keywords": [ 400 | "abstractions", 401 | "contracts", 402 | "decoupling", 403 | "interfaces", 404 | "interoperability", 405 | "standards" 406 | ], 407 | "time": "2018-12-05T08:06:11+00:00" 408 | }, 409 | { 410 | "name": "symfony/debug", 411 | "version": "v4.2.2", 412 | "source": { 413 | "type": "git", 414 | "url": "https://github.com/symfony/debug.git", 415 | "reference": "64cb33c81e37d19b7715d4a6a4d49c1c382066dd" 416 | }, 417 | "dist": { 418 | "type": "zip", 419 | "url": "https://api.github.com/repos/symfony/debug/zipball/64cb33c81e37d19b7715d4a6a4d49c1c382066dd", 420 | "reference": "64cb33c81e37d19b7715d4a6a4d49c1c382066dd", 421 | "shasum": "" 422 | }, 423 | "require": { 424 | "php": "^7.1.3", 425 | "psr/log": "~1.0" 426 | }, 427 | "conflict": { 428 | "symfony/http-kernel": "<3.4" 429 | }, 430 | "require-dev": { 431 | "symfony/http-kernel": "~3.4|~4.0" 432 | }, 433 | "type": "library", 434 | "extra": { 435 | "branch-alias": { 436 | "dev-master": "4.2-dev" 437 | } 438 | }, 439 | "autoload": { 440 | "psr-4": { 441 | "Symfony\\Component\\Debug\\": "" 442 | }, 443 | "exclude-from-classmap": [ 444 | "/Tests/" 445 | ] 446 | }, 447 | "notification-url": "https://packagist.org/downloads/", 448 | "license": [ 449 | "MIT" 450 | ], 451 | "authors": [ 452 | { 453 | "name": "Fabien Potencier", 454 | "email": "fabien@symfony.com" 455 | }, 456 | { 457 | "name": "Symfony Community", 458 | "homepage": "https://symfony.com/contributors" 459 | } 460 | ], 461 | "description": "Symfony Debug Component", 462 | "homepage": "https://symfony.com", 463 | "time": "2019-01-03T09:07:35+00:00" 464 | }, 465 | { 466 | "name": "symfony/event-dispatcher", 467 | "version": "v4.2.2", 468 | "source": { 469 | "type": "git", 470 | "url": "https://github.com/symfony/event-dispatcher.git", 471 | "reference": "887de6d34c86cf0cb6cbf910afb170cdb743cb5e" 472 | }, 473 | "dist": { 474 | "type": "zip", 475 | "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/887de6d34c86cf0cb6cbf910afb170cdb743cb5e", 476 | "reference": "887de6d34c86cf0cb6cbf910afb170cdb743cb5e", 477 | "shasum": "" 478 | }, 479 | "require": { 480 | "php": "^7.1.3", 481 | "symfony/contracts": "^1.0" 482 | }, 483 | "conflict": { 484 | "symfony/dependency-injection": "<3.4" 485 | }, 486 | "require-dev": { 487 | "psr/log": "~1.0", 488 | "symfony/config": "~3.4|~4.0", 489 | "symfony/dependency-injection": "~3.4|~4.0", 490 | "symfony/expression-language": "~3.4|~4.0", 491 | "symfony/stopwatch": "~3.4|~4.0" 492 | }, 493 | "suggest": { 494 | "symfony/dependency-injection": "", 495 | "symfony/http-kernel": "" 496 | }, 497 | "type": "library", 498 | "extra": { 499 | "branch-alias": { 500 | "dev-master": "4.2-dev" 501 | } 502 | }, 503 | "autoload": { 504 | "psr-4": { 505 | "Symfony\\Component\\EventDispatcher\\": "" 506 | }, 507 | "exclude-from-classmap": [ 508 | "/Tests/" 509 | ] 510 | }, 511 | "notification-url": "https://packagist.org/downloads/", 512 | "license": [ 513 | "MIT" 514 | ], 515 | "authors": [ 516 | { 517 | "name": "Fabien Potencier", 518 | "email": "fabien@symfony.com" 519 | }, 520 | { 521 | "name": "Symfony Community", 522 | "homepage": "https://symfony.com/contributors" 523 | } 524 | ], 525 | "description": "Symfony EventDispatcher Component", 526 | "homepage": "https://symfony.com", 527 | "time": "2019-01-05T16:37:49+00:00" 528 | }, 529 | { 530 | "name": "symfony/http-foundation", 531 | "version": "v4.2.2", 532 | "source": { 533 | "type": "git", 534 | "url": "https://github.com/symfony/http-foundation.git", 535 | "reference": "a633d422a09242064ba24e44a6e1494c5126de86" 536 | }, 537 | "dist": { 538 | "type": "zip", 539 | "url": "https://api.github.com/repos/symfony/http-foundation/zipball/a633d422a09242064ba24e44a6e1494c5126de86", 540 | "reference": "a633d422a09242064ba24e44a6e1494c5126de86", 541 | "shasum": "" 542 | }, 543 | "require": { 544 | "php": "^7.1.3", 545 | "symfony/polyfill-mbstring": "~1.1" 546 | }, 547 | "require-dev": { 548 | "predis/predis": "~1.0", 549 | "symfony/expression-language": "~3.4|~4.0" 550 | }, 551 | "type": "library", 552 | "extra": { 553 | "branch-alias": { 554 | "dev-master": "4.2-dev" 555 | } 556 | }, 557 | "autoload": { 558 | "psr-4": { 559 | "Symfony\\Component\\HttpFoundation\\": "" 560 | }, 561 | "exclude-from-classmap": [ 562 | "/Tests/" 563 | ] 564 | }, 565 | "notification-url": "https://packagist.org/downloads/", 566 | "license": [ 567 | "MIT" 568 | ], 569 | "authors": [ 570 | { 571 | "name": "Fabien Potencier", 572 | "email": "fabien@symfony.com" 573 | }, 574 | { 575 | "name": "Symfony Community", 576 | "homepage": "https://symfony.com/contributors" 577 | } 578 | ], 579 | "description": "Symfony HttpFoundation Component", 580 | "homepage": "https://symfony.com", 581 | "time": "2019-01-05T16:37:49+00:00" 582 | }, 583 | { 584 | "name": "symfony/http-kernel", 585 | "version": "v4.2.2", 586 | "source": { 587 | "type": "git", 588 | "url": "https://github.com/symfony/http-kernel.git", 589 | "reference": "83de6543328917c18d5498eeb6bb6d36f7aab31b" 590 | }, 591 | "dist": { 592 | "type": "zip", 593 | "url": "https://api.github.com/repos/symfony/http-kernel/zipball/83de6543328917c18d5498eeb6bb6d36f7aab31b", 594 | "reference": "83de6543328917c18d5498eeb6bb6d36f7aab31b", 595 | "shasum": "" 596 | }, 597 | "require": { 598 | "php": "^7.1.3", 599 | "psr/log": "~1.0", 600 | "symfony/contracts": "^1.0.2", 601 | "symfony/debug": "~3.4|~4.0", 602 | "symfony/event-dispatcher": "~4.1", 603 | "symfony/http-foundation": "^4.1.1", 604 | "symfony/polyfill-ctype": "~1.8" 605 | }, 606 | "conflict": { 607 | "symfony/config": "<3.4", 608 | "symfony/dependency-injection": "<4.2", 609 | "symfony/translation": "<4.2", 610 | "symfony/var-dumper": "<4.1.1", 611 | "twig/twig": "<1.34|<2.4,>=2" 612 | }, 613 | "provide": { 614 | "psr/log-implementation": "1.0" 615 | }, 616 | "require-dev": { 617 | "psr/cache": "~1.0", 618 | "symfony/browser-kit": "~3.4|~4.0", 619 | "symfony/config": "~3.4|~4.0", 620 | "symfony/console": "~3.4|~4.0", 621 | "symfony/css-selector": "~3.4|~4.0", 622 | "symfony/dependency-injection": "^4.2", 623 | "symfony/dom-crawler": "~3.4|~4.0", 624 | "symfony/expression-language": "~3.4|~4.0", 625 | "symfony/finder": "~3.4|~4.0", 626 | "symfony/process": "~3.4|~4.0", 627 | "symfony/routing": "~3.4|~4.0", 628 | "symfony/stopwatch": "~3.4|~4.0", 629 | "symfony/templating": "~3.4|~4.0", 630 | "symfony/translation": "~4.2", 631 | "symfony/var-dumper": "^4.1.1" 632 | }, 633 | "suggest": { 634 | "symfony/browser-kit": "", 635 | "symfony/config": "", 636 | "symfony/console": "", 637 | "symfony/dependency-injection": "", 638 | "symfony/var-dumper": "" 639 | }, 640 | "type": "library", 641 | "extra": { 642 | "branch-alias": { 643 | "dev-master": "4.2-dev" 644 | } 645 | }, 646 | "autoload": { 647 | "psr-4": { 648 | "Symfony\\Component\\HttpKernel\\": "" 649 | }, 650 | "exclude-from-classmap": [ 651 | "/Tests/" 652 | ] 653 | }, 654 | "notification-url": "https://packagist.org/downloads/", 655 | "license": [ 656 | "MIT" 657 | ], 658 | "authors": [ 659 | { 660 | "name": "Fabien Potencier", 661 | "email": "fabien@symfony.com" 662 | }, 663 | { 664 | "name": "Symfony Community", 665 | "homepage": "https://symfony.com/contributors" 666 | } 667 | ], 668 | "description": "Symfony HttpKernel Component", 669 | "homepage": "https://symfony.com", 670 | "time": "2019-01-06T16:19:23+00:00" 671 | }, 672 | { 673 | "name": "symfony/inflector", 674 | "version": "v4.2.2", 675 | "source": { 676 | "type": "git", 677 | "url": "https://github.com/symfony/inflector.git", 678 | "reference": "9f64271222922ef1a10e43f77d88baf72bf22b0e" 679 | }, 680 | "dist": { 681 | "type": "zip", 682 | "url": "https://api.github.com/repos/symfony/inflector/zipball/9f64271222922ef1a10e43f77d88baf72bf22b0e", 683 | "reference": "9f64271222922ef1a10e43f77d88baf72bf22b0e", 684 | "shasum": "" 685 | }, 686 | "require": { 687 | "php": "^7.1.3", 688 | "symfony/polyfill-ctype": "~1.8" 689 | }, 690 | "type": "library", 691 | "extra": { 692 | "branch-alias": { 693 | "dev-master": "4.2-dev" 694 | } 695 | }, 696 | "autoload": { 697 | "psr-4": { 698 | "Symfony\\Component\\Inflector\\": "" 699 | }, 700 | "exclude-from-classmap": [ 701 | "/Tests/" 702 | ] 703 | }, 704 | "notification-url": "https://packagist.org/downloads/", 705 | "license": [ 706 | "MIT" 707 | ], 708 | "authors": [ 709 | { 710 | "name": "Bernhard Schussek", 711 | "email": "bschussek@gmail.com" 712 | }, 713 | { 714 | "name": "Symfony Community", 715 | "homepage": "https://symfony.com/contributors" 716 | } 717 | ], 718 | "description": "Symfony Inflector Component", 719 | "homepage": "https://symfony.com", 720 | "keywords": [ 721 | "inflection", 722 | "pluralize", 723 | "singularize", 724 | "string", 725 | "symfony", 726 | "words" 727 | ], 728 | "time": "2019-01-03T09:07:35+00:00" 729 | }, 730 | { 731 | "name": "symfony/polyfill-ctype", 732 | "version": "v1.10.0", 733 | "source": { 734 | "type": "git", 735 | "url": "https://github.com/symfony/polyfill-ctype.git", 736 | "reference": "e3d826245268269cd66f8326bd8bc066687b4a19" 737 | }, 738 | "dist": { 739 | "type": "zip", 740 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19", 741 | "reference": "e3d826245268269cd66f8326bd8bc066687b4a19", 742 | "shasum": "" 743 | }, 744 | "require": { 745 | "php": ">=5.3.3" 746 | }, 747 | "suggest": { 748 | "ext-ctype": "For best performance" 749 | }, 750 | "type": "library", 751 | "extra": { 752 | "branch-alias": { 753 | "dev-master": "1.9-dev" 754 | } 755 | }, 756 | "autoload": { 757 | "psr-4": { 758 | "Symfony\\Polyfill\\Ctype\\": "" 759 | }, 760 | "files": [ 761 | "bootstrap.php" 762 | ] 763 | }, 764 | "notification-url": "https://packagist.org/downloads/", 765 | "license": [ 766 | "MIT" 767 | ], 768 | "authors": [ 769 | { 770 | "name": "Symfony Community", 771 | "homepage": "https://symfony.com/contributors" 772 | }, 773 | { 774 | "name": "Gert de Pagter", 775 | "email": "backendtea@gmail.com" 776 | } 777 | ], 778 | "description": "Symfony polyfill for ctype functions", 779 | "homepage": "https://symfony.com", 780 | "keywords": [ 781 | "compatibility", 782 | "ctype", 783 | "polyfill", 784 | "portable" 785 | ], 786 | "time": "2018-08-06T14:22:27+00:00" 787 | }, 788 | { 789 | "name": "symfony/polyfill-mbstring", 790 | "version": "v1.10.0", 791 | "source": { 792 | "type": "git", 793 | "url": "https://github.com/symfony/polyfill-mbstring.git", 794 | "reference": "c79c051f5b3a46be09205c73b80b346e4153e494" 795 | }, 796 | "dist": { 797 | "type": "zip", 798 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494", 799 | "reference": "c79c051f5b3a46be09205c73b80b346e4153e494", 800 | "shasum": "" 801 | }, 802 | "require": { 803 | "php": ">=5.3.3" 804 | }, 805 | "suggest": { 806 | "ext-mbstring": "For best performance" 807 | }, 808 | "type": "library", 809 | "extra": { 810 | "branch-alias": { 811 | "dev-master": "1.9-dev" 812 | } 813 | }, 814 | "autoload": { 815 | "psr-4": { 816 | "Symfony\\Polyfill\\Mbstring\\": "" 817 | }, 818 | "files": [ 819 | "bootstrap.php" 820 | ] 821 | }, 822 | "notification-url": "https://packagist.org/downloads/", 823 | "license": [ 824 | "MIT" 825 | ], 826 | "authors": [ 827 | { 828 | "name": "Nicolas Grekas", 829 | "email": "p@tchwork.com" 830 | }, 831 | { 832 | "name": "Symfony Community", 833 | "homepage": "https://symfony.com/contributors" 834 | } 835 | ], 836 | "description": "Symfony polyfill for the Mbstring extension", 837 | "homepage": "https://symfony.com", 838 | "keywords": [ 839 | "compatibility", 840 | "mbstring", 841 | "polyfill", 842 | "portable", 843 | "shim" 844 | ], 845 | "time": "2018-09-21T13:07:52+00:00" 846 | }, 847 | { 848 | "name": "symfony/property-access", 849 | "version": "v4.2.2", 850 | "source": { 851 | "type": "git", 852 | "url": "https://github.com/symfony/property-access.git", 853 | "reference": "a21d40670000f61a1a4b90a607d54696aad914cd" 854 | }, 855 | "dist": { 856 | "type": "zip", 857 | "url": "https://api.github.com/repos/symfony/property-access/zipball/a21d40670000f61a1a4b90a607d54696aad914cd", 858 | "reference": "a21d40670000f61a1a4b90a607d54696aad914cd", 859 | "shasum": "" 860 | }, 861 | "require": { 862 | "php": "^7.1.3", 863 | "symfony/inflector": "~3.4|~4.0" 864 | }, 865 | "require-dev": { 866 | "symfony/cache": "~3.4|~4.0" 867 | }, 868 | "suggest": { 869 | "psr/cache-implementation": "To cache access methods." 870 | }, 871 | "type": "library", 872 | "extra": { 873 | "branch-alias": { 874 | "dev-master": "4.2-dev" 875 | } 876 | }, 877 | "autoload": { 878 | "psr-4": { 879 | "Symfony\\Component\\PropertyAccess\\": "" 880 | }, 881 | "exclude-from-classmap": [ 882 | "/Tests/" 883 | ] 884 | }, 885 | "notification-url": "https://packagist.org/downloads/", 886 | "license": [ 887 | "MIT" 888 | ], 889 | "authors": [ 890 | { 891 | "name": "Fabien Potencier", 892 | "email": "fabien@symfony.com" 893 | }, 894 | { 895 | "name": "Symfony Community", 896 | "homepage": "https://symfony.com/contributors" 897 | } 898 | ], 899 | "description": "Symfony PropertyAccess Component", 900 | "homepage": "https://symfony.com", 901 | "keywords": [ 902 | "access", 903 | "array", 904 | "extraction", 905 | "index", 906 | "injection", 907 | "object", 908 | "property", 909 | "property path", 910 | "reflection" 911 | ], 912 | "time": "2019-01-05T16:37:49+00:00" 913 | }, 914 | { 915 | "name": "symfony/property-info", 916 | "version": "v4.2.2", 917 | "source": { 918 | "type": "git", 919 | "url": "https://github.com/symfony/property-info.git", 920 | "reference": "cfb42283015c194d14917f4dc108df7efc63fa4a" 921 | }, 922 | "dist": { 923 | "type": "zip", 924 | "url": "https://api.github.com/repos/symfony/property-info/zipball/cfb42283015c194d14917f4dc108df7efc63fa4a", 925 | "reference": "cfb42283015c194d14917f4dc108df7efc63fa4a", 926 | "shasum": "" 927 | }, 928 | "require": { 929 | "php": "^7.1.3", 930 | "symfony/inflector": "~3.4|~4.0" 931 | }, 932 | "conflict": { 933 | "phpdocumentor/reflection-docblock": "<3.0||>=3.2.0,<3.2.2", 934 | "phpdocumentor/type-resolver": "<0.3.0", 935 | "symfony/dependency-injection": "<3.4" 936 | }, 937 | "require-dev": { 938 | "doctrine/annotations": "~1.0", 939 | "phpdocumentor/reflection-docblock": "^3.0|^4.0", 940 | "symfony/cache": "~3.4|~4.0", 941 | "symfony/dependency-injection": "~3.4|~4.0", 942 | "symfony/serializer": "~3.4|~4.0" 943 | }, 944 | "suggest": { 945 | "phpdocumentor/reflection-docblock": "To use the PHPDoc", 946 | "psr/cache-implementation": "To cache results", 947 | "symfony/doctrine-bridge": "To use Doctrine metadata", 948 | "symfony/serializer": "To use Serializer metadata" 949 | }, 950 | "type": "library", 951 | "extra": { 952 | "branch-alias": { 953 | "dev-master": "4.2-dev" 954 | } 955 | }, 956 | "autoload": { 957 | "psr-4": { 958 | "Symfony\\Component\\PropertyInfo\\": "" 959 | }, 960 | "exclude-from-classmap": [ 961 | "/Tests/" 962 | ] 963 | }, 964 | "notification-url": "https://packagist.org/downloads/", 965 | "license": [ 966 | "MIT" 967 | ], 968 | "authors": [ 969 | { 970 | "name": "Kévin Dunglas", 971 | "email": "dunglas@gmail.com" 972 | }, 973 | { 974 | "name": "Symfony Community", 975 | "homepage": "https://symfony.com/contributors" 976 | } 977 | ], 978 | "description": "Symfony Property Info Component", 979 | "homepage": "https://symfony.com", 980 | "keywords": [ 981 | "doctrine", 982 | "phpdoc", 983 | "property", 984 | "symfony", 985 | "type", 986 | "validator" 987 | ], 988 | "time": "2019-01-03T09:07:35+00:00" 989 | }, 990 | { 991 | "name": "symfony/serializer", 992 | "version": "v4.2.2", 993 | "source": { 994 | "type": "git", 995 | "url": "https://github.com/symfony/serializer.git", 996 | "reference": "0e696a2a8ce2648a8b1074fc9aedd9fdd328ba77" 997 | }, 998 | "dist": { 999 | "type": "zip", 1000 | "url": "https://api.github.com/repos/symfony/serializer/zipball/0e696a2a8ce2648a8b1074fc9aedd9fdd328ba77", 1001 | "reference": "0e696a2a8ce2648a8b1074fc9aedd9fdd328ba77", 1002 | "shasum": "" 1003 | }, 1004 | "require": { 1005 | "php": "^7.1.3", 1006 | "symfony/polyfill-ctype": "~1.8" 1007 | }, 1008 | "conflict": { 1009 | "phpdocumentor/type-resolver": "<0.2.1", 1010 | "symfony/dependency-injection": "<3.4", 1011 | "symfony/property-access": "<3.4", 1012 | "symfony/property-info": "<3.4", 1013 | "symfony/yaml": "<3.4" 1014 | }, 1015 | "require-dev": { 1016 | "doctrine/annotations": "~1.0", 1017 | "doctrine/cache": "~1.0", 1018 | "phpdocumentor/reflection-docblock": "^3.0|^4.0", 1019 | "symfony/cache": "~3.4|~4.0", 1020 | "symfony/config": "~3.4|~4.0", 1021 | "symfony/dependency-injection": "~3.4|~4.0", 1022 | "symfony/http-foundation": "~3.4|~4.0", 1023 | "symfony/property-access": "~3.4|~4.0", 1024 | "symfony/property-info": "~3.4|~4.0", 1025 | "symfony/validator": "~3.4|~4.0", 1026 | "symfony/yaml": "~3.4|~4.0" 1027 | }, 1028 | "suggest": { 1029 | "doctrine/annotations": "For using the annotation mapping. You will also need doctrine/cache.", 1030 | "doctrine/cache": "For using the default cached annotation reader and metadata cache.", 1031 | "psr/cache-implementation": "For using the metadata cache.", 1032 | "symfony/config": "For using the XML mapping loader.", 1033 | "symfony/http-foundation": "To use the DataUriNormalizer.", 1034 | "symfony/property-access": "For using the ObjectNormalizer.", 1035 | "symfony/property-info": "To deserialize relations.", 1036 | "symfony/yaml": "For using the default YAML mapping loader." 1037 | }, 1038 | "type": "library", 1039 | "extra": { 1040 | "branch-alias": { 1041 | "dev-master": "4.2-dev" 1042 | } 1043 | }, 1044 | "autoload": { 1045 | "psr-4": { 1046 | "Symfony\\Component\\Serializer\\": "" 1047 | }, 1048 | "exclude-from-classmap": [ 1049 | "/Tests/" 1050 | ] 1051 | }, 1052 | "notification-url": "https://packagist.org/downloads/", 1053 | "license": [ 1054 | "MIT" 1055 | ], 1056 | "authors": [ 1057 | { 1058 | "name": "Fabien Potencier", 1059 | "email": "fabien@symfony.com" 1060 | }, 1061 | { 1062 | "name": "Symfony Community", 1063 | "homepage": "https://symfony.com/contributors" 1064 | } 1065 | ], 1066 | "description": "Symfony Serializer Component", 1067 | "homepage": "https://symfony.com", 1068 | "time": "2019-01-03T09:07:35+00:00" 1069 | }, 1070 | { 1071 | "name": "willdurand/negotiation", 1072 | "version": "v2.3.1", 1073 | "source": { 1074 | "type": "git", 1075 | "url": "https://github.com/willdurand/Negotiation.git", 1076 | "reference": "03436ededa67c6e83b9b12defac15384cb399dc9" 1077 | }, 1078 | "dist": { 1079 | "type": "zip", 1080 | "url": "https://api.github.com/repos/willdurand/Negotiation/zipball/03436ededa67c6e83b9b12defac15384cb399dc9", 1081 | "reference": "03436ededa67c6e83b9b12defac15384cb399dc9", 1082 | "shasum": "" 1083 | }, 1084 | "require": { 1085 | "php": ">=5.4.0" 1086 | }, 1087 | "require-dev": { 1088 | "phpunit/phpunit": "~4.5" 1089 | }, 1090 | "type": "library", 1091 | "extra": { 1092 | "branch-alias": { 1093 | "dev-master": "2.3-dev" 1094 | } 1095 | }, 1096 | "autoload": { 1097 | "psr-4": { 1098 | "Negotiation\\": "src/Negotiation" 1099 | } 1100 | }, 1101 | "notification-url": "https://packagist.org/downloads/", 1102 | "license": [ 1103 | "MIT" 1104 | ], 1105 | "authors": [ 1106 | { 1107 | "name": "William Durand", 1108 | "email": "will+git@drnd.me" 1109 | } 1110 | ], 1111 | "description": "Content Negotiation tools for PHP provided as a standalone library.", 1112 | "homepage": "http://williamdurand.fr/Negotiation/", 1113 | "keywords": [ 1114 | "accept", 1115 | "content", 1116 | "format", 1117 | "header", 1118 | "negotiation" 1119 | ], 1120 | "time": "2017-05-14T17:21:12+00:00" 1121 | } 1122 | ], 1123 | "packages-dev": [], 1124 | "aliases": [], 1125 | "minimum-stability": "stable", 1126 | "stability-flags": [], 1127 | "prefer-stable": false, 1128 | "prefer-lowest": false, 1129 | "platform": [], 1130 | "platform-dev": [] 1131 | } 1132 | --------------------------------------------------------------------------------