Skip to content

Instantly share code, notes, and snippets.

@ollo-ride-nico
Created October 11, 2018 13:50
Show Gist options
  • Save ollo-ride-nico/a62ebcd2f737600c081712e62a69239f to your computer and use it in GitHub Desktop.
Save ollo-ride-nico/a62ebcd2f737600c081712e62a69239f to your computer and use it in GitHub Desktop.
This gist exceeds the recommended number of files (~10). To access all files, please clone this gist.
# This file is a "template" of which env vars need to be defined for your application
# Copy this file to .env file for development, create environment variables when deploying to production
# https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration
###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET=a006eea95fd0d269b1e6f41041f37847
#TRUSTED_PROXIES=127.0.0.1,127.0.0.2
#TRUSTED_HOSTS=localhost,example.com
###< symfony/framework-bundle ###
# This file is a "template" of which env vars need to be defined for your application
# Copy this file to .env file for development, create environment variables when deploying to production
# https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration
###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET=a006eea95fd0d269b1e6f41041f37847
#TRUSTED_PROXIES=127.0.0.1,127.0.0.2
#TRUSTED_HOSTS=localhost,example.com
###< symfony/framework-bundle ###
###> symfony/framework-bundle ###
/.env
/public/bundles/
/var/
/vendor/
###< symfony/framework-bundle ###
#!/usr/bin/env php
<?php
use App\Kernel;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Debug\Debug;
use Symfony\Component\Dotenv\Dotenv;
set_time_limit(0);
require __DIR__.'/../vendor/autoload.php';
if (!class_exists(Application::class)) {
throw new \RuntimeException('You need to add "symfony/framework-bundle" as a Composer dependency.');
}
if (!isset($_SERVER['APP_ENV'])) {
if (!class_exists(Dotenv::class)) {
throw new \RuntimeException('APP_ENV environment variable is not defined. You need to define environment variables for configuration or add "symfony/dotenv" as a Composer dependency to load variables from a .env file.');
}
(new Dotenv())->load(__DIR__.'/../.env');
}
$input = new ArgvInput();
$env = $input->getParameterOption(['--env', '-e'], $_SERVER['APP_ENV'] ?? 'dev', true);
$debug = (bool) ($_SERVER['APP_DEBUG'] ?? ('prod' !== $env)) && !$input->hasParameterOption('--no-debug', true);
if ($debug) {
umask(0000);
if (class_exists(Debug::class)) {
Debug::enable();
}
}
$kernel = new Kernel($env, $debug);
$application = new Application($kernel);
$application->run($input);
{
"type": "project",
"license": "proprietary",
"require": {
"php": "^7.1.3",
"ext-ctype": "*",
"ext-iconv": "*",
"symfony/console": "*",
"symfony/flex": "^1.1",
"symfony/framework-bundle": "*",
"symfony/yaml": "*"
},
"require-dev": {
"symfony/dotenv": "*"
},
"config": {
"preferred-install": {
"*": "dist"
},
"sort-packages": true
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"App\\Tests\\": "tests/"
}
},
"replace": {
"paragonie/random_compat": "2.*",
"symfony/polyfill-ctype": "*",
"symfony/polyfill-iconv": "*",
"symfony/polyfill-php71": "*",
"symfony/polyfill-php70": "*",
"symfony/polyfill-php56": "*"
},
"scripts": {
"auto-scripts": {
"cache:clear": "symfony-cmd",
"assets:install %PUBLIC_DIR%": "symfony-cmd"
},
"post-install-cmd": [
"@auto-scripts"
],
"post-update-cmd": [
"@auto-scripts"
]
},
"conflict": {
"symfony/symfony": "*"
},
"extra": {
"symfony": {
"allow-contrib": false,
"require": "4.1.*"
}
}
}
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "626c5bd436f867ed8c4a4bd50351ae2e",
"packages": [
{
"name": "psr/cache",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/cache.git",
"reference": "d11b50ad223250cf17b86e38383413f5a6764bf8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8",
"reference": "d11b50ad223250cf17b86e38383413f5a6764bf8",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Cache\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for caching libraries",
"keywords": [
"cache",
"psr",
"psr-6"
],
"time": "2016-08-06T20:24:11+00:00"
},
{
"name": "psr/container",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/container.git",
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Container\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common Container Interface (PHP FIG PSR-11)",
"homepage": "https://github.com/php-fig/container",
"keywords": [
"PSR-11",
"container",
"container-interface",
"container-interop",
"psr"
],
"time": "2017-02-14T16:28:37+00:00"
},
{
"name": "psr/log",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
"reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Log\\": "Psr/Log/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"homepage": "https://github.com/php-fig/log",
"keywords": [
"log",
"psr",
"psr-3"
],
"time": "2016-10-10T12:19:37+00:00"
},
{
"name": "psr/simple-cache",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/simple-cache.git",
"reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
"reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\SimpleCache\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interfaces for simple caching",
"keywords": [
"cache",
"caching",
"psr",
"psr-16",
"simple-cache"
],
"time": "2017-10-23T01:57:42+00:00"
},
{
"name": "symfony/cache",
"version": "v4.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/cache.git",
"reference": "05ce0ddc8bc1ffe592105398fc2c725cb3080a38"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/cache/zipball/05ce0ddc8bc1ffe592105398fc2c725cb3080a38",
"reference": "05ce0ddc8bc1ffe592105398fc2c725cb3080a38",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"psr/cache": "~1.0",
"psr/log": "~1.0",
"psr/simple-cache": "^1.0"
},
"conflict": {
"symfony/var-dumper": "<3.4"
},
"provide": {
"psr/cache-implementation": "1.0",
"psr/simple-cache-implementation": "1.0"
},
"require-dev": {
"cache/integration-tests": "dev-master",
"doctrine/cache": "~1.6",
"doctrine/dbal": "~2.4",
"predis/predis": "~1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Cache\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Cache component with PSR-6, PSR-16, and tags",
"homepage": "https://symfony.com",
"keywords": [
"caching",
"psr6"
],
"time": "2018-09-30T03:38:13+00:00"
},
{
"name": "symfony/config",
"version": "v4.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/config.git",
"reference": "b3d4d7b567d7a49e6dfafb6d4760abc921177c96"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/config/zipball/b3d4d7b567d7a49e6dfafb6d4760abc921177c96",
"reference": "b3d4d7b567d7a49e6dfafb6d4760abc921177c96",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"symfony/filesystem": "~3.4|~4.0",
"symfony/polyfill-ctype": "~1.8"
},
"conflict": {
"symfony/finder": "<3.4"
},
"require-dev": {
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/event-dispatcher": "~3.4|~4.0",
"symfony/finder": "~3.4|~4.0",
"symfony/yaml": "~3.4|~4.0"
},
"suggest": {
"symfony/yaml": "To use the yaml reference dumper"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Config\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Config Component",
"homepage": "https://symfony.com",
"time": "2018-09-08T13:24:10+00:00"
},
{
"name": "symfony/console",
"version": "v4.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "dc7122fe5f6113cfaba3b3de575d31112c9aa60b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/dc7122fe5f6113cfaba3b3de575d31112c9aa60b",
"reference": "dc7122fe5f6113cfaba3b3de575d31112c9aa60b",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"symfony/polyfill-mbstring": "~1.0"
},
"conflict": {
"symfony/dependency-injection": "<3.4",
"symfony/process": "<3.3"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/config": "~3.4|~4.0",
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/event-dispatcher": "~3.4|~4.0",
"symfony/lock": "~3.4|~4.0",
"symfony/process": "~3.4|~4.0"
},
"suggest": {
"psr/log-implementation": "For using the console logger",
"symfony/event-dispatcher": "",
"symfony/lock": "",
"symfony/process": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Console\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"time": "2018-10-03T08:15:46+00:00"
},
{
"name": "symfony/debug",
"version": "v4.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
"reference": "e3f76ce6198f81994e019bb2b4e533e9de1b9b90"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/debug/zipball/e3f76ce6198f81994e019bb2b4e533e9de1b9b90",
"reference": "e3f76ce6198f81994e019bb2b4e533e9de1b9b90",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"psr/log": "~1.0"
},
"conflict": {
"symfony/http-kernel": "<3.4"
},
"require-dev": {
"symfony/http-kernel": "~3.4|~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Debug\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Debug Component",
"homepage": "https://symfony.com",
"time": "2018-10-02T16:36:10+00:00"
},
{
"name": "symfony/dependency-injection",
"version": "v4.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/dependency-injection.git",
"reference": "f6b9d893ad28aefd8942dc0469c8397e2216fe30"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/f6b9d893ad28aefd8942dc0469c8397e2216fe30",
"reference": "f6b9d893ad28aefd8942dc0469c8397e2216fe30",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"psr/container": "^1.0"
},
"conflict": {
"symfony/config": "<4.1.1",
"symfony/finder": "<3.4",
"symfony/proxy-manager-bridge": "<3.4",
"symfony/yaml": "<3.4"
},
"provide": {
"psr/container-implementation": "1.0"
},
"require-dev": {
"symfony/config": "~4.1",
"symfony/expression-language": "~3.4|~4.0",
"symfony/yaml": "~3.4|~4.0"
},
"suggest": {
"symfony/config": "",
"symfony/expression-language": "For using expressions in service container configuration",
"symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required",
"symfony/proxy-manager-bridge": "Generate service proxies to lazy load them",
"symfony/yaml": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\DependencyInjection\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony DependencyInjection Component",
"homepage": "https://symfony.com",
"time": "2018-10-02T12:40:59+00:00"
},
{
"name": "symfony/event-dispatcher",
"version": "v4.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
"reference": "bfb30c2ad377615a463ebbc875eba64a99f6aa3e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/bfb30c2ad377615a463ebbc875eba64a99f6aa3e",
"reference": "bfb30c2ad377615a463ebbc875eba64a99f6aa3e",
"shasum": ""
},
"require": {
"php": "^7.1.3"
},
"conflict": {
"symfony/dependency-injection": "<3.4"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/config": "~3.4|~4.0",
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/expression-language": "~3.4|~4.0",
"symfony/stopwatch": "~3.4|~4.0"
},
"suggest": {
"symfony/dependency-injection": "",
"symfony/http-kernel": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\EventDispatcher\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com",
"time": "2018-07-26T09:10:45+00:00"
},
{
"name": "symfony/filesystem",
"version": "v4.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "596d12b40624055c300c8b619755b748ca5cf0b5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/596d12b40624055c300c8b619755b748ca5cf0b5",
"reference": "596d12b40624055c300c8b619755b748ca5cf0b5",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"symfony/polyfill-ctype": "~1.8"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Filesystem\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Filesystem Component",
"homepage": "https://symfony.com",
"time": "2018-10-02T12:40:59+00:00"
},
{
"name": "symfony/finder",
"version": "v4.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "1f17195b44543017a9c9b2d437c670627e96ad06"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/1f17195b44543017a9c9b2d437c670627e96ad06",
"reference": "1f17195b44543017a9c9b2d437c670627e96ad06",
"shasum": ""
},
"require": {
"php": "^7.1.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Finder\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com",
"time": "2018-10-03T08:47:56+00:00"
},
{
"name": "symfony/flex",
"version": "v1.1.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/flex.git",
"reference": "9fb60f232af0764d58002e7872acb43a74506d25"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/flex/zipball/9fb60f232af0764d58002e7872acb43a74506d25",
"reference": "9fb60f232af0764d58002e7872acb43a74506d25",
"shasum": ""
},
"require": {
"composer-plugin-api": "^1.0",
"php": "^7.0"
},
"require-dev": {
"composer/composer": "^1.0.2",
"symfony/phpunit-bridge": "^3.2.8"
},
"type": "composer-plugin",
"extra": {
"branch-alias": {
"dev-master": "1.1-dev"
},
"class": "Symfony\\Flex\\Flex"
},
"autoload": {
"psr-4": {
"Symfony\\Flex\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
}
],
"description": "Composer plugin for Symfony",
"time": "2018-09-03T08:17:12+00:00"
},
{
"name": "symfony/framework-bundle",
"version": "v4.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/framework-bundle.git",
"reference": "3a0f2ec035c6ecc0f751fda1a76b02310bc9bbfe"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/framework-bundle/zipball/3a0f2ec035c6ecc0f751fda1a76b02310bc9bbfe",
"reference": "3a0f2ec035c6ecc0f751fda1a76b02310bc9bbfe",
"shasum": ""
},
"require": {
"ext-xml": "*",
"php": "^7.1.3",
"symfony/cache": "~3.4|~4.0",
"symfony/config": "~3.4|~4.0",
"symfony/dependency-injection": "^4.1.1",
"symfony/event-dispatcher": "^4.1",
"symfony/filesystem": "~3.4|~4.0",
"symfony/finder": "~3.4|~4.0",
"symfony/http-foundation": "^4.1",
"symfony/http-kernel": "^4.1",
"symfony/polyfill-mbstring": "~1.0",
"symfony/routing": "^4.1"
},
"conflict": {
"phpdocumentor/reflection-docblock": "<3.0",
"phpdocumentor/type-resolver": "<0.2.1",
"phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0",
"symfony/asset": "<3.4",
"symfony/console": "<3.4",
"symfony/form": "<4.1",
"symfony/messenger": ">=4.2",
"symfony/property-info": "<3.4",
"symfony/serializer": "<4.1",
"symfony/stopwatch": "<3.4",
"symfony/translation": "<3.4",
"symfony/twig-bridge": "<4.1.1",
"symfony/validator": "<4.1",
"symfony/workflow": "<4.1"
},
"require-dev": {
"doctrine/annotations": "~1.0",
"doctrine/cache": "~1.0",
"fig/link-util": "^1.0",
"phpdocumentor/reflection-docblock": "^3.0|^4.0",
"symfony/asset": "~3.4|~4.0",
"symfony/browser-kit": "~3.4|~4.0",
"symfony/console": "~3.4|~4.0",
"symfony/css-selector": "~3.4|~4.0",
"symfony/dom-crawler": "~3.4|~4.0",
"symfony/expression-language": "~3.4|~4.0",
"symfony/form": "^4.1",
"symfony/lock": "~3.4|~4.0",
"symfony/messenger": "^4.1",
"symfony/polyfill-intl-icu": "~1.0",
"symfony/process": "~3.4|~4.0",
"symfony/property-info": "~3.4|~4.0",
"symfony/security": "~3.4|~4.0",
"symfony/security-core": "~3.4|~4.0",
"symfony/security-csrf": "~3.4|~4.0",
"symfony/serializer": "^4.1",
"symfony/stopwatch": "~3.4|~4.0",
"symfony/templating": "~3.4|~4.0",
"symfony/translation": "~3.4|~4.0",
"symfony/validator": "^4.1",
"symfony/var-dumper": "~3.4|~4.0",
"symfony/web-link": "~3.4|~4.0",
"symfony/workflow": "^4.1",
"symfony/yaml": "~3.4|~4.0",
"twig/twig": "~1.34|~2.4"
},
"suggest": {
"ext-apcu": "For best performance of the system caches",
"symfony/console": "For using the console commands",
"symfony/form": "For using forms",
"symfony/property-info": "For using the property_info service",
"symfony/serializer": "For using the serializer service",
"symfony/validator": "For using validation",
"symfony/web-link": "For using web links, features such as preloading, prefetching or prerendering",
"symfony/yaml": "For using the debug:config and lint:yaml commands"
},
"type": "symfony-bundle",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Bundle\\FrameworkBundle\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony FrameworkBundle",
"homepage": "https://symfony.com",
"time": "2018-10-03T08:47:56+00:00"
},
{
"name": "symfony/http-foundation",
"version": "v4.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
"reference": "d528136617ff24f530e70df9605acc1b788b08d4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/d528136617ff24f530e70df9605acc1b788b08d4",
"reference": "d528136617ff24f530e70df9605acc1b788b08d4",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"symfony/polyfill-mbstring": "~1.1"
},
"require-dev": {
"predis/predis": "~1.0",
"symfony/expression-language": "~3.4|~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\HttpFoundation\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony HttpFoundation Component",
"homepage": "https://symfony.com",
"time": "2018-10-03T08:48:45+00:00"
},
{
"name": "symfony/http-kernel",
"version": "v4.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
"reference": "f5e7c15a5d010be0e16ce798594c5960451d4220"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/f5e7c15a5d010be0e16ce798594c5960451d4220",
"reference": "f5e7c15a5d010be0e16ce798594c5960451d4220",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"psr/log": "~1.0",
"symfony/debug": "~3.4|~4.0",
"symfony/event-dispatcher": "~4.1",
"symfony/http-foundation": "^4.1.1",
"symfony/polyfill-ctype": "~1.8"
},
"conflict": {
"symfony/config": "<3.4",
"symfony/dependency-injection": "<4.1",
"symfony/var-dumper": "<4.1.1",
"twig/twig": "<1.34|<2.4,>=2"
},
"provide": {
"psr/log-implementation": "1.0"
},
"require-dev": {
"psr/cache": "~1.0",
"symfony/browser-kit": "~3.4|~4.0",
"symfony/config": "~3.4|~4.0",
"symfony/console": "~3.4|~4.0",
"symfony/css-selector": "~3.4|~4.0",
"symfony/dependency-injection": "^4.1",
"symfony/dom-crawler": "~3.4|~4.0",
"symfony/expression-language": "~3.4|~4.0",
"symfony/finder": "~3.4|~4.0",
"symfony/process": "~3.4|~4.0",
"symfony/routing": "~3.4|~4.0",
"symfony/stopwatch": "~3.4|~4.0",
"symfony/templating": "~3.4|~4.0",
"symfony/translation": "~3.4|~4.0",
"symfony/var-dumper": "^4.1.1"
},
"suggest": {
"symfony/browser-kit": "",
"symfony/config": "",
"symfony/console": "",
"symfony/dependency-injection": "",
"symfony/var-dumper": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\HttpKernel\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony HttpKernel Component",
"homepage": "https://symfony.com",
"time": "2018-10-03T12:53:38+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.9.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d0cd638f4634c16d8df4508e847f14e9e43168b8",
"reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.9-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"time": "2018-08-06T14:22:27+00:00"
},
{
"name": "symfony/routing",
"version": "v4.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/routing.git",
"reference": "537803f0bdfede36b9acef052d2e4d447d9fa0e9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/routing/zipball/537803f0bdfede36b9acef052d2e4d447d9fa0e9",
"reference": "537803f0bdfede36b9acef052d2e4d447d9fa0e9",
"shasum": ""
},
"require": {
"php": "^7.1.3"
},
"conflict": {
"symfony/config": "<3.4",
"symfony/dependency-injection": "<3.4",
"symfony/yaml": "<3.4"
},
"require-dev": {
"doctrine/annotations": "~1.0",
"psr/log": "~1.0",
"symfony/config": "~3.4|~4.0",
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/expression-language": "~3.4|~4.0",
"symfony/http-foundation": "~3.4|~4.0",
"symfony/yaml": "~3.4|~4.0"
},
"suggest": {
"doctrine/annotations": "For using the annotation loader",
"symfony/config": "For using the all-in-one router or any loader",
"symfony/dependency-injection": "For loading routes from a service",
"symfony/expression-language": "For using expression matching",
"symfony/http-foundation": "For using a Symfony Request object",
"symfony/yaml": "For using the YAML loader"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Routing\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Routing Component",
"homepage": "https://symfony.com",
"keywords": [
"router",
"routing",
"uri",
"url"
],
"time": "2018-10-02T12:40:59+00:00"
},
{
"name": "symfony/yaml",
"version": "v4.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "367e689b2fdc19965be435337b50bc8adf2746c9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/367e689b2fdc19965be435337b50bc8adf2746c9",
"reference": "367e689b2fdc19965be435337b50bc8adf2746c9",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"symfony/polyfill-ctype": "~1.8"
},
"conflict": {
"symfony/console": "<3.4"
},
"require-dev": {
"symfony/console": "~3.4|~4.0"
},
"suggest": {
"symfony/console": "For validating YAML files using the lint command"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Yaml\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
"time": "2018-10-02T16:36:10+00:00"
}
],
"packages-dev": [
{
"name": "symfony/dotenv",
"version": "v4.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/dotenv.git",
"reference": "22ca63c46e252b8a8f37b8f9e6da66bff5b3d3e7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/dotenv/zipball/22ca63c46e252b8a8f37b8f9e6da66bff5b3d3e7",
"reference": "22ca63c46e252b8a8f37b8f9e6da66bff5b3d3e7",
"shasum": ""
},
"require": {
"php": "^7.1.3"
},
"require-dev": {
"symfony/process": "~3.4|~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Dotenv\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Registers environment variables from a .env file",
"homepage": "https://symfony.com",
"keywords": [
"dotenv",
"env",
"environment"
],
"time": "2018-07-26T11:24:31+00:00"
}
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": "^7.1.3",
"ext-ctype": "*",
"ext-iconv": "*"
},
"platform-dev": []
}
<?php
return [
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
];
framework:
router:
strict_requirements: true
framework:
secret: '%env(APP_SECRET)%'
#default_locale: en
#csrf_protection: true
#http_method_override: true
# Enables session support. Note that the session will ONLY be started if you read or write from it.
# Remove or comment this section to explicitly disable session support.
session:
handler_id: ~
#esi: true
#fragments: true
php_errors:
log: true
cache:
# Put the unique name of your app here: the prefix seed
# is used to compute stable namespaces for cache keys.
#prefix_seed: your_vendor_name/app_name
# The app cache caches to the filesystem by default.
# Other options include:
# Redis
#app: cache.adapter.redis
#default_redis_provider: redis://localhost
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
#app: cache.adapter.apcu
framework:
router:
strict_requirements: ~
framework:
test: true
session:
storage_id: session.storage.mock_file
framework:
router:
strict_requirements: true
#index:
# path: /
# controller: App\Controller\DefaultController::index
# This file is the entry point to configure your own services.
# Files in the packages/ subdirectory configure your dependencies.
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
public: false # Allows optimizing the container by removing unused services; this also means
# fetching services directly from the container via $container->get() won't work.
# The best practice is to be explicit about your dependencies anyway.
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/*'
exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
# controllers are imported separately to make sure services can be injected
# as action arguments even if you don't extend any base controller class
App\Controller\:
resource: '../src/Controller'
tags: ['controller.service_arguments']
# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones
<?php
use App\Kernel;
use Symfony\Component\Debug\Debug;
use Symfony\Component\Dotenv\Dotenv;
use Symfony\Component\HttpFoundation\Request;
require __DIR__.'/../vendor/autoload.php';
// The check is to ensure we don't use .env in production
if (!isset($_SERVER['APP_ENV']) && !isset($_ENV['APP_ENV'])) {
if (!class_exists(Dotenv::class)) {
throw new \RuntimeException('APP_ENV environment variable is not defined. You need to define environment variables for configuration or add "symfony/dotenv" as a Composer dependency to load variables from a .env file.');
}
(new Dotenv())->load(__DIR__.'/../.env');
}
$env = $_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? 'dev';
$debug = (bool) ($_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? ('prod' !== $env));
if ($debug) {
umask(0000);
Debug::enable();
}
if ($trustedProxies = $_SERVER['TRUSTED_PROXIES'] ?? $_ENV['TRUSTED_PROXIES'] ?? false) {
Request::setTrustedProxies(explode(',', $trustedProxies), Request::HEADER_X_FORWARDED_ALL ^ Request::HEADER_X_FORWARDED_HOST);
}
if ($trustedHosts = $_SERVER['TRUSTED_HOSTS'] ?? $_ENV['TRUSTED_HOSTS'] ?? false) {
Request::setTrustedHosts(explode(',', $trustedHosts));
}
$kernel = new Kernel($env, $debug);
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
<?php
namespace App;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
use Symfony\Component\Routing\RouteCollectionBuilder;
class Kernel extends BaseKernel
{
use MicroKernelTrait;
const CONFIG_EXTS = '.{php,xml,yaml,yml}';
public function getCacheDir()
{
return $this->getProjectDir().'/var/cache/'.$this->environment;
}
public function getLogDir()
{
return $this->getProjectDir().'/var/log';
}
public function registerBundles()
{
$contents = require $this->getProjectDir().'/config/bundles.php';
foreach ($contents as $class => $envs) {
if (isset($envs['all']) || isset($envs[$this->environment])) {
yield new $class();
}
}
}
protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader)
{
$container->addResource(new FileResource($this->getProjectDir().'/config/bundles.php'));
// Feel free to remove the "container.autowiring.strict_mode" parameter
// if you are using symfony/dependency-injection 4.0+ as it's the default behavior
$container->setParameter('container.autowiring.strict_mode', true);
$container->setParameter('container.dumper.inline_class_loader', true);
$confDir = $this->getProjectDir().'/config';
$loader->load($confDir.'/{packages}/*'.self::CONFIG_EXTS, 'glob');
$loader->load($confDir.'/{packages}/'.$this->environment.'/**/*'.self::CONFIG_EXTS, 'glob');
$loader->load($confDir.'/{services}'.self::CONFIG_EXTS, 'glob');
$loader->load($confDir.'/{services}_'.$this->environment.self::CONFIG_EXTS, 'glob');
}
protected function configureRoutes(RouteCollectionBuilder $routes)
{
$confDir = $this->getProjectDir().'/config';
$routes->import($confDir.'/{routes}/*'.self::CONFIG_EXTS, '/', 'glob');
$routes->import($confDir.'/{routes}/'.$this->environment.'/**/*'.self::CONFIG_EXTS, '/', 'glob');
$routes->import($confDir.'/{routes}'.self::CONFIG_EXTS, '/', 'glob');
}
}
{
"psr/cache": {
"version": "1.0.1"
},
"psr/container": {
"version": "1.0.0"
},
"psr/log": {
"version": "1.0.2"
},
"psr/simple-cache": {
"version": "1.0.1"
},
"symfony/cache": {
"version": "v4.1.6"
},
"symfony/config": {
"version": "v4.1.6"
},
"symfony/console": {
"version": "3.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "master",
"version": "3.3",
"ref": "e3868d2f4a5104f19f844fe551099a00c6562527"
}
},
"symfony/debug": {
"version": "v4.1.6"
},
"symfony/dependency-injection": {
"version": "v4.1.6"
},
"symfony/dotenv": {
"version": "v4.1.6"
},
"symfony/event-dispatcher": {
"version": "v4.1.6"
},
"symfony/filesystem": {
"version": "v4.1.6"
},
"symfony/finder": {
"version": "v4.1.6"
},
"symfony/flex": {
"version": "1.0",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "master",
"version": "1.0",
"ref": "e921bdbfe20cdefa3b82f379d1cd36df1bc8d115"
}
},
"symfony/framework-bundle": {
"version": "3.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "master",
"version": "3.3",
"ref": "1717e67afa995e4f01a25ba9ae7aca5b2327bcaa"
}
},
"symfony/http-foundation": {
"version": "v4.1.6"
},
"symfony/http-kernel": {
"version": "v4.1.6"
},
"symfony/polyfill-mbstring": {
"version": "v1.9.0"
},
"symfony/routing": {
"version": "4.0",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "master",
"version": "4.0",
"ref": "5f514d9d3b8a8aac3d62ae6a86b18b90ed0c7826"
}
},
"symfony/yaml": {
"version": "v4.1.6"
}
}
<?php return array (
0 => 'Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController',
1 => 'Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller',
);
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'argument_resolver.default' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/Controller/ArgumentValueResolverInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/Controller/ArgumentResolver/DefaultValueResolver.php';
return $this->privates['argument_resolver.default'] = new \Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver();
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'argument_resolver.request_attribute' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/Controller/ArgumentValueResolverInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestAttributeValueResolver.php';
return $this->privates['argument_resolver.request_attribute'] = new \Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestAttributeValueResolver();
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'argument_resolver.request' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/Controller/ArgumentValueResolverInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestValueResolver.php';
return $this->privates['argument_resolver.request'] = new \Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestValueResolver();
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'argument_resolver.service' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/Controller/ArgumentValueResolverInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/Controller/ArgumentResolver/ServiceValueResolver.php';
return $this->privates['argument_resolver.service'] = new \Symfony\Component\HttpKernel\Controller\ArgumentResolver\ServiceValueResolver(new \Symfony\Component\DependencyInjection\ServiceLocator(array()));
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'argument_resolver.session' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/Controller/ArgumentValueResolverInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/Controller/ArgumentResolver/SessionValueResolver.php';
return $this->privates['argument_resolver.session'] = new \Symfony\Component\HttpKernel\Controller\ArgumentResolver\SessionValueResolver();
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'argument_resolver.variadic' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/Controller/ArgumentValueResolverInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/Controller/ArgumentResolver/VariadicValueResolver.php';
return $this->privates['argument_resolver.variadic'] = new \Symfony\Component\HttpKernel\Controller\ArgumentResolver\VariadicValueResolver();
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the public 'cache.app_clearer' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/CacheClearer/CacheClearerInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/CacheClearer/Psr6CacheClearer.php';
return $this->services['cache.app_clearer'] = new \Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer(array('cache.app' => ($this->services['cache.app'] ?? $this->load('getCache_AppService.php'))));
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the public 'cache.app' shared service.
include_once $this->targetDirs[3].'/vendor/psr/cache/src/CacheItemPoolInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/cache/Adapter/AdapterInterface.php';
include_once $this->targetDirs[3].'/vendor/psr/log/Psr/Log/LoggerAwareInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/cache/ResettableInterface.php';
include_once $this->targetDirs[3].'/vendor/psr/log/Psr/Log/LoggerAwareTrait.php';
include_once $this->targetDirs[3].'/vendor/symfony/cache/Traits/AbstractTrait.php';
include_once $this->targetDirs[3].'/vendor/symfony/cache/Adapter/AbstractAdapter.php';
include_once $this->targetDirs[3].'/vendor/symfony/cache/PruneableInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/cache/Traits/FilesystemCommonTrait.php';
include_once $this->targetDirs[3].'/vendor/symfony/cache/Traits/FilesystemTrait.php';
include_once $this->targetDirs[3].'/vendor/symfony/cache/Adapter/FilesystemAdapter.php';
$this->services['cache.app'] = $instance = new \Symfony\Component\Cache\Adapter\FilesystemAdapter('l2WGSBZAlu', 0, ($this->targetDirs[0].'/pools'));
$instance->setLogger(($this->privates['logger'] ?? $this->privates['logger'] = new \Symfony\Component\HttpKernel\Log\Logger()));
return $instance;
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the public 'cache.global_clearer' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/CacheClearer/CacheClearerInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/CacheClearer/Psr6CacheClearer.php';
return $this->services['cache.global_clearer'] = new \Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer(array('cache.app' => ($this->services['cache.app'] ?? $this->load('getCache_AppService.php')), 'cache.system' => ($this->services['cache.system'] ?? $this->load('getCache_SystemService.php'))));
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the public 'cache.system_clearer' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/CacheClearer/CacheClearerInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/CacheClearer/Psr6CacheClearer.php';
return $this->services['cache.system_clearer'] = new \Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer(array('cache.system' => ($this->services['cache.system'] ?? $this->load('getCache_SystemService.php'))));
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the public 'cache.system' shared service.
include_once $this->targetDirs[3].'/vendor/psr/cache/src/CacheItemPoolInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/cache/Adapter/AdapterInterface.php';
include_once $this->targetDirs[3].'/vendor/psr/log/Psr/Log/LoggerAwareInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/cache/ResettableInterface.php';
include_once $this->targetDirs[3].'/vendor/psr/log/Psr/Log/LoggerAwareTrait.php';
include_once $this->targetDirs[3].'/vendor/symfony/cache/Traits/AbstractTrait.php';
include_once $this->targetDirs[3].'/vendor/symfony/cache/Adapter/AbstractAdapter.php';
return $this->services['cache.system'] = \Symfony\Component\Cache\Adapter\AbstractAdapter::createSystemCache('UGP9+Vscxx', 0, $this->getParameter('container.build_id'), ($this->targetDirs[0].'/pools'), ($this->privates['logger'] ?? $this->privates['logger'] = new \Symfony\Component\HttpKernel\Log\Logger()));
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the public 'cache_clearer' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/CacheClearer/CacheClearerInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/CacheClearer/ChainCacheClearer.php';
return $this->services['cache_clearer'] = new \Symfony\Component\HttpKernel\CacheClearer\ChainCacheClearer(new RewindableGenerator(function () {
yield 0 => ($this->services['cache.system_clearer'] ?? $this->load('getCache_SystemClearerService.php'));
}, 1));
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the public 'cache_warmer' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerAggregate.php';
return $this->services['cache_warmer'] = new \Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerAggregate(new RewindableGenerator(function () {
yield 0 => ($this->privates['router.cache_warmer'] ?? $this->load('getRouter_CacheWarmerService.php'));
}, 1));
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'config.resource.self_checking_resource_checker' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/config/ResourceCheckerInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/config/Resource/SelfCheckingResourceChecker.php';
return $this->privates['config.resource.self_checking_resource_checker'] = new \Symfony\Component\Config\Resource\SelfCheckingResourceChecker();
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'console.command.about' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/console/Command/Command.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Command/AboutCommand.php';
$this->privates['console.command.about'] = $instance = new \Symfony\Bundle\FrameworkBundle\Command\AboutCommand();
$instance->setName('about');
return $instance;
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'console.command.assets_install' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/console/Command/Command.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Command/AssetsInstallCommand.php';
include_once $this->targetDirs[3].'/vendor/symfony/filesystem/Filesystem.php';
$this->privates['console.command.assets_install'] = $instance = new \Symfony\Bundle\FrameworkBundle\Command\AssetsInstallCommand(($this->services['filesystem'] ?? $this->services['filesystem'] = new \Symfony\Component\Filesystem\Filesystem()));
$instance->setName('assets:install');
return $instance;
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'console.command.cache_clear' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/console/Command/Command.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Command/CacheClearCommand.php';
include_once $this->targetDirs[3].'/vendor/symfony/filesystem/Filesystem.php';
$this->privates['console.command.cache_clear'] = $instance = new \Symfony\Bundle\FrameworkBundle\Command\CacheClearCommand(($this->services['cache_clearer'] ?? $this->load('getCacheClearerService.php')), ($this->services['filesystem'] ?? $this->services['filesystem'] = new \Symfony\Component\Filesystem\Filesystem()));
$instance->setName('cache:clear');
return $instance;
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'console.command.cache_pool_clear' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/console/Command/Command.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Command/CachePoolClearCommand.php';
$this->privates['console.command.cache_pool_clear'] = $instance = new \Symfony\Bundle\FrameworkBundle\Command\CachePoolClearCommand(($this->services['cache.global_clearer'] ?? $this->load('getCache_GlobalClearerService.php')));
$instance->setName('cache:pool:clear');
return $instance;
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'console.command.cache_pool_delete' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/console/Command/Command.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Command/CachePoolDeleteCommand.php';
$this->privates['console.command.cache_pool_delete'] = $instance = new \Symfony\Bundle\FrameworkBundle\Command\CachePoolDeleteCommand(($this->services['cache.global_clearer'] ?? $this->load('getCache_GlobalClearerService.php')));
$instance->setName('cache:pool:delete');
return $instance;
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'console.command.cache_pool_prune' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/console/Command/Command.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Command/CachePoolPruneCommand.php';
$this->privates['console.command.cache_pool_prune'] = $instance = new \Symfony\Bundle\FrameworkBundle\Command\CachePoolPruneCommand(new RewindableGenerator(function () {
yield 'cache.app' => ($this->services['cache.app'] ?? $this->load('getCache_AppService.php'));
}, 1));
$instance->setName('cache:pool:prune');
return $instance;
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'console.command.cache_warmup' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/console/Command/Command.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Command/CacheWarmupCommand.php';
$this->privates['console.command.cache_warmup'] = $instance = new \Symfony\Bundle\FrameworkBundle\Command\CacheWarmupCommand(($this->services['cache_warmer'] ?? $this->load('getCacheWarmerService.php')));
$instance->setName('cache:warmup');
return $instance;
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'console.command.config_debug' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/console/Command/Command.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Command/ContainerDebugCommand.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Command/AbstractConfigCommand.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Command/ConfigDebugCommand.php';
$this->privates['console.command.config_debug'] = $instance = new \Symfony\Bundle\FrameworkBundle\Command\ConfigDebugCommand();
$instance->setName('debug:config');
return $instance;
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'console.command.config_dump_reference' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/console/Command/Command.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Command/ContainerDebugCommand.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Command/AbstractConfigCommand.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Command/ConfigDumpReferenceCommand.php';
$this->privates['console.command.config_dump_reference'] = $instance = new \Symfony\Bundle\FrameworkBundle\Command\ConfigDumpReferenceCommand();
$instance->setName('config:dump-reference');
return $instance;
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'console.command.container_debug' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/console/Command/Command.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Command/ContainerDebugCommand.php';
$this->privates['console.command.container_debug'] = $instance = new \Symfony\Bundle\FrameworkBundle\Command\ContainerDebugCommand();
$instance->setName('debug:container');
return $instance;
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'console.command.debug_autowiring' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/console/Command/Command.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Command/ContainerDebugCommand.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Command/DebugAutowiringCommand.php';
$this->privates['console.command.debug_autowiring'] = $instance = new \Symfony\Bundle\FrameworkBundle\Command\DebugAutowiringCommand();
$instance->setName('debug:autowiring');
return $instance;
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'console.command.event_dispatcher_debug' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/console/Command/Command.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Command/EventDispatcherDebugCommand.php';
$this->privates['console.command.event_dispatcher_debug'] = $instance = new \Symfony\Bundle\FrameworkBundle\Command\EventDispatcherDebugCommand(($this->services['event_dispatcher'] ?? $this->getEventDispatcherService()));
$instance->setName('debug:event-dispatcher');
return $instance;
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'console.command.router_debug' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/console/Command/Command.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Command/RouterDebugCommand.php';
$this->privates['console.command.router_debug'] = $instance = new \Symfony\Bundle\FrameworkBundle\Command\RouterDebugCommand(($this->services['router'] ?? $this->getRouterService()));
$instance->setName('debug:router');
return $instance;
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'console.command.router_match' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/console/Command/Command.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Command/RouterMatchCommand.php';
$this->privates['console.command.router_match'] = $instance = new \Symfony\Bundle\FrameworkBundle\Command\RouterMatchCommand(($this->services['router'] ?? $this->getRouterService()));
$instance->setName('router:match');
return $instance;
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'console.command.yaml_lint' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/console/Command/Command.php';
include_once $this->targetDirs[3].'/vendor/symfony/yaml/Command/LintCommand.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Command/YamlLintCommand.php';
$this->privates['console.command.yaml_lint'] = $instance = new \Symfony\Bundle\FrameworkBundle\Command\YamlLintCommand();
$instance->setName('lint:yaml');
return $instance;
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the public 'console.command_loader' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/console/CommandLoader/CommandLoaderInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php';
return $this->services['console.command_loader'] = new \Symfony\Component\Console\CommandLoader\ContainerCommandLoader(new \Symfony\Component\DependencyInjection\ServiceLocator(array('console.command.about' => function (): \Symfony\Bundle\FrameworkBundle\Command\AboutCommand {
return ($this->privates['console.command.about'] ?? $this->load('getConsole_Command_AboutService.php'));
}, 'console.command.assets_install' => function (): \Symfony\Bundle\FrameworkBundle\Command\AssetsInstallCommand {
return ($this->privates['console.command.assets_install'] ?? $this->load('getConsole_Command_AssetsInstallService.php'));
}, 'console.command.cache_clear' => function (): \Symfony\Bundle\FrameworkBundle\Command\CacheClearCommand {
return ($this->privates['console.command.cache_clear'] ?? $this->load('getConsole_Command_CacheClearService.php'));
}, 'console.command.cache_pool_clear' => function (): \Symfony\Bundle\FrameworkBundle\Command\CachePoolClearCommand {
return ($this->privates['console.command.cache_pool_clear'] ?? $this->load('getConsole_Command_CachePoolClearService.php'));
}, 'console.command.cache_pool_delete' => function (): \Symfony\Bundle\FrameworkBundle\Command\CachePoolDeleteCommand {
return ($this->privates['console.command.cache_pool_delete'] ?? $this->load('getConsole_Command_CachePoolDeleteService.php'));
}, 'console.command.cache_pool_prune' => function (): \Symfony\Bundle\FrameworkBundle\Command\CachePoolPruneCommand {
return ($this->privates['console.command.cache_pool_prune'] ?? $this->load('getConsole_Command_CachePoolPruneService.php'));
}, 'console.command.cache_warmup' => function (): \Symfony\Bundle\FrameworkBundle\Command\CacheWarmupCommand {
return ($this->privates['console.command.cache_warmup'] ?? $this->load('getConsole_Command_CacheWarmupService.php'));
}, 'console.command.config_debug' => function (): \Symfony\Bundle\FrameworkBundle\Command\ConfigDebugCommand {
return ($this->privates['console.command.config_debug'] ?? $this->load('getConsole_Command_ConfigDebugService.php'));
}, 'console.command.config_dump_reference' => function (): \Symfony\Bundle\FrameworkBundle\Command\ConfigDumpReferenceCommand {
return ($this->privates['console.command.config_dump_reference'] ?? $this->load('getConsole_Command_ConfigDumpReferenceService.php'));
}, 'console.command.container_debug' => function (): \Symfony\Bundle\FrameworkBundle\Command\ContainerDebugCommand {
return ($this->privates['console.command.container_debug'] ?? $this->load('getConsole_Command_ContainerDebugService.php'));
}, 'console.command.debug_autowiring' => function (): \Symfony\Bundle\FrameworkBundle\Command\DebugAutowiringCommand {
return ($this->privates['console.command.debug_autowiring'] ?? $this->load('getConsole_Command_DebugAutowiringService.php'));
}, 'console.command.event_dispatcher_debug' => function (): \Symfony\Bundle\FrameworkBundle\Command\EventDispatcherDebugCommand {
return ($this->privates['console.command.event_dispatcher_debug'] ?? $this->load('getConsole_Command_EventDispatcherDebugService.php'));
}, 'console.command.router_debug' => function (): \Symfony\Bundle\FrameworkBundle\Command\RouterDebugCommand {
return ($this->privates['console.command.router_debug'] ?? $this->load('getConsole_Command_RouterDebugService.php'));
}, 'console.command.router_match' => function (): \Symfony\Bundle\FrameworkBundle\Command\RouterMatchCommand {
return ($this->privates['console.command.router_match'] ?? $this->load('getConsole_Command_RouterMatchService.php'));
}, 'console.command.yaml_lint' => function (): \Symfony\Bundle\FrameworkBundle\Command\YamlLintCommand {
return ($this->privates['console.command.yaml_lint'] ?? $this->load('getConsole_Command_YamlLintService.php'));
})), array('about' => 'console.command.about', 'assets:install' => 'console.command.assets_install', 'cache:clear' => 'console.command.cache_clear', 'cache:pool:clear' => 'console.command.cache_pool_clear', 'cache:pool:prune' => 'console.command.cache_pool_prune', 'cache:pool:delete' => 'console.command.cache_pool_delete', 'cache:warmup' => 'console.command.cache_warmup', 'debug:config' => 'console.command.config_debug', 'config:dump-reference' => 'console.command.config_dump_reference', 'debug:container' => 'console.command.container_debug', 'debug:autowiring' => 'console.command.debug_autowiring', 'debug:event-dispatcher' => 'console.command.event_dispatcher_debug', 'debug:router' => 'console.command.router_debug', 'router:match' => 'console.command.router_match', 'lint:yaml' => 'console.command.yaml_lint'));
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'console.error_listener' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/console/EventListener/ErrorListener.php';
return $this->privates['console.error_listener'] = new \Symfony\Component\Console\EventListener\ErrorListener(($this->privates['logger'] ?? $this->privates['logger'] = new \Symfony\Component\HttpKernel\Log\Logger()));
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'dependency_injection.config.container_parameters_resource_checker' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/config/ResourceCheckerInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/dependency-injection/Config/ContainerParametersResourceChecker.php';
return $this->privates['dependency_injection.config.container_parameters_resource_checker'] = new \Symfony\Component\DependencyInjection\Config\ContainerParametersResourceChecker($this);
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the public 'filesystem' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/filesystem/Filesystem.php';
return $this->services['filesystem'] = new \Symfony\Component\Filesystem\Filesystem();
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the public 'Symfony\Bundle\FrameworkBundle\Controller\RedirectController' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Controller/RedirectController.php';
return $this->services['Symfony\Bundle\FrameworkBundle\Controller\RedirectController'] = new \Symfony\Bundle\FrameworkBundle\Controller\RedirectController(($this->services['router'] ?? $this->getRouterService()), 80, 443);
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'router.cache_warmer' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/CacheWarmer/RouterCacheWarmer.php';
return $this->privates['router.cache_warmer'] = new \Symfony\Bundle\FrameworkBundle\CacheWarmer\RouterCacheWarmer((new \Symfony\Component\DependencyInjection\ServiceLocator(array('router' => function () {
return ($this->services['router'] ?? $this->getRouterService());
})))->withContext('router.cache_warmer', $this));
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the public 'routing.loader' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/config/Loader/LoaderInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/config/Loader/Loader.php';
include_once $this->targetDirs[3].'/vendor/symfony/config/Loader/DelegatingLoader.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Routing/DelegatingLoader.php';
include_once $this->targetDirs[3].'/vendor/symfony/config/Loader/LoaderResolverInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/config/Loader/LoaderResolver.php';
include_once $this->targetDirs[3].'/vendor/symfony/config/Loader/FileLoader.php';
include_once $this->targetDirs[3].'/vendor/symfony/routing/Loader/XmlFileLoader.php';
include_once $this->targetDirs[3].'/vendor/symfony/config/FileLocatorInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/config/FileLocator.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/Config/FileLocator.php';
include_once $this->targetDirs[3].'/vendor/symfony/routing/Loader/YamlFileLoader.php';
include_once $this->targetDirs[3].'/vendor/symfony/routing/Loader/PhpFileLoader.php';
include_once $this->targetDirs[3].'/vendor/symfony/routing/Loader/GlobFileLoader.php';
include_once $this->targetDirs[3].'/vendor/symfony/routing/Loader/DirectoryLoader.php';
include_once $this->targetDirs[3].'/vendor/symfony/routing/Loader/ObjectRouteLoader.php';
include_once $this->targetDirs[3].'/vendor/symfony/routing/Loader/DependencyInjection/ServiceRouterLoader.php';
$a = new \Symfony\Component\Config\Loader\LoaderResolver();
$b = new \Symfony\Component\HttpKernel\Config\FileLocator(($this->services['kernel'] ?? $this->get('kernel', 1)), ($this->targetDirs[3].'/src/Resources'), array(0 => ($this->targetDirs[3].'/src')));
$a->addLoader(new \Symfony\Component\Routing\Loader\XmlFileLoader($b));
$a->addLoader(new \Symfony\Component\Routing\Loader\YamlFileLoader($b));
$a->addLoader(new \Symfony\Component\Routing\Loader\PhpFileLoader($b));
$a->addLoader(new \Symfony\Component\Routing\Loader\GlobFileLoader($b));
$a->addLoader(new \Symfony\Component\Routing\Loader\DirectoryLoader($b));
$a->addLoader(new \Symfony\Component\Routing\Loader\DependencyInjection\ServiceRouterLoader($this));
return $this->services['routing.loader'] = new \Symfony\Bundle\FrameworkBundle\Routing\DelegatingLoader(($this->privates['controller_name_converter'] ?? $this->privates['controller_name_converter'] = new \Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser(($this->services['kernel'] ?? $this->get('kernel', 1)))), $a);
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the public 'session' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/http-foundation/Session/SessionInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-foundation/Session/Session.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-foundation/Session/Storage/SessionStorageInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-foundation/Session/SessionBagInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-foundation/Session/Storage/MetadataBag.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-foundation/Session/Attribute/AttributeBagInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-foundation/Session/Attribute/AttributeBag.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-foundation/Session/Flash/FlashBagInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-foundation/Session/Flash/FlashBag.php';
return $this->services['session'] = new \Symfony\Component\HttpFoundation\Session\Session(new \Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage($this->parameters['session.storage.options'], NULL, new \Symfony\Component\HttpFoundation\Session\Storage\MetadataBag('_sf2_meta', '0')), new \Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag(), new \Symfony\Component\HttpFoundation\Session\Flash\FlashBag());
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the public 'Symfony\Bundle\FrameworkBundle\Controller\TemplateController' shared service.
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Controller/TemplateController.php';
return $this->services['Symfony\Bundle\FrameworkBundle\Controller\TemplateController'] = new \Symfony\Bundle\FrameworkBundle\Controller\TemplateController(NULL, NULL);
<?php
return array(
'.1_NativeFileSessionHandler~ekBW_9l' => true,
'.2_ServiceLocator~ekBW_9l' => true,
'.cache_connection.GD_MSZC' => true,
'.cache_connection.JKE6keX' => true,
'.service_locator.9_yeNH1' => true,
'.service_locator.AoifO_3' => true,
'.service_locator.K2fdwAZ' => true,
'.service_locator.gmwRZ3h' => true,
'.service_locator.oNnsU_h' => true,
'.service_locator.oNnsU_h.router.default' => true,
'.service_locator.tdKlFgs' => true,
'.service_locator.tdKlFgs.router.cache_warmer' => true,
'Psr\\Cache\\CacheItemPoolInterface' => true,
'Psr\\Container\\ContainerInterface' => true,
'Psr\\Log\\LoggerInterface' => true,
'Psr\\SimpleCache\\CacheInterface' => true,
'SessionHandlerInterface' => true,
'Symfony\\Component\\Cache\\Adapter\\AdapterInterface' => true,
'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true,
'Symfony\\Component\\DependencyInjection\\ParameterBag\\ContainerBagInterface' => true,
'Symfony\\Component\\DependencyInjection\\ParameterBag\\ParameterBagInterface' => true,
'Symfony\\Component\\EventDispatcher\\EventDispatcherInterface' => true,
'Symfony\\Component\\Filesystem\\Filesystem' => true,
'Symfony\\Component\\HttpFoundation\\RequestStack' => true,
'Symfony\\Component\\HttpFoundation\\Session\\Flash\\FlashBagInterface' => true,
'Symfony\\Component\\HttpFoundation\\Session\\SessionInterface' => true,
'Symfony\\Component\\HttpFoundation\\Session\\Storage\\SessionStorageInterface' => true,
'Symfony\\Component\\HttpKernel\\Config\\FileLocator' => true,
'Symfony\\Component\\HttpKernel\\Debug\\FileLinkFormatter' => true,
'Symfony\\Component\\HttpKernel\\HttpKernelInterface' => true,
'Symfony\\Component\\HttpKernel\\KernelInterface' => true,
'Symfony\\Component\\Routing\\Generator\\UrlGeneratorInterface' => true,
'Symfony\\Component\\Routing\\Matcher\\UrlMatcherInterface' => true,
'Symfony\\Component\\Routing\\RequestContext' => true,
'Symfony\\Component\\Routing\\RequestContextAwareInterface' => true,
'Symfony\\Component\\Routing\\RouterInterface' => true,
'argument_metadata_factory' => true,
'argument_resolver' => true,
'argument_resolver.controller_locator' => true,
'argument_resolver.default' => true,
'argument_resolver.request' => true,
'argument_resolver.request_attribute' => true,
'argument_resolver.service' => true,
'argument_resolver.session' => true,
'argument_resolver.variadic' => true,
'cache.adapter.apcu' => true,
'cache.adapter.array' => true,
'cache.adapter.doctrine' => true,
'cache.adapter.filesystem' => true,
'cache.adapter.memcached' => true,
'cache.adapter.psr6' => true,
'cache.adapter.redis' => true,
'cache.adapter.system' => true,
'cache.annotations' => true,
'cache.app.simple' => true,
'cache.default_clearer' => true,
'cache.default_memcached_provider' => true,
'cache.default_redis_provider' => true,
'cache.serializer' => true,
'cache.validator' => true,
'config.resource.self_checking_resource_checker' => true,
'config_cache_factory' => true,
'console.command.about' => true,
'console.command.assets_install' => true,
'console.command.cache_clear' => true,
'console.command.cache_pool_clear' => true,
'console.command.cache_pool_delete' => true,
'console.command.cache_pool_prune' => true,
'console.command.cache_warmup' => true,
'console.command.config_debug' => true,
'console.command.config_dump_reference' => true,
'console.command.container_debug' => true,
'console.command.debug_autowiring' => true,
'console.command.event_dispatcher_debug' => true,
'console.command.router_debug' => true,
'console.command.router_match' => true,
'console.command.yaml_lint' => true,
'console.error_listener' => true,
'controller_name_converter' => true,
'controller_resolver' => true,
'debug.debug_handlers_listener' => true,
'debug.file_link_formatter' => true,
'dependency_injection.config.container_parameters_resource_checker' => true,
'file_locator' => true,
'fragment.handler' => true,
'fragment.renderer.inline' => true,
'locale_listener' => true,
'logger' => true,
'parameter_bag' => true,
'resolve_controller_name_subscriber' => true,
'response_listener' => true,
'router.cache_warmer' => true,
'router.default' => true,
'router.request_context' => true,
'router_listener' => true,
'routing.loader.directory' => true,
'routing.loader.glob' => true,
'routing.loader.php' => true,
'routing.loader.service' => true,
'routing.loader.xml' => true,
'routing.loader.yml' => true,
'routing.resolver' => true,
'services_resetter' => true,
'session.attribute_bag' => true,
'session.flash_bag' => true,
'session.handler.native_file' => true,
'session.save_listener' => true,
'session.storage' => true,
'session.storage.filesystem' => true,
'session.storage.metadata_bag' => true,
'session.storage.mock_file' => true,
'session.storage.native' => true,
'session.storage.php_bridge' => true,
'session_listener' => true,
'streamed_response_listener' => true,
'uri_signer' => true,
'validate_request_listener' => true,
);
<?php
namespace ContainerKnJrcj8;
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
/**
* This class has been auto-generated
* by the Symfony Dependency Injection Component.
*
* @final since Symfony 3.3
*/
class srcDevDebugProjectContainer extends Container
{
private $buildParameters;
private $containerDir;
private $parameters;
private $targetDirs = array();
/**
* @internal but protected for BC on cache:clear
*/
protected $privates = array();
public function __construct(array $buildParameters = array(), $containerDir = __DIR__)
{
$dir = $this->targetDirs[0] = \dirname($containerDir);
for ($i = 1; $i <= 5; ++$i) {
$this->targetDirs[$i] = $dir = \dirname($dir);
}
$this->buildParameters = $buildParameters;
$this->containerDir = $containerDir;
$this->parameters = $this->getDefaultParameters();
$this->services = $this->privates = array();
$this->syntheticIds = array(
'kernel' => true,
);
$this->methodMap = array(
'event_dispatcher' => 'getEventDispatcherService',
'http_kernel' => 'getHttpKernelService',
'request_stack' => 'getRequestStackService',
'router' => 'getRouterService',
);
$this->fileMap = array(
'Symfony\\Bundle\\FrameworkBundle\\Controller\\RedirectController' => 'getRedirectControllerService.php',
'Symfony\\Bundle\\FrameworkBundle\\Controller\\TemplateController' => 'getTemplateControllerService.php',
'cache.app' => 'getCache_AppService.php',
'cache.app_clearer' => 'getCache_AppClearerService.php',
'cache.global_clearer' => 'getCache_GlobalClearerService.php',
'cache.system' => 'getCache_SystemService.php',
'cache.system_clearer' => 'getCache_SystemClearerService.php',
'cache_clearer' => 'getCacheClearerService.php',
'cache_warmer' => 'getCacheWarmerService.php',
'console.command_loader' => 'getConsole_CommandLoaderService.php',
'filesystem' => 'getFilesystemService.php',
'routing.loader' => 'getRouting_LoaderService.php',
'session' => 'getSessionService.php',
);
$this->aliases = array();
$this->privates['service_container'] = function () {
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Controller/ControllerNameParser.php';
include_once $this->targetDirs[3].'/vendor/symfony/event-dispatcher/EventSubscriberInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/EventListener/ResponseListener.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/EventListener/StreamedResponseListener.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/EventListener/LocaleListener.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/EventListener/ValidateRequestListener.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/EventListener/ResolveControllerNameSubscriber.php';
include_once $this->targetDirs[3].'/vendor/symfony/event-dispatcher/EventDispatcherInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/event-dispatcher/EventDispatcher.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/HttpKernelInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/TerminableInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/HttpKernel.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/Controller/ControllerResolverInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/Controller/ControllerResolver.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/Controller/ContainerControllerResolver.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Controller/ControllerResolver.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/Controller/ArgumentResolverInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/Controller/ArgumentResolver.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactoryInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactory.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-foundation/RequestStack.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/EventListener/AbstractSessionListener.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/EventListener/SessionListener.php';
include_once $this->targetDirs[3].'/vendor/symfony/dependency-injection/ServiceLocator.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/EventListener/DebugHandlersListener.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/Debug/FileLinkFormatter.php';
include_once $this->targetDirs[3].'/vendor/symfony/routing/RequestContext.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/EventListener/RouterListener.php';
include_once $this->targetDirs[3].'/vendor/psr/log/Psr/Log/LoggerInterface.php';
include_once $this->targetDirs[3].'/vendor/psr/log/Psr/Log/AbstractLogger.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/Log/Logger.php';
include_once $this->targetDirs[3].'/vendor/symfony/routing/RequestContextAwareInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/routing/Matcher/UrlMatcherInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/routing/Generator/UrlGeneratorInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/routing/RouterInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/routing/Matcher/RequestMatcherInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/routing/Router.php';
include_once $this->targetDirs[3].'/vendor/symfony/http-kernel/CacheWarmer/WarmableInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/dependency-injection/ServiceSubscriberInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/framework-bundle/Routing/Router.php';
include_once $this->targetDirs[3].'/vendor/symfony/dependency-injection/ParameterBag/ParameterBagInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/dependency-injection/ParameterBag/ParameterBag.php';
include_once $this->targetDirs[3].'/vendor/symfony/dependency-injection/ParameterBag/FrozenParameterBag.php';
include_once $this->targetDirs[3].'/vendor/symfony/dependency-injection/ParameterBag/ContainerBagInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/dependency-injection/ParameterBag/ContainerBag.php';
include_once $this->targetDirs[3].'/vendor/symfony/config/ConfigCacheFactoryInterface.php';
include_once $this->targetDirs[3].'/vendor/symfony/config/ResourceCheckerConfigCacheFactory.php';
};
}
public function reset()
{
$this->privates = array();
parent::reset();
}
public function compile()
{
throw new LogicException('You cannot compile a dumped container that was already compiled.');
}
public function isCompiled()
{
return true;
}
public function getRemovedIds()
{
return require $this->containerDir.\DIRECTORY_SEPARATOR.'removed-ids.php';
}
protected function load($file, $lazyLoad = true)
{
return require $this->containerDir.\DIRECTORY_SEPARATOR.$file;
}
/**
* Gets the public 'event_dispatcher' shared service.
*
* @return \Symfony\Component\EventDispatcher\EventDispatcher
*/
protected function getEventDispatcherService()
{
$this->services['event_dispatcher'] = $instance = new \Symfony\Component\EventDispatcher\EventDispatcher();
$instance->addListener('kernel.response', array(0 => function () {
return ($this->privates['response_listener'] ?? $this->privates['response_listener'] = new \Symfony\Component\HttpKernel\EventListener\ResponseListener('UTF-8'));
}, 1 => 'onKernelResponse'), 0);
$instance->addListener('kernel.response', array(0 => function () {
return ($this->privates['streamed_response_listener'] ?? $this->privates['streamed_response_listener'] = new \Symfony\Component\HttpKernel\EventListener\StreamedResponseListener());
}, 1 => 'onKernelResponse'), -1024);
$instance->addListener('kernel.request', array(0 => function () {
return ($this->privates['locale_listener'] ?? $this->getLocaleListenerService());
}, 1 => 'onKernelRequest'), 16);
$instance->addListener('kernel.finish_request', array(0 => function () {
return ($this->privates['locale_listener'] ?? $this->getLocaleListenerService());
}, 1 => 'onKernelFinishRequest'), 0);
$instance->addListener('kernel.request', array(0 => function () {
return ($this->privates['validate_request_listener'] ?? $this->privates['validate_request_listener'] = new \Symfony\Component\HttpKernel\EventListener\ValidateRequestListener());
}, 1 => 'onKernelRequest'), 256);
$instance->addListener('kernel.request', array(0 => function () {
return ($this->privates['resolve_controller_name_subscriber'] ?? $this->getResolveControllerNameSubscriberService());
}, 1 => 'onKernelRequest'), 24);
$instance->addListener('console.error', array(0 => function () {
return ($this->privates['console.error_listener'] ?? $this->load('getConsole_ErrorListenerService.php'));
}, 1 => 'onConsoleError'), -128);
$instance->addListener('console.terminate', array(0 => function () {
return ($this->privates['console.error_listener'] ?? $this->load('getConsole_ErrorListenerService.php'));
}, 1 => 'onConsoleTerminate'), -128);
$instance->addListener('kernel.request', array(0 => function () {
return ($this->privates['session_listener'] ?? $this->getSessionListenerService());
}, 1 => 'onKernelRequest'), 128);
$instance->addListener('kernel.response', array(0 => function () {
return ($this->privates['session_listener'] ?? $this->getSessionListenerService());
}, 1 => 'onKernelResponse'), -1000);
$instance->addListener('kernel.finish_request', array(0 => function () {
return ($this->privates['session_listener'] ?? $this->getSessionListenerService());
}, 1 => 'onFinishRequest'), 0);
$instance->addListener('kernel.request', array(0 => function () {
return ($this->privates['debug.debug_handlers_listener'] ?? $this->getDebug_DebugHandlersListenerService());
}, 1 => 'configure'), 2048);
$instance->addListener('console.command', array(0 => function () {
return ($this->privates['debug.debug_handlers_listener'] ?? $this->getDebug_DebugHandlersListenerService());
}, 1 => 'configure'), 2048);
$instance->addListener('kernel.request', array(0 => function () {
return ($this->privates['router_listener'] ?? $this->getRouterListenerService());
}, 1 => 'onKernelRequest'), 32);
$instance->addListener('kernel.finish_request', array(0 => function () {
return ($this->privates['router_listener'] ?? $this->getRouterListenerService());
}, 1 => 'onKernelFinishRequest'), 0);
$instance->addListener('kernel.exception', array(0 => function () {
return ($this->privates['router_listener'] ?? $this->getRouterListenerService());
}, 1 => 'onKernelException'), -64);
return $instance;
}
/**
* Gets the public 'http_kernel' shared service.
*
* @return \Symfony\Component\HttpKernel\HttpKernel
*/
protected function getHttpKernelService()
{
return $this->services['http_kernel'] = new \Symfony\Component\HttpKernel\HttpKernel(($this->services['event_dispatcher'] ?? $this->getEventDispatcherService()), new \Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver($this, ($this->privates['controller_name_converter'] ?? $this->privates['controller_name_converter'] = new \Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser(($this->services['kernel'] ?? $this->get('kernel', 1)))), ($this->privates['logger'] ?? $this->privates['logger'] = new \Symfony\Component\HttpKernel\Log\Logger())), ($this->services['request_stack'] ?? $this->services['request_stack'] = new \Symfony\Component\HttpFoundation\RequestStack()), new \Symfony\Component\HttpKernel\Controller\ArgumentResolver(new \Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactory(), new RewindableGenerator(function () {
yield 0 => ($this->privates['argument_resolver.request_attribute'] ?? $this->privates['argument_resolver.request_attribute'] = new \Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestAttributeValueResolver());
yield 1 => ($this->privates['argument_resolver.request'] ?? $this->privates['argument_resolver.request'] = new \Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestValueResolver());
yield 2 => ($this->privates['argument_resolver.session'] ?? $this->privates['argument_resolver.session'] = new \Symfony\Component\HttpKernel\Controller\ArgumentResolver\SessionValueResolver());
yield 3 => ($this->privates['argument_resolver.service'] ?? $this->load('getArgumentResolver_ServiceService.php'));
yield 4 => ($this->privates['argument_resolver.default'] ?? $this->privates['argument_resolver.default'] = new \Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver());
yield 5 => ($this->privates['argument_resolver.variadic'] ?? $this->privates['argument_resolver.variadic'] = new \Symfony\Component\HttpKernel\Controller\ArgumentResolver\VariadicValueResolver());
}, 6)));
}
/**
* Gets the public 'request_stack' shared service.
*
* @return \Symfony\Component\HttpFoundation\RequestStack
*/
protected function getRequestStackService()
{
return $this->services['request_stack'] = new \Symfony\Component\HttpFoundation\RequestStack();
}
/**
* Gets the public 'router' shared service.
*
* @return \Symfony\Bundle\FrameworkBundle\Routing\Router
*/
protected function getRouterService()
{
$this->services['router'] = $instance = new \Symfony\Bundle\FrameworkBundle\Routing\Router((new \Symfony\Component\DependencyInjection\ServiceLocator(array('routing.loader' => function (): \Symfony\Component\Config\Loader\LoaderInterface {
return ($this->services['routing.loader'] ?? $this->load('getRouting_LoaderService.php'));
})))->withContext('router.default', $this), 'kernel::loadRoutes', array('cache_dir' => $this->targetDirs[0], 'debug' => true, 'generator_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator', 'generator_base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator', 'generator_dumper_class' => 'Symfony\\Component\\Routing\\Generator\\Dumper\\PhpGeneratorDumper', 'generator_cache_class' => 'srcDevDebugProjectContainerUrlGenerator', 'matcher_class' => 'Symfony\\Bundle\\FrameworkBundle\\Routing\\RedirectableUrlMatcher', 'matcher_base_class' => 'Symfony\\Bundle\\FrameworkBundle\\Routing\\RedirectableUrlMatcher', 'matcher_dumper_class' => 'Symfony\\Component\\Routing\\Matcher\\Dumper\\PhpMatcherDumper', 'matcher_cache_class' => 'srcDevDebugProjectContainerUrlMatcher', 'strict_requirements' => true, 'resource_type' => 'service'), ($this->privates['router.request_context'] ?? $this->getRouter_RequestContextService()), new \Symfony\Component\DependencyInjection\ParameterBag\ContainerBag($this), ($this->privates['logger'] ?? $this->privates['logger'] = new \Symfony\Component\HttpKernel\Log\Logger()));
$instance->setConfigCacheFactory(new \Symfony\Component\Config\ResourceCheckerConfigCacheFactory(new RewindableGenerator(function () {
yield 0 => ($this->privates['dependency_injection.config.container_parameters_resource_checker'] ?? $this->privates['dependency_injection.config.container_parameters_resource_checker'] = new \Symfony\Component\DependencyInjection\Config\ContainerParametersResourceChecker($this));
yield 1 => ($this->privates['config.resource.self_checking_resource_checker'] ?? $this->privates['config.resource.self_checking_resource_checker'] = new \Symfony\Component\Config\Resource\SelfCheckingResourceChecker());
}, 2)));
return $instance;
}
/**
* Gets the private 'debug.debug_handlers_listener' shared service.
*
* @return \Symfony\Component\HttpKernel\EventListener\DebugHandlersListener
*/
protected function getDebug_DebugHandlersListenerService()
{
return $this->privates['debug.debug_handlers_listener'] = new \Symfony\Component\HttpKernel\EventListener\DebugHandlersListener(NULL, ($this->privates['logger'] ?? $this->privates['logger'] = new \Symfony\Component\HttpKernel\Log\Logger()), NULL, -1, true, new \Symfony\Component\HttpKernel\Debug\FileLinkFormatter(NULL), true);
}
/**
* Gets the private 'locale_listener' shared service.
*
* @return \Symfony\Component\HttpKernel\EventListener\LocaleListener
*/
protected function getLocaleListenerService()
{
return $this->privates['locale_listener'] = new \Symfony\Component\HttpKernel\EventListener\LocaleListener(($this->services['request_stack'] ?? $this->services['request_stack'] = new \Symfony\Component\HttpFoundation\RequestStack()), 'en', ($this->services['router'] ?? $this->getRouterService()));
}
/**
* Gets the private 'resolve_controller_name_subscriber' shared service.
*
* @return \Symfony\Bundle\FrameworkBundle\EventListener\ResolveControllerNameSubscriber
*/
protected function getResolveControllerNameSubscriberService()
{
return $this->privates['resolve_controller_name_subscriber'] = new \Symfony\Bundle\FrameworkBundle\EventListener\ResolveControllerNameSubscriber(($this->privates['controller_name_converter'] ?? $this->privates['controller_name_converter'] = new \Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser(($this->services['kernel'] ?? $this->get('kernel', 1)))));
}
/**
* Gets the private 'router.request_context' shared service.
*
* @return \Symfony\Component\Routing\RequestContext
*/
protected function getRouter_RequestContextService()
{
return $this->privates['router.request_context'] = new \Symfony\Component\Routing\RequestContext('', 'GET', 'localhost', 'http', 80, 443);
}
/**
* Gets the private 'router_listener' shared service.
*
* @return \Symfony\Component\HttpKernel\EventListener\RouterListener
*/
protected function getRouterListenerService()
{
return $this->privates['router_listener'] = new \Symfony\Component\HttpKernel\EventListener\RouterListener(($this->services['router'] ?? $this->getRouterService()), ($this->services['request_stack'] ?? $this->services['request_stack'] = new \Symfony\Component\HttpFoundation\RequestStack()), ($this->privates['router.request_context'] ?? $this->getRouter_RequestContextService()), ($this->privates['logger'] ?? $this->privates['logger'] = new \Symfony\Component\HttpKernel\Log\Logger()), $this->targetDirs[3], true);
}
/**
* Gets the private 'session_listener' shared service.
*
* @return \Symfony\Component\HttpKernel\EventListener\SessionListener
*/
protected function getSessionListenerService()
{
return $this->privates['session_listener'] = new \Symfony\Component\HttpKernel\EventListener\SessionListener(new \Symfony\Component\DependencyInjection\ServiceLocator(array('initialized_session' => function () {
return ($this->services['session'] ?? null);
}, 'session' => function () {
return ($this->services['session'] ?? $this->load('getSessionService.php'));
})));
}
public function getParameter($name)
{
$name = (string) $name;
if (isset($this->buildParameters[$name])) {
return $this->buildParameters[$name];
}
if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name));
}
if (isset($this->loadedDynamicParameters[$name])) {
return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name);
}
return $this->parameters[$name];
}
public function hasParameter($name)
{
$name = (string) $name;
if (isset($this->buildParameters[$name])) {
return true;
}
return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters);
}
public function setParameter($name, $value)
{
throw new LogicException('Impossible to call set() on a frozen ParameterBag.');
}
public function getParameterBag()
{
if (null === $this->parameterBag) {
$parameters = $this->parameters;
foreach ($this->loadedDynamicParameters as $name => $loaded) {
$parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name);
}
foreach ($this->buildParameters as $name => $value) {
$parameters[$name] = $value;
}
$this->parameterBag = new FrozenParameterBag($parameters);
}
return $this->parameterBag;
}
private $loadedDynamicParameters = array(
'kernel.root_dir' => false,
'kernel.project_dir' => false,
'kernel.cache_dir' => false,
'kernel.logs_dir' => false,
'kernel.bundles_metadata' => false,
'kernel.secret' => false,
'session.save_path' => false,
'debug.container.dump' => false,
);
private $dynamicParameters = array();
/**
* Computes a dynamic parameter.
*
* @param string The name of the dynamic parameter to load
*
* @return mixed The value of the dynamic parameter
*
* @throws InvalidArgumentException When the dynamic parameter does not exist
*/
private function getDynamicParameter($name)
{
switch ($name) {
case 'kernel.root_dir': $value = ($this->targetDirs[3].'/src'); break;
case 'kernel.project_dir': $value = $this->targetDirs[3]; break;
case 'kernel.cache_dir': $value = $this->targetDirs[0]; break;
case 'kernel.logs_dir': $value = ($this->targetDirs[2].'/log'); break;
case 'kernel.bundles_metadata': $value = array(
'FrameworkBundle' => array(
'path' => ($this->targetDirs[3].'/vendor/symfony/framework-bundle'),
'namespace' => 'Symfony\\Bundle\\FrameworkBundle',
),
); break;
case 'kernel.secret': $value = $this->getEnv('APP_SECRET'); break;
case 'session.save_path': $value = ($this->targetDirs[0].'/sessions'); break;
case 'debug.container.dump': $value = ($this->targetDirs[0].'/srcDevDebugProjectContainer.xml'); break;
default: throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name));
}
$this->loadedDynamicParameters[$name] = true;
return $this->dynamicParameters[$name] = $value;
}
/**
* Gets the default parameters.
*
* @return array An array of the default parameters
*/
protected function getDefaultParameters()
{
return array(
'kernel.environment' => 'dev',
'kernel.debug' => true,
'kernel.name' => 'src',
'kernel.bundles' => array(
'FrameworkBundle' => 'Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle',
),
'kernel.charset' => 'UTF-8',
'kernel.container_class' => 'srcDevDebugProjectContainer',
'container.autowiring.strict_mode' => true,
'container.dumper.inline_class_loader' => true,
'fragment.renderer.hinclude.global_template' => '',
'fragment.path' => '/_fragment',
'kernel.http_method_override' => true,
'kernel.trusted_hosts' => array(
),
'kernel.default_locale' => 'en',
'templating.helper.code.file_link_format' => NULL,
'debug.file_link_format' => NULL,
'session.metadata.storage_key' => '_sf2_meta',
'session.storage.options' => array(
'cache_limiter' => '0',
'cookie_httponly' => true,
'gc_probability' => 1,
),
'session.metadata.update_threshold' => '0',
'data_collector.templates' => array(
),
'debug.error_handler.throw_at' => -1,
'router.request_context.host' => 'localhost',
'router.request_context.scheme' => 'http',
'router.request_context.base_url' => '',
'router.resource' => 'kernel::loadRoutes',
'router.cache_class_prefix' => 'srcDevDebugProjectContainer',
'request_listener.http_port' => 80,
'request_listener.https_port' => 443,
'console.command.ids' => array(
),
);
}
}
<?php
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
if (\class_exists(\ContainerKnJrcj8\srcDevDebugProjectContainer::class, false)) {
// no-op
} elseif (!include __DIR__.'/ContainerKnJrcj8/srcDevDebugProjectContainer.php') {
touch(__DIR__.'/ContainerKnJrcj8.legacy');
return;
}
if (!\class_exists(srcDevDebugProjectContainer::class, false)) {
\class_alias(\ContainerKnJrcj8\srcDevDebugProjectContainer::class, srcDevDebugProjectContainer::class, false);
}
return new \ContainerKnJrcj8\srcDevDebugProjectContainer(array(
'container.build_hash' => 'KnJrcj8',
'container.build_id' => '5af88e4c',
'container.build_time' => 1539265520,
), __DIR__.\DIRECTORY_SEPARATOR.'ContainerKnJrcj8');
a:24:{i:0;C:50:"Symfony\Component\Config\Resource\ComposerResource":85:{a:1:{s:58:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/vendor";i:1539265518;}}i:1;C:46:"Symfony\Component\Config\Resource\FileResource":74:{s:66:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/src/Kernel.php";}i:2;C:56:"Symfony\Component\Config\Resource\ClassExistenceResource":101:{a:2:{i:0;s:75:"Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass";i:1;b:0;}}i:3;C:56:"Symfony\Component\Config\Resource\ClassExistenceResource":102:{a:2:{i:0;s:76:"Symfony\Component\Validator\DependencyInjection\AddValidatorInitializersPass";i:1;b:0;}}i:4;C:56:"Symfony\Component\Config\Resource\ClassExistenceResource":93:{a:2:{i:0;s:67:"Symfony\Component\Console\DependencyInjection\AddConsoleCommandPass";i:1;b:1;}}i:5;C:56:"Symfony\Component\Config\Resource\ClassExistenceResource":90:{a:2:{i:0;s:64:"Symfony\Component\Translation\DependencyInjection\TranslatorPass";i:1;b:0;}}i:6;C:56:"Symfony\Component\Config\Resource\ClassExistenceResource":100:{a:2:{i:0;s:74:"Symfony\Component\Translation\DependencyInjection\TranslationExtractorPass";i:1;b:0;}}i:7;C:56:"Symfony\Component\Config\Resource\ClassExistenceResource":97:{a:2:{i:0;s:71:"Symfony\Component\Translation\DependencyInjection\TranslationDumperPass";i:1;b:0;}}i:8;C:56:"Symfony\Component\Config\Resource\ClassExistenceResource":89:{a:2:{i:0;s:63:"Symfony\Component\Serializer\DependencyInjection\SerializerPass";i:1;b:0;}}i:9;C:56:"Symfony\Component\Config\Resource\ClassExistenceResource":93:{a:2:{i:0;s:67:"Symfony\Component\PropertyInfo\DependencyInjection\PropertyInfoPass";i:1;b:0;}}i:10;C:56:"Symfony\Component\Config\Resource\ClassExistenceResource":94:{a:2:{i:0;s:68:"Symfony\Component\Workflow\DependencyInjection\ValidateWorkflowsPass";i:1;b:0;}}i:11;C:56:"Symfony\Component\Config\Resource\ClassExistenceResource":77:{a:2:{i:0;s:51:"Symfony\Component\Form\DependencyInjection\FormPass";i:1;b:0;}}i:12;C:56:"Symfony\Component\Config\Resource\ClassExistenceResource":87:{a:2:{i:0;s:61:"Symfony\Component\Messenger\DependencyInjection\MessengerPass";i:1;b:0;}}i:13;C:46:"Symfony\Component\Config\Resource\FileResource":78:{s:70:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config/bundles.php";}i:14;C:46:"Symfony\Component\Config\Resource\FileResource":90:{s:82:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config/packages/framework.yaml";}i:15;C:46:"Symfony\Component\Config\Resource\FileResource":88:{s:80:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config/packages/routing.yaml";}i:16;C:46:"Symfony\Component\Config\Resource\GlobResource":172:{a:4:{i:0;s:58:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config";i:1;s:32:"/{packages}/*.{php,xml,yaml,yml}";i:2;b:0;i:3;s:32:"a8d995a7279cfc07b653158126a01f26";}}i:17;C:46:"Symfony\Component\Config\Resource\FileResource":92:{s:84:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config/packages/dev/routing.yaml";}i:18;C:46:"Symfony\Component\Config\Resource\GlobResource":179:{a:4:{i:0;s:58:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config";i:1;s:39:"/{packages}/dev/**/*.{php,xml,yaml,yml}";i:2;b:0;i:3;s:32:"15daf4edc0bebc1017b9325f9a877ac3";}}i:19;C:46:"Symfony\Component\Config\Resource\FileResource":80:{s:72:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config/services.yaml";}i:20;C:46:"Symfony\Component\Config\Resource\GlobResource":138:{a:4:{i:0;s:55:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/src";i:1;s:2:"/*";i:2;b:1;i:3;s:32:"36332e941bc1ae7d87a6402c0e2183a5";}}i:21;C:46:"Symfony\Component\Config\Resource\GlobResource":147:{a:4:{i:0;s:66:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/src/Controller";i:1;s:0:"";i:2;b:1;i:3;s:32:"d41d8cd98f00b204e9800998ecf8427e";}}i:22;C:46:"Symfony\Component\Config\Resource\GlobResource":170:{a:4:{i:0;s:58:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config";i:1;s:30:"/{services}.{php,xml,yaml,yml}";i:2;b:0;i:3;s:32:"4eabcae6004b265945ad7e334b257934";}}i:23;C:46:"Symfony\Component\Config\Resource\GlobResource":174:{a:4:{i:0;s:58:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config";i:1;s:34:"/{services}_dev.{php,xml,yaml,yml}";i:2;b:0;i:3;s:32:"d41d8cd98f00b204e9800998ecf8427e";}}}
<?xml version="1.0" encoding="utf-8"?>
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="kernel.root_dir">/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/src</parameter>
<parameter key="kernel.project_dir">/Users/Dirollo/Documents/Mes sites/BoucherieDirollo</parameter>
<parameter key="kernel.environment">dev</parameter>
<parameter key="kernel.debug">true</parameter>
<parameter key="kernel.name">src</parameter>
<parameter key="kernel.cache_dir">/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/var/cache/dev</parameter>
<parameter key="kernel.logs_dir">/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/var/log</parameter>
<parameter key="kernel.bundles" type="collection">
<parameter key="FrameworkBundle">Symfony\Bundle\FrameworkBundle\FrameworkBundle</parameter>
</parameter>
<parameter key="kernel.bundles_metadata" type="collection">
<parameter key="FrameworkBundle" type="collection">
<parameter key="path">/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/vendor/symfony/framework-bundle</parameter>
<parameter key="namespace">Symfony\Bundle\FrameworkBundle</parameter>
</parameter>
</parameter>
<parameter key="kernel.charset">UTF-8</parameter>
<parameter key="kernel.container_class">srcDevDebugProjectContainer</parameter>
<parameter key="container.autowiring.strict_mode">true</parameter>
<parameter key="container.dumper.inline_class_loader">true</parameter>
<parameter key="fragment.renderer.hinclude.global_template"></parameter>
<parameter key="fragment.path">/_fragment</parameter>
<parameter key="kernel.secret">%env(APP_SECRET)%</parameter>
<parameter key="kernel.http_method_override">true</parameter>
<parameter key="kernel.trusted_hosts" type="collection"/>
<parameter key="kernel.default_locale">en</parameter>
<parameter key="templating.helper.code.file_link_format">null</parameter>
<parameter key="debug.file_link_format">null</parameter>
<parameter key="session.metadata.storage_key">_sf2_meta</parameter>
<parameter key="session.storage.options" type="collection">
<parameter key="cache_limiter">0</parameter>
<parameter key="cookie_httponly">true</parameter>
<parameter key="gc_probability">1</parameter>
</parameter>
<parameter key="session.save_path">/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/var/cache/dev/sessions</parameter>
<parameter key="session.metadata.update_threshold">0</parameter>
<parameter key="data_collector.templates" type="collection"/>
<parameter key="debug.error_handler.throw_at">-1</parameter>
<parameter key="debug.container.dump">/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/var/cache/dev/srcDevDebugProjectContainer.xml</parameter>
<parameter key="router.request_context.host">localhost</parameter>
<parameter key="router.request_context.scheme">http</parameter>
<parameter key="router.request_context.base_url"></parameter>
<parameter key="router.resource">kernel::loadRoutes</parameter>
<parameter key="router.cache_class_prefix">srcDevDebugProjectContainer</parameter>
<parameter key="request_listener.http_port">80</parameter>
<parameter key="request_listener.https_port">443</parameter>
<parameter key="console.command.ids" type="collection"/>
</parameters>
<services>
<service id="service_container" class="Symfony\Component\DependencyInjection\ContainerInterface" public="true" synthetic="true"/>
<service id="controller_name_converter" class="Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser" public="false">
<tag name="monolog.logger" channel="request"/>
<argument type="service" id="kernel"/>
</service>
<service id="controller_resolver" class="Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver" public="false">
<tag name="monolog.logger" channel="request"/>
<argument type="service" id="service_container"/>
<argument type="service" id="controller_name_converter"/>
<argument type="service" id="logger" on-invalid="ignore"/>
</service>
<service id="argument_metadata_factory" class="Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactory" public="false"/>
<service id="argument_resolver" class="Symfony\Component\HttpKernel\Controller\ArgumentResolver" public="false">
<argument type="service" id="argument_metadata_factory"/>
<argument type="iterator">
<argument type="service" id="argument_resolver.request_attribute"/>
<argument type="service" id="argument_resolver.request"/>
<argument type="service" id="argument_resolver.session"/>
<argument type="service" id="argument_resolver.service"/>
<argument type="service" id="argument_resolver.default"/>
<argument type="service" id="argument_resolver.variadic"/>
</argument>
</service>
<service id="argument_resolver.request_attribute" class="Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestAttributeValueResolver" public="false">
<tag name="controller.argument_value_resolver" priority="100"/>
</service>
<service id="argument_resolver.request" class="Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestValueResolver" public="false">
<tag name="controller.argument_value_resolver" priority="50"/>
</service>
<service id="argument_resolver.session" class="Symfony\Component\HttpKernel\Controller\ArgumentResolver\SessionValueResolver" public="false">
<tag name="controller.argument_value_resolver" priority="50"/>
</service>
<service id="argument_resolver.service" class="Symfony\Component\HttpKernel\Controller\ArgumentResolver\ServiceValueResolver" public="false">
<tag name="controller.argument_value_resolver" priority="-50"/>
<argument type="service" id=".service_locator.9_yeNH1"/>
</service>
<service id="argument_resolver.default" class="Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver" public="false">
<tag name="controller.argument_value_resolver" priority="-100"/>
</service>
<service id="argument_resolver.variadic" class="Symfony\Component\HttpKernel\Controller\ArgumentResolver\VariadicValueResolver" public="false">
<tag name="controller.argument_value_resolver" priority="-150"/>
</service>
<service id="response_listener" class="Symfony\Component\HttpKernel\EventListener\ResponseListener" public="false">
<tag name="kernel.event_subscriber"/>
<tag name="container.hot_path"/>
<argument>UTF-8</argument>
</service>
<service id="streamed_response_listener" class="Symfony\Component\HttpKernel\EventListener\StreamedResponseListener" public="false">
<tag name="kernel.event_subscriber"/>
<tag name="container.hot_path"/>
</service>
<service id="locale_listener" class="Symfony\Component\HttpKernel\EventListener\LocaleListener" public="false">
<tag name="kernel.event_subscriber"/>
<tag name="container.hot_path"/>
<tag name="container.hot_path"/>
<argument type="service" id="request_stack"/>
<argument>en</argument>
<argument type="service" id="router.default" on-invalid="ignore"/>
</service>
<service id="validate_request_listener" class="Symfony\Component\HttpKernel\EventListener\ValidateRequestListener" public="false">
<tag name="kernel.event_subscriber"/>
<tag name="container.hot_path"/>
</service>
<service id="resolve_controller_name_subscriber" class="Symfony\Bundle\FrameworkBundle\EventListener\ResolveControllerNameSubscriber" public="false">
<tag name="kernel.event_subscriber"/>
<tag name="container.hot_path"/>
<argument type="service" id="controller_name_converter"/>
</service>
<service id="parameter_bag" class="Symfony\Component\DependencyInjection\ParameterBag\ContainerBag" public="false">
<argument type="service" id="service_container"/>
</service>
<service id="event_dispatcher" class="Symfony\Component\EventDispatcher\EventDispatcher" public="true">
<tag name="container.hot_path"/>
<call method="addListener">
<argument>kernel.response</argument>
<argument type="collection">
<argument type="service" id="response_listener"/>
<argument>onKernelResponse</argument>
</argument>
<argument>0</argument>
</call>
<call method="addListener">
<argument>kernel.response</argument>
<argument type="collection">
<argument type="service" id="streamed_response_listener"/>
<argument>onKernelResponse</argument>
</argument>
<argument>-1024</argument>
</call>
<call method="addListener">
<argument>kernel.request</argument>
<argument type="collection">
<argument type="service" id="locale_listener"/>
<argument>onKernelRequest</argument>
</argument>
<argument>16</argument>
</call>
<call method="addListener">
<argument>kernel.finish_request</argument>
<argument type="collection">
<argument type="service" id="locale_listener"/>
<argument>onKernelFinishRequest</argument>
</argument>
<argument>0</argument>
</call>
<call method="addListener">
<argument>kernel.request</argument>
<argument type="collection">
<argument type="service" id="validate_request_listener"/>
<argument>onKernelRequest</argument>
</argument>
<argument>256</argument>
</call>
<call method="addListener">
<argument>kernel.request</argument>
<argument type="collection">
<argument type="service" id="resolve_controller_name_subscriber"/>
<argument>onKernelRequest</argument>
</argument>
<argument>24</argument>
</call>
<call method="addListener">
<argument>console.error</argument>
<argument type="collection">
<argument type="service" id="console.error_listener"/>
<argument>onConsoleError</argument>
</argument>
<argument>-128</argument>
</call>
<call method="addListener">
<argument>console.terminate</argument>
<argument type="collection">
<argument type="service" id="console.error_listener"/>
<argument>onConsoleTerminate</argument>
</argument>
<argument>-128</argument>
</call>
<call method="addListener">
<argument>kernel.request</argument>
<argument type="collection">
<argument type="service" id="session_listener"/>
<argument>onKernelRequest</argument>
</argument>
<argument>128</argument>
</call>
<call method="addListener">
<argument>kernel.response</argument>
<argument type="collection">
<argument type="service" id="session_listener"/>
<argument>onKernelResponse</argument>
</argument>
<argument>-1000</argument>
</call>
<call method="addListener">
<argument>kernel.finish_request</argument>
<argument type="collection">
<argument type="service" id="session_listener"/>
<argument>onFinishRequest</argument>
</argument>
<argument>0</argument>
</call>
<call method="addListener">
<argument>kernel.request</argument>
<argument type="collection">
<argument type="service" id="debug.debug_handlers_listener"/>
<argument>configure</argument>
</argument>
<argument>2048</argument>
</call>
<call method="addListener">
<argument>console.command</argument>
<argument type="collection">
<argument type="service" id="debug.debug_handlers_listener"/>
<argument>configure</argument>
</argument>
<argument>2048</argument>
</call>
<call method="addListener">
<argument>kernel.request</argument>
<argument type="collection">
<argument type="service" id="router_listener"/>
<argument>onKernelRequest</argument>
</argument>
<argument>32</argument>
</call>
<call method="addListener">
<argument>kernel.finish_request</argument>
<argument type="collection">
<argument type="service" id="router_listener"/>
<argument>onKernelFinishRequest</argument>
</argument>
<argument>0</argument>
</call>
<call method="addListener">
<argument>kernel.exception</argument>
<argument type="collection">
<argument type="service" id="router_listener"/>
<argument>onKernelException</argument>
</argument>
<argument>-64</argument>
</call>
</service>
<service id="http_kernel" class="Symfony\Component\HttpKernel\HttpKernel" public="true">
<tag name="container.hot_path"/>
<argument type="service" id="event_dispatcher"/>
<argument type="service" id="controller_resolver"/>
<argument type="service" id="request_stack"/>
<argument type="service" id="argument_resolver"/>
</service>
<service id="request_stack" class="Symfony\Component\HttpFoundation\RequestStack" public="true"/>
<service id="cache_warmer" class="Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerAggregate" public="true">
<argument type="tagged" tag="kernel.cache_warmer"/>
</service>
<service id="cache_clearer" class="Symfony\Component\HttpKernel\CacheClearer\ChainCacheClearer" public="true">
<argument type="tagged" tag="kernel.cache_clearer"/>
</service>
<service id="kernel" public="true" synthetic="true"/>
<service id="filesystem" class="Symfony\Component\Filesystem\Filesystem" public="true"/>
<service id="file_locator" class="Symfony\Component\HttpKernel\Config\FileLocator" public="false">
<argument type="service" id="kernel"/>
<argument>/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/src/Resources</argument>
<argument type="collection">
<argument>/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/src</argument>
</argument>
</service>
<service id="uri_signer" class="Symfony\Component\HttpKernel\UriSigner" public="false">
<argument>%env(APP_SECRET)%</argument>
</service>
<service id="config_cache_factory" class="Symfony\Component\Config\ResourceCheckerConfigCacheFactory" public="false">
<argument type="tagged" tag="config_cache.resource_checker"/>
</service>
<service id="dependency_injection.config.container_parameters_resource_checker" class="Symfony\Component\DependencyInjection\Config\ContainerParametersResourceChecker" public="false">
<tag name="config_cache.resource_checker" priority="-980"/>
<argument type="service" id="service_container"/>
</service>
<service id="config.resource.self_checking_resource_checker" class="Symfony\Component\Config\Resource\SelfCheckingResourceChecker" public="false">
<tag name="config_cache.resource_checker" priority="-990"/>
</service>
<service id="fragment.handler" class="Symfony\Component\HttpKernel\DependencyInjection\LazyLoadingFragmentHandler" public="false">
<argument type="service" id=".service_locator.gmwRZ3h"/>
<argument type="service" id="request_stack"/>
<argument>true</argument>
</service>
<service id="fragment.renderer.inline" class="Symfony\Component\HttpKernel\Fragment\InlineFragmentRenderer" public="false">
<tag name="kernel.fragment_renderer" alias="inline"/>
<argument type="service" id="http_kernel"/>
<argument type="service" id="event_dispatcher"/>
<call method="setFragmentPath">
<argument>/_fragment</argument>
</call>
</service>
<service id="console.error_listener" class="Symfony\Component\Console\EventListener\ErrorListener" public="false">
<tag name="kernel.event_subscriber"/>
<tag name="monolog.logger" channel="console"/>
<argument type="service" id="logger" on-invalid="null"/>
</service>
<service id="console.command.about" class="Symfony\Bundle\FrameworkBundle\Command\AboutCommand" public="false">
<tag name="console.command" command="about"/>
<call method="setName">
<argument>about</argument>
</call>
</service>
<service id="console.command.assets_install" class="Symfony\Bundle\FrameworkBundle\Command\AssetsInstallCommand" public="false">
<tag name="console.command" command="assets:install"/>
<argument type="service" id="filesystem"/>
<call method="setName">
<argument>assets:install</argument>
</call>
</service>
<service id="console.command.cache_clear" class="Symfony\Bundle\FrameworkBundle\Command\CacheClearCommand" public="false">
<tag name="console.command" command="cache:clear"/>
<argument type="service" id="cache_clearer"/>
<argument type="service" id="filesystem"/>
<call method="setName">
<argument>cache:clear</argument>
</call>
</service>
<service id="console.command.cache_pool_clear" class="Symfony\Bundle\FrameworkBundle\Command\CachePoolClearCommand" public="false">
<tag name="console.command" command="cache:pool:clear"/>
<argument type="service" id="cache.global_clearer"/>
<call method="setName">
<argument>cache:pool:clear</argument>
</call>
</service>
<service id="console.command.cache_pool_prune" class="Symfony\Bundle\FrameworkBundle\Command\CachePoolPruneCommand" public="false">
<tag name="console.command" command="cache:pool:prune"/>
<argument type="iterator"/>
<call method="setName">
<argument>cache:pool:prune</argument>
</call>
</service>
<service id="console.command.cache_pool_delete" class="Symfony\Bundle\FrameworkBundle\Command\CachePoolDeleteCommand" public="false">
<tag name="console.command" command="cache:pool:delete"/>
<argument type="service" id="cache.global_clearer"/>
<call method="setName">
<argument>cache:pool:delete</argument>
</call>
</service>
<service id="console.command.cache_warmup" class="Symfony\Bundle\FrameworkBundle\Command\CacheWarmupCommand" public="false">
<tag name="console.command" command="cache:warmup"/>
<argument type="service" id="cache_warmer"/>
<call method="setName">
<argument>cache:warmup</argument>
</call>
</service>
<service id="console.command.config_debug" class="Symfony\Bundle\FrameworkBundle\Command\ConfigDebugCommand" public="false">
<tag name="console.command" command="debug:config"/>
<call method="setName">
<argument>debug:config</argument>
</call>
</service>
<service id="console.command.config_dump_reference" class="Symfony\Bundle\FrameworkBundle\Command\ConfigDumpReferenceCommand" public="false">
<tag name="console.command" command="config:dump-reference"/>
<call method="setName">
<argument>config:dump-reference</argument>
</call>
</service>
<service id="console.command.container_debug" class="Symfony\Bundle\FrameworkBundle\Command\ContainerDebugCommand" public="false">
<tag name="console.command" command="debug:container"/>
<call method="setName">
<argument>debug:container</argument>
</call>
</service>
<service id="console.command.debug_autowiring" class="Symfony\Bundle\FrameworkBundle\Command\DebugAutowiringCommand" public="false">
<tag name="console.command" command="debug:autowiring"/>
<call method="setName">
<argument>debug:autowiring</argument>
</call>
</service>
<service id="console.command.event_dispatcher_debug" class="Symfony\Bundle\FrameworkBundle\Command\EventDispatcherDebugCommand" public="false">
<tag name="console.command" command="debug:event-dispatcher"/>
<argument type="service" id="event_dispatcher"/>
<call method="setName">
<argument>debug:event-dispatcher</argument>
</call>
</service>
<service id="console.command.router_debug" class="Symfony\Bundle\FrameworkBundle\Command\RouterDebugCommand" public="false">
<tag name="console.command" command="debug:router"/>
<argument type="service" id="router.default"/>
<call method="setName">
<argument>debug:router</argument>
</call>
</service>
<service id="console.command.router_match" class="Symfony\Bundle\FrameworkBundle\Command\RouterMatchCommand" public="false">
<tag name="console.command" command="router:match"/>
<argument type="service" id="router.default"/>
<call method="setName">
<argument>router:match</argument>
</call>
</service>
<service id="console.command.yaml_lint" class="Symfony\Bundle\FrameworkBundle\Command\YamlLintCommand" public="false">
<tag name="console.command" command="lint:yaml"/>
<call method="setName">
<argument>lint:yaml</argument>
</call>
</service>
<service id="cache.app" class="Symfony\Component\Cache\Adapter\FilesystemAdapter" public="true">
<tag name="cache.pool"/>
<argument>l2WGSBZAlu</argument>
<argument>0</argument>
<argument>/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/var/cache/dev/pools</argument>
<call method="setLogger">
<argument type="service" id="logger" on-invalid="ignore"/>
</call>
</service>
<service id="cache.app.simple" class="Symfony\Component\Cache\Simple\Psr6Cache" public="false">
<argument type="service" id="cache.app"/>
</service>
<service id="cache.system" class="Symfony\Component\Cache\Adapter\AdapterInterface" public="true">
<tag name="cache.pool"/>
<argument>UGP9+Vscxx</argument>
<argument>0</argument>
<argument>%container.build_id%</argument>
<argument>/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/var/cache/dev/pools</argument>
<argument type="service" id="logger" on-invalid="ignore"/>
<factory class="Symfony\Component\Cache\Adapter\AbstractAdapter" method="createSystemCache"/>
</service>
<service id="cache.validator" class="Symfony\Component\Cache\Adapter\AdapterInterface" public="false">
<tag name="cache.pool"/>
<argument>Fhi2oyVX0s</argument>
<argument>0</argument>
<argument>%container.build_id%</argument>
<argument>/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/var/cache/dev/pools</argument>
<argument type="service" id="logger" on-invalid="ignore"/>
<factory class="Symfony\Component\Cache\Adapter\AbstractAdapter" method="createSystemCache"/>
</service>
<service id="cache.serializer" class="Symfony\Component\Cache\Adapter\AdapterInterface" public="false">
<tag name="cache.pool"/>
<argument>oQCa-mwIRh</argument>
<argument>0</argument>
<argument>%container.build_id%</argument>
<argument>/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/var/cache/dev/pools</argument>
<argument type="service" id="logger" on-invalid="ignore"/>
<factory class="Symfony\Component\Cache\Adapter\AbstractAdapter" method="createSystemCache"/>
</service>
<service id="cache.annotations" class="Symfony\Component\Cache\Adapter\AdapterInterface" public="false">
<tag name="cache.pool"/>
<argument>qR0bSrclhY</argument>
<argument>0</argument>
<argument>%container.build_id%</argument>
<argument>/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/var/cache/dev/pools</argument>
<argument type="service" id="logger" on-invalid="ignore"/>
<factory class="Symfony\Component\Cache\Adapter\AbstractAdapter" method="createSystemCache"/>
</service>
<service id="cache.adapter.system" class="Symfony\Component\Cache\Adapter\AdapterInterface" public="false" abstract="true">
<tag name="cache.pool" clearer="cache.system_clearer"/>
<tag name="monolog.logger" channel="cache"/>
<argument></argument>
<argument>0</argument>
<argument>%container.build_id%</argument>
<argument>/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/var/cache/dev/pools</argument>
<argument type="service" id="logger" on-invalid="ignore"/>
<factory class="Symfony\Component\Cache\Adapter\AbstractAdapter" method="createSystemCache"/>
</service>
<service id="cache.adapter.apcu" class="Symfony\Component\Cache\Adapter\ApcuAdapter" public="false" abstract="true">
<tag name="cache.pool" clearer="cache.default_clearer"/>
<tag name="monolog.logger" channel="cache"/>
<argument></argument>
<argument>0</argument>
<argument>%container.build_id%</argument>
<call method="setLogger">
<argument type="service" id="logger" on-invalid="ignore"/>
</call>
</service>
<service id="cache.adapter.doctrine" class="Symfony\Component\Cache\Adapter\DoctrineAdapter" public="false" abstract="true">
<tag name="cache.pool" provider="cache.default_doctrine_provider" clearer="cache.default_clearer"/>
<tag name="monolog.logger" channel="cache"/>
<argument></argument>
<argument></argument>
<argument>0</argument>
<call method="setLogger">
<argument type="service" id="logger" on-invalid="ignore"/>
</call>
</service>
<service id="cache.adapter.filesystem" class="Symfony\Component\Cache\Adapter\FilesystemAdapter" public="false" abstract="true">
<tag name="cache.pool" clearer="cache.default_clearer"/>
<tag name="monolog.logger" channel="cache"/>
<argument></argument>
<argument>0</argument>
<argument>/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/var/cache/dev/pools</argument>
<call method="setLogger">
<argument type="service" id="logger" on-invalid="ignore"/>
</call>
</service>
<service id="cache.adapter.psr6" class="Symfony\Component\Cache\Adapter\ProxyAdapter" public="false" abstract="true">
<tag name="cache.pool" provider="cache.default_psr6_provider" clearer="cache.default_clearer"/>
<argument></argument>
<argument></argument>
<argument>0</argument>
</service>
<service id="cache.adapter.redis" class="Symfony\Component\Cache\Adapter\RedisAdapter" public="false" abstract="true">
<tag name="cache.pool" provider="cache.default_redis_provider" clearer="cache.default_clearer"/>
<tag name="monolog.logger" channel="cache"/>
<argument></argument>
<argument></argument>
<argument>0</argument>
<call method="setLogger">
<argument type="service" id="logger" on-invalid="ignore"/>
</call>
</service>
<service id="cache.adapter.memcached" class="Symfony\Component\Cache\Adapter\MemcachedAdapter" public="false" abstract="true">
<tag name="cache.pool" provider="cache.default_memcached_provider" clearer="cache.default_clearer" reset="reset"/>
<tag name="monolog.logger" channel="cache"/>
<argument></argument>
<argument></argument>
<argument>0</argument>
<call method="setLogger">
<argument type="service" id="logger" on-invalid="ignore"/>
</call>
</service>
<service id="cache.adapter.array" class="Symfony\Component\Cache\Adapter\ArrayAdapter" public="false" abstract="true">
<tag name="cache.pool" clearer="cache.default_clearer"/>
<tag name="monolog.logger" channel="cache"/>
<argument>0</argument>
<call method="setLogger">
<argument type="service" id="logger" on-invalid="ignore"/>
</call>
</service>
<service id="cache.default_clearer" class="Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer" public="false">
<tag name="cache.pool.clearer"/>
<argument type="collection">
<argument key="cache.app" type="service" id="cache.app" on-invalid="ignore_uninitialized"/>
</argument>
</service>
<service id="cache.system_clearer" class="Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer" public="true">
<tag name="cache.pool.clearer"/>
<tag name="kernel.cache_clearer"/>
<argument type="collection">
<argument key="cache.system" type="service" id="cache.system" on-invalid="ignore_uninitialized"/>
<argument key="cache.validator" type="service" id="cache.validator" on-invalid="ignore_uninitialized"/>
<argument key="cache.serializer" type="service" id="cache.serializer" on-invalid="ignore_uninitialized"/>
<argument key="cache.annotations" type="service" id="cache.annotations" on-invalid="ignore_uninitialized"/>
</argument>
</service>
<service id="cache.global_clearer" class="Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer" public="true">
<tag name="cache.pool.clearer"/>
<argument type="collection">
<argument key="cache.app" type="service" id="cache.app" on-invalid="ignore_uninitialized"/>
<argument key="cache.system" type="service" id="cache.system" on-invalid="ignore_uninitialized"/>
<argument key="cache.validator" type="service" id="cache.validator" on-invalid="ignore_uninitialized"/>
<argument key="cache.serializer" type="service" id="cache.serializer" on-invalid="ignore_uninitialized"/>
<argument key="cache.annotations" type="service" id="cache.annotations" on-invalid="ignore_uninitialized"/>
</argument>
</service>
<service id=".2_ServiceLocator~ekBW_9l" class="Symfony\Component\DependencyInjection\ServiceLocator" public="false">
<tag name="container.service_locator"/>
<argument type="collection">
<argument key="initialized_session" type="service" id="session" on-invalid="ignore_uninitialized"/>
<argument key="session" type="service" id="session" on-invalid="ignore"/>
</argument>
</service>
<service id=".1_NativeFileSessionHandler~ekBW_9l" class="Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler" public="false">
<argument>/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/var/cache/dev/sessions</argument>
</service>
<service id="session" class="Symfony\Component\HttpFoundation\Session\Session" public="true">
<argument type="service" id="session.storage.native"/>
<argument type="service" id="session.attribute_bag"/>
<argument type="service" id="session.flash_bag"/>
</service>
<service id="session.storage.metadata_bag" class="Symfony\Component\HttpFoundation\Session\Storage\MetadataBag" public="false">
<argument>_sf2_meta</argument>
<argument>0</argument>
</service>
<service id="session.storage.native" class="Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage" public="false">
<argument>%session.storage.options%</argument>
<argument>null</argument>
<argument type="service" id="session.storage.metadata_bag"/>
</service>
<service id="session.storage.php_bridge" class="Symfony\Component\HttpFoundation\Session\Storage\PhpBridgeSessionStorage" public="false">
<argument>null</argument>
<argument type="service" id="session.storage.metadata_bag"/>
</service>
<service id="session.flash_bag" class="Symfony\Component\HttpFoundation\Session\Flash\FlashBag" public="false"/>
<service id="session.attribute_bag" class="Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag" public="false"/>
<service id="session.storage.mock_file" class="Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage" public="false">
<argument>/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/var/cache/dev/sessions</argument>
<argument>MOCKSESSID</argument>
<argument type="service" id="session.storage.metadata_bag"/>
</service>
<service id="session.handler.native_file" class="Symfony\Component\HttpFoundation\Session\Storage\Handler\StrictSessionHandler" public="false">
<argument type="service" id=".1_NativeFileSessionHandler~ekBW_9l"/>
</service>
<service id="session_listener" class="Symfony\Component\HttpKernel\EventListener\SessionListener" public="false">
<tag name="kernel.event_subscriber"/>
<tag name="container.hot_path"/>
<tag name="container.hot_path"/>
<tag name="container.hot_path"/>
<argument type="service" id=".2_ServiceLocator~ekBW_9l"/>
</service>
<service id="session.save_listener" class="Symfony\Component\HttpKernel\EventListener\SaveSessionListener" public="false">
<deprecated>The "%service_id%" service is deprecated since Symfony 4.1. Use the "session_listener" service instead.</deprecated>
</service>
<service id=".cache_connection.GD_MSZC" class="Symfony\Component\Cache\Adapter\AbstractAdapter" public="false">
<argument>redis://localhost</argument>
<argument type="collection">
<argument key="lazy">true</argument>
</argument>
<factory class="Symfony\Component\Cache\Adapter\AbstractAdapter" method="createConnection"/>
</service>
<service id=".cache_connection.JKE6keX" class="Symfony\Component\Cache\Adapter\AbstractAdapter" public="false">
<argument>memcached://localhost</argument>
<argument type="collection">
<argument key="lazy">true</argument>
</argument>
<factory class="Symfony\Component\Cache\Adapter\AbstractAdapter" method="createConnection"/>
</service>
<service id="debug.debug_handlers_listener" class="Symfony\Component\HttpKernel\EventListener\DebugHandlersListener" public="false">
<tag name="kernel.event_subscriber"/>
<tag name="monolog.logger" channel="php"/>
<tag name="container.hot_path"/>
<argument>null</argument>
<argument type="service" id="logger" on-invalid="null"/>
<argument>null</argument>
<argument>-1</argument>
<argument>true</argument>
<argument type="service" id="debug.file_link_formatter"/>
<argument>true</argument>
</service>
<service id="debug.file_link_formatter" class="Symfony\Component\HttpKernel\Debug\FileLinkFormatter" public="false">
<argument>null</argument>
</service>
<service id="routing.resolver" class="Symfony\Component\Config\Loader\LoaderResolver" public="false">
<call method="addLoader">
<argument type="service" id="routing.loader.xml"/>
</call>
<call method="addLoader">
<argument type="service" id="routing.loader.yml"/>
</call>
<call method="addLoader">
<argument type="service" id="routing.loader.php"/>
</call>
<call method="addLoader">
<argument type="service" id="routing.loader.glob"/>
</call>
<call method="addLoader">
<argument type="service" id="routing.loader.directory"/>
</call>
<call method="addLoader">
<argument type="service" id="routing.loader.service"/>
</call>
</service>
<service id="routing.loader.xml" class="Symfony\Component\Routing\Loader\XmlFileLoader" public="false">
<tag name="routing.loader"/>
<argument type="service" id="file_locator"/>
</service>
<service id="routing.loader.yml" class="Symfony\Component\Routing\Loader\YamlFileLoader" public="false">
<tag name="routing.loader"/>
<argument type="service" id="file_locator"/>
</service>
<service id="routing.loader.php" class="Symfony\Component\Routing\Loader\PhpFileLoader" public="false">
<tag name="routing.loader"/>
<argument type="service" id="file_locator"/>
</service>
<service id="routing.loader.glob" class="Symfony\Component\Routing\Loader\GlobFileLoader" public="false">
<tag name="routing.loader"/>
<argument type="service" id="file_locator"/>
</service>
<service id="routing.loader.directory" class="Symfony\Component\Routing\Loader\DirectoryLoader" public="false">
<tag name="routing.loader"/>
<argument type="service" id="file_locator"/>
</service>
<service id="routing.loader.service" class="Symfony\Component\Routing\Loader\DependencyInjection\ServiceRouterLoader" public="false">
<tag name="routing.loader"/>
<argument type="service" id="service_container"/>
</service>
<service id="routing.loader" class="Symfony\Bundle\FrameworkBundle\Routing\DelegatingLoader" public="true">
<argument type="service" id="controller_name_converter"/>
<argument type="service" id="routing.resolver"/>
</service>
<service id="router.default" class="Symfony\Bundle\FrameworkBundle\Routing\Router" public="false">
<tag name="monolog.logger" channel="router"/>
<tag name="container.service_subscriber" id="routing.loader"/>
<argument type="service" id=".service_locator.oNnsU_h.router.default"/>
<argument>kernel::loadRoutes</argument>
<argument type="collection">
<argument key="cache_dir">/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/var/cache/dev</argument>
<argument key="debug">true</argument>
<argument key="generator_class">Symfony\Component\Routing\Generator\UrlGenerator</argument>
<argument key="generator_base_class">Symfony\Component\Routing\Generator\UrlGenerator</argument>
<argument key="generator_dumper_class">Symfony\Component\Routing\Generator\Dumper\PhpGeneratorDumper</argument>
<argument key="generator_cache_class">srcDevDebugProjectContainerUrlGenerator</argument>
<argument key="matcher_class">Symfony\Bundle\FrameworkBundle\Routing\RedirectableUrlMatcher</argument>
<argument key="matcher_base_class">Symfony\Bundle\FrameworkBundle\Routing\RedirectableUrlMatcher</argument>
<argument key="matcher_dumper_class">Symfony\Component\Routing\Matcher\Dumper\PhpMatcherDumper</argument>
<argument key="matcher_cache_class">srcDevDebugProjectContainerUrlMatcher</argument>
<argument key="strict_requirements">true</argument>
<argument key="resource_type">service</argument>
</argument>
<argument type="service" id="router.request_context" on-invalid="ignore"/>
<argument type="service" id="parameter_bag" on-invalid="ignore"/>
<argument type="service" id="logger" on-invalid="ignore"/>
<call method="setConfigCacheFactory">
<argument type="service" id="config_cache_factory"/>
</call>
</service>
<service id="router.request_context" class="Symfony\Component\Routing\RequestContext" public="false">
<argument></argument>
<argument>GET</argument>
<argument>localhost</argument>
<argument>http</argument>
<argument>80</argument>
<argument>443</argument>
</service>
<service id="router.cache_warmer" class="Symfony\Bundle\FrameworkBundle\CacheWarmer\RouterCacheWarmer" public="false">
<tag name="container.service_subscriber" id="router"/>
<tag name="kernel.cache_warmer"/>
<argument type="service" id=".service_locator.tdKlFgs.router.cache_warmer"/>
</service>
<service id="router_listener" class="Symfony\Component\HttpKernel\EventListener\RouterListener" public="false">
<tag name="kernel.event_subscriber"/>
<tag name="monolog.logger" channel="request"/>
<tag name="container.hot_path"/>
<tag name="container.hot_path"/>
<argument type="service" id="router.default"/>
<argument type="service" id="request_stack"/>
<argument type="service" id="router.request_context" on-invalid="ignore"/>
<argument type="service" id="logger" on-invalid="ignore"/>
<argument>/Users/Dirollo/Documents/Mes sites/BoucherieDirollo</argument>
<argument>true</argument>
</service>
<service id="Symfony\Bundle\FrameworkBundle\Controller\RedirectController" class="Symfony\Bundle\FrameworkBundle\Controller\RedirectController" public="true">
<argument type="service" id="router.default"/>
<argument>80</argument>
<argument>443</argument>
</service>
<service id="Symfony\Bundle\FrameworkBundle\Controller\TemplateController" class="Symfony\Bundle\FrameworkBundle\Controller\TemplateController" public="true">
<argument>null</argument>
<argument>null</argument>
</service>
<service id=".service_locator.9_yeNH1" class="Symfony\Component\DependencyInjection\ServiceLocator" public="false">
<tag name="container.service_locator"/>
<argument type="collection"/>
</service>
<service id=".service_locator.gmwRZ3h" class="Symfony\Component\DependencyInjection\ServiceLocator" public="false">
<tag name="container.service_locator"/>
<argument type="collection">
<argument key="inline" type="service" id="fragment.renderer.inline"/>
</argument>
</service>
<service id="logger" class="Symfony\Component\HttpKernel\Log\Logger" public="false"/>
<service id=".service_locator.oNnsU_h" class="Symfony\Component\DependencyInjection\ServiceLocator" public="false">
<tag name="container.service_locator"/>
<argument type="collection">
<argument key="routing.loader" type="service" id="routing.loader"/>
</argument>
</service>
<service id=".service_locator.oNnsU_h.router.default" class="Symfony\Component\DependencyInjection\ServiceLocator" public="false">
<argument>router.default</argument>
<argument type="service" id="service_container"/>
<factory service=".service_locator.oNnsU_h" method="withContext"/>
</service>
<service id=".service_locator.tdKlFgs" class="Symfony\Component\DependencyInjection\ServiceLocator" public="false">
<tag name="container.service_locator"/>
<argument type="collection">
<argument key="router" type="service" id="router.default"/>
</argument>
</service>
<service id=".service_locator.tdKlFgs.router.cache_warmer" class="Symfony\Component\DependencyInjection\ServiceLocator" public="false">
<argument>router.cache_warmer</argument>
<argument type="service" id="service_container"/>
<factory service=".service_locator.tdKlFgs" method="withContext"/>
</service>
<service id="console.command_loader" class="Symfony\Component\Console\CommandLoader\ContainerCommandLoader" public="true">
<argument type="service" id=".service_locator.K2fdwAZ"/>
<argument type="collection">
<argument key="about">console.command.about</argument>
<argument key="assets:install">console.command.assets_install</argument>
<argument key="cache:clear">console.command.cache_clear</argument>
<argument key="cache:pool:clear">console.command.cache_pool_clear</argument>
<argument key="cache:pool:prune">console.command.cache_pool_prune</argument>
<argument key="cache:pool:delete">console.command.cache_pool_delete</argument>
<argument key="cache:warmup">console.command.cache_warmup</argument>
<argument key="debug:config">console.command.config_debug</argument>
<argument key="config:dump-reference">console.command.config_dump_reference</argument>
<argument key="debug:container">console.command.container_debug</argument>
<argument key="debug:autowiring">console.command.debug_autowiring</argument>
<argument key="debug:event-dispatcher">console.command.event_dispatcher_debug</argument>
<argument key="debug:router">console.command.router_debug</argument>
<argument key="router:match">console.command.router_match</argument>
<argument key="lint:yaml">console.command.yaml_lint</argument>
</argument>
</service>
<service id=".service_locator.K2fdwAZ" class="Symfony\Component\DependencyInjection\ServiceLocator" public="false">
<tag name="container.service_locator"/>
<argument type="collection">
<argument key="console.command.about" type="service" id="console.command.about"/>
<argument key="console.command.assets_install" type="service" id="console.command.assets_install"/>
<argument key="console.command.cache_clear" type="service" id="console.command.cache_clear"/>
<argument key="console.command.cache_pool_clear" type="service" id="console.command.cache_pool_clear"/>
<argument key="console.command.cache_pool_delete" type="service" id="console.command.cache_pool_delete"/>
<argument key="console.command.cache_pool_prune" type="service" id="console.command.cache_pool_prune"/>
<argument key="console.command.cache_warmup" type="service" id="console.command.cache_warmup"/>
<argument key="console.command.config_debug" type="service" id="console.command.config_debug"/>
<argument key="console.command.config_dump_reference" type="service" id="console.command.config_dump_reference"/>
<argument key="console.command.container_debug" type="service" id="console.command.container_debug"/>
<argument key="console.command.debug_autowiring" type="service" id="console.command.debug_autowiring"/>
<argument key="console.command.event_dispatcher_debug" type="service" id="console.command.event_dispatcher_debug"/>
<argument key="console.command.router_debug" type="service" id="console.command.router_debug"/>
<argument key="console.command.router_match" type="service" id="console.command.router_match"/>
<argument key="console.command.yaml_lint" type="service" id="console.command.yaml_lint"/>
</argument>
</service>
<service id="Psr\Container\ContainerInterface" alias="service_container" public="false"/>
<service id="Symfony\Component\DependencyInjection\ContainerInterface" alias="service_container" public="false"/>
<service id="Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface" alias="parameter_bag" public="false"/>
<service id="Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface" alias="parameter_bag" public="false"/>
<service id="Symfony\Component\EventDispatcher\EventDispatcherInterface" alias="event_dispatcher" public="false"/>
<service id="Symfony\Component\HttpKernel\HttpKernelInterface" alias="http_kernel" public="false"/>
<service id="Symfony\Component\HttpFoundation\RequestStack" alias="request_stack" public="false"/>
<service id="Symfony\Component\HttpKernel\KernelInterface" alias="kernel" public="false"/>
<service id="Symfony\Component\Filesystem\Filesystem" alias="filesystem" public="false"/>
<service id="Symfony\Component\HttpKernel\Config\FileLocator" alias="file_locator" public="false"/>
<service id="cache.app_clearer" alias="cache.default_clearer" public="true"/>
<service id="Psr\Cache\CacheItemPoolInterface" alias="cache.app" public="false"/>
<service id="Psr\SimpleCache\CacheInterface" alias="cache.app.simple" public="false"/>
<service id="Symfony\Component\Cache\Adapter\AdapterInterface" alias="cache.app" public="false"/>
<service id="Symfony\Component\HttpFoundation\Session\SessionInterface" alias="session" public="false"/>
<service id="Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface" alias="session.storage.native" public="false"/>
<service id="SessionHandlerInterface" alias="session.handler" public="false"/>
<service id="Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface" alias="session.flash_bag" public="false"/>
<service id="session.storage.filesystem" alias="session.storage.mock_file" public="false"/>
<service id="session.storage" alias="session.storage.native"/>
<service id="cache.default_redis_provider" alias=".cache_connection.GD_MSZC" public="false"/>
<service id="cache.default_memcached_provider" alias=".cache_connection.JKE6keX" public="false"/>
<service id="Symfony\Component\HttpKernel\Debug\FileLinkFormatter" alias="debug.file_link_formatter" public="false"/>
<service id="router" alias="router.default" public="true"/>
<service id="Symfony\Component\Routing\RouterInterface" alias="router.default" public="false"/>
<service id="Symfony\Component\Routing\Generator\UrlGeneratorInterface" alias="router.default" public="false"/>
<service id="Symfony\Component\Routing\Matcher\UrlMatcherInterface" alias="router.default" public="false"/>
<service id="Symfony\Component\Routing\RequestContextAwareInterface" alias="router.default" public="false"/>
<service id="Symfony\Component\Routing\RequestContext" alias="router.request_context" public="false"/>
<service id="argument_resolver.controller_locator" alias=".service_locator.9_yeNH1"/>
<service id="Psr\Log\LoggerInterface" alias="logger" public="false"/>
<service id=".service_locator.AoifO_3" alias=".2_ServiceLocator~ekBW_9l" public="false"/>
</services>
</container>
a:24:{i:0;C:50:"Symfony\Component\Config\Resource\ComposerResource":85:{a:1:{s:58:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/vendor";i:1539265518;}}i:1;C:46:"Symfony\Component\Config\Resource\FileResource":74:{s:66:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/src/Kernel.php";}i:2;C:56:"Symfony\Component\Config\Resource\ClassExistenceResource":101:{a:2:{i:0;s:75:"Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass";i:1;b:0;}}i:3;C:56:"Symfony\Component\Config\Resource\ClassExistenceResource":102:{a:2:{i:0;s:76:"Symfony\Component\Validator\DependencyInjection\AddValidatorInitializersPass";i:1;b:0;}}i:4;C:56:"Symfony\Component\Config\Resource\ClassExistenceResource":93:{a:2:{i:0;s:67:"Symfony\Component\Console\DependencyInjection\AddConsoleCommandPass";i:1;b:1;}}i:5;C:56:"Symfony\Component\Config\Resource\ClassExistenceResource":90:{a:2:{i:0;s:64:"Symfony\Component\Translation\DependencyInjection\TranslatorPass";i:1;b:0;}}i:6;C:56:"Symfony\Component\Config\Resource\ClassExistenceResource":100:{a:2:{i:0;s:74:"Symfony\Component\Translation\DependencyInjection\TranslationExtractorPass";i:1;b:0;}}i:7;C:56:"Symfony\Component\Config\Resource\ClassExistenceResource":97:{a:2:{i:0;s:71:"Symfony\Component\Translation\DependencyInjection\TranslationDumperPass";i:1;b:0;}}i:8;C:56:"Symfony\Component\Config\Resource\ClassExistenceResource":89:{a:2:{i:0;s:63:"Symfony\Component\Serializer\DependencyInjection\SerializerPass";i:1;b:0;}}i:9;C:56:"Symfony\Component\Config\Resource\ClassExistenceResource":93:{a:2:{i:0;s:67:"Symfony\Component\PropertyInfo\DependencyInjection\PropertyInfoPass";i:1;b:0;}}i:10;C:56:"Symfony\Component\Config\Resource\ClassExistenceResource":94:{a:2:{i:0;s:68:"Symfony\Component\Workflow\DependencyInjection\ValidateWorkflowsPass";i:1;b:0;}}i:11;C:56:"Symfony\Component\Config\Resource\ClassExistenceResource":77:{a:2:{i:0;s:51:"Symfony\Component\Form\DependencyInjection\FormPass";i:1;b:0;}}i:12;C:56:"Symfony\Component\Config\Resource\ClassExistenceResource":87:{a:2:{i:0;s:61:"Symfony\Component\Messenger\DependencyInjection\MessengerPass";i:1;b:0;}}i:13;C:46:"Symfony\Component\Config\Resource\FileResource":78:{s:70:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config/bundles.php";}i:14;C:46:"Symfony\Component\Config\Resource\FileResource":90:{s:82:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config/packages/framework.yaml";}i:15;C:46:"Symfony\Component\Config\Resource\FileResource":88:{s:80:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config/packages/routing.yaml";}i:16;C:46:"Symfony\Component\Config\Resource\GlobResource":172:{a:4:{i:0;s:58:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config";i:1;s:32:"/{packages}/*.{php,xml,yaml,yml}";i:2;b:0;i:3;s:32:"a8d995a7279cfc07b653158126a01f26";}}i:17;C:46:"Symfony\Component\Config\Resource\FileResource":92:{s:84:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config/packages/dev/routing.yaml";}i:18;C:46:"Symfony\Component\Config\Resource\GlobResource":179:{a:4:{i:0;s:58:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config";i:1;s:39:"/{packages}/dev/**/*.{php,xml,yaml,yml}";i:2;b:0;i:3;s:32:"15daf4edc0bebc1017b9325f9a877ac3";}}i:19;C:46:"Symfony\Component\Config\Resource\FileResource":80:{s:72:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config/services.yaml";}i:20;C:46:"Symfony\Component\Config\Resource\GlobResource":138:{a:4:{i:0;s:55:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/src";i:1;s:2:"/*";i:2;b:1;i:3;s:32:"36332e941bc1ae7d87a6402c0e2183a5";}}i:21;C:46:"Symfony\Component\Config\Resource\GlobResource":147:{a:4:{i:0;s:66:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/src/Controller";i:1;s:0:"";i:2;b:1;i:3;s:32:"d41d8cd98f00b204e9800998ecf8427e";}}i:22;C:46:"Symfony\Component\Config\Resource\GlobResource":170:{a:4:{i:0;s:58:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config";i:1;s:30:"/{services}.{php,xml,yaml,yml}";i:2;b:0;i:3;s:32:"4eabcae6004b265945ad7e334b257934";}}i:23;C:46:"Symfony\Component\Config\Resource\GlobResource":174:{a:4:{i:0;s:58:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config";i:1;s:34:"/{services}_dev.{php,xml,yaml,yml}";i:2;b:0;i:3;s:32:"d41d8cd98f00b204e9800998ecf8427e";}}}
Symfony\Component\DependencyInjection\Compiler\ResolveChildDefinitionsPass: Resolving inheritance for "cache.app" (parent: cache.adapter.filesystem).
Symfony\Component\DependencyInjection\Compiler\ResolveChildDefinitionsPass: Resolving inheritance for "cache.system" (parent: cache.adapter.system).
Symfony\Component\DependencyInjection\Compiler\ResolveChildDefinitionsPass: Resolving inheritance for "cache.validator" (parent: cache.system).
Symfony\Component\DependencyInjection\Compiler\ResolveChildDefinitionsPass: Resolving inheritance for "cache.serializer" (parent: cache.system).
Symfony\Component\DependencyInjection\Compiler\ResolveChildDefinitionsPass: Resolving inheritance for "cache.annotations" (parent: cache.system).
Symfony\Component\DependencyInjection\Compiler\ResolveChildDefinitionsPass: Resolving inheritance for "cache.system_clearer" (parent: cache.default_clearer).
Symfony\Component\DependencyInjection\Compiler\ResolveChildDefinitionsPass: Resolving inheritance for "cache.global_clearer" (parent: cache.default_clearer).
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Psr\Container\ContainerInterface"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Symfony\Component\DependencyInjection\ContainerInterface"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Symfony\Component\EventDispatcher\EventDispatcherInterface"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Symfony\Component\HttpKernel\HttpKernelInterface"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Symfony\Component\HttpFoundation\RequestStack"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Symfony\Component\HttpKernel\KernelInterface"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Symfony\Component\Filesystem\Filesystem"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Symfony\Component\HttpKernel\Config\FileLocator"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Psr\Cache\CacheItemPoolInterface"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Psr\SimpleCache\CacheInterface"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Symfony\Component\Cache\Adapter\AdapterInterface"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Symfony\Component\HttpFoundation\Session\SessionInterface"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "SessionHandlerInterface"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "session.storage.filesystem"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "session.storage"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "cache.default_redis_provider"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "cache.default_memcached_provider"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Symfony\Component\HttpKernel\Debug\FileLinkFormatter"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Symfony\Component\Routing\RouterInterface"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Symfony\Component\Routing\Generator\UrlGeneratorInterface"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Symfony\Component\Routing\Matcher\UrlMatcherInterface"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Symfony\Component\Routing\RequestContextAwareInterface"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Symfony\Component\Routing\RequestContext"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "argument_resolver.controller_locator"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Psr\Log\LoggerInterface"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service ".service_locator.AoifO_3"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\ReplaceAliasByActualDefinitionPass: Changed reference of service "locale_listener" previously pointing to "router.default" to "router".
Symfony\Component\DependencyInjection\Compiler\ReplaceAliasByActualDefinitionPass: Changed reference of service "console.command.router_debug" previously pointing to "router.default" to "router".
Symfony\Component\DependencyInjection\Compiler\ReplaceAliasByActualDefinitionPass: Changed reference of service "console.command.router_match" previously pointing to "router.default" to "router".
Symfony\Component\DependencyInjection\Compiler\ReplaceAliasByActualDefinitionPass: Changed reference of service "router_listener" previously pointing to "router.default" to "router".
Symfony\Component\DependencyInjection\Compiler\ReplaceAliasByActualDefinitionPass: Changed reference of service "Symfony\Bundle\FrameworkBundle\Controller\RedirectController" previously pointing to "router.default" to "router".
Symfony\Component\DependencyInjection\Compiler\ReplaceAliasByActualDefinitionPass: Changed reference of service ".service_locator.tdKlFgs" previously pointing to "router.default" to "router".
Symfony\Component\DependencyInjection\Compiler\RemoveAbstractDefinitionsPass: Removed service "cache.adapter.system"; reason: abstract.
Symfony\Component\DependencyInjection\Compiler\RemoveAbstractDefinitionsPass: Removed service "cache.adapter.apcu"; reason: abstract.
Symfony\Component\DependencyInjection\Compiler\RemoveAbstractDefinitionsPass: Removed service "cache.adapter.doctrine"; reason: abstract.
Symfony\Component\DependencyInjection\Compiler\RemoveAbstractDefinitionsPass: Removed service "cache.adapter.filesystem"; reason: abstract.
Symfony\Component\DependencyInjection\Compiler\RemoveAbstractDefinitionsPass: Removed service "cache.adapter.psr6"; reason: abstract.
Symfony\Component\DependencyInjection\Compiler\RemoveAbstractDefinitionsPass: Removed service "cache.adapter.redis"; reason: abstract.
Symfony\Component\DependencyInjection\Compiler\RemoveAbstractDefinitionsPass: Removed service "cache.adapter.memcached"; reason: abstract.
Symfony\Component\DependencyInjection\Compiler\RemoveAbstractDefinitionsPass: Removed service "cache.adapter.array"; reason: abstract.
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "argument_metadata_factory" to "argument_resolver".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service ".service_locator.9_yeNH1" to "argument_resolver.service".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "controller_resolver" to "http_kernel".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "argument_resolver" to "http_kernel".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service ".service_locator.gmwRZ3h" to "fragment.handler".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "session.storage.native" to "session".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "session.attribute_bag" to "session".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "session.flash_bag" to "session".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service ".1_NativeFileSessionHandler~ekBW_9l" to "session.handler.native_file".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service ".2_ServiceLocator~ekBW_9l" to "session_listener".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "debug.file_link_formatter" to "debug.debug_handlers_listener".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "routing.loader.xml" to "routing.resolver".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "routing.loader.yml" to "routing.resolver".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "routing.loader.php" to "routing.resolver".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "routing.loader.glob" to "routing.resolver".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "routing.loader.directory" to "routing.resolver".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "routing.loader.service" to "routing.resolver".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "routing.resolver" to "routing.loader".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service ".service_locator.tdKlFgs.router.cache_warmer" to "router.cache_warmer".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service ".service_locator.oNnsU_h" to ".service_locator.oNnsU_h.router.default".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service ".service_locator.tdKlFgs" to ".service_locator.tdKlFgs.router.cache_warmer".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service ".service_locator.K2fdwAZ" to "console.command_loader".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service ".service_locator.oNnsU_h.router.default" to "router".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "parameter_bag" to "router".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "config_cache_factory" to "router".
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "controller_resolver"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "argument_metadata_factory"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "argument_resolver"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "parameter_bag"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "uri_signer"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "config_cache_factory"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "fragment.handler"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "cache.app.simple"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "cache.validator"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "cache.serializer"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "cache.annotations"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service ".2_ServiceLocator~ekBW_9l"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service ".1_NativeFileSessionHandler~ekBW_9l"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "session.storage.native"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "session.storage.php_bridge"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "session.flash_bag"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "session.attribute_bag"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "session.storage.mock_file"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "session.handler.native_file"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "session.save_listener"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service ".cache_connection.GD_MSZC"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service ".cache_connection.JKE6keX"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "debug.file_link_formatter"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "routing.resolver"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "routing.loader.xml"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "routing.loader.yml"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "routing.loader.php"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "routing.loader.glob"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "routing.loader.directory"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "routing.loader.service"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service ".service_locator.9_yeNH1"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service ".service_locator.gmwRZ3h"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service ".service_locator.oNnsU_h"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service ".service_locator.oNnsU_h.router.default"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service ".service_locator.tdKlFgs"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service ".service_locator.tdKlFgs.router.cache_warmer"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service ".service_locator.K2fdwAZ"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "session.storage.metadata_bag" to "session".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "file_locator" to "routing.loader".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "file_locator" to "routing.loader".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "file_locator" to "routing.loader".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "file_locator" to "routing.loader".
Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "file_locator" to "routing.loader".
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "file_locator"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "fragment.renderer.inline"; reason: unused.
Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "session.storage.metadata_bag"; reason: unused.
<?php
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Exception\RouteNotFoundException;
use Psr\Log\LoggerInterface;
/**
* This class has been auto-generated
* by the Symfony Routing Component.
*/
class srcDevDebugProjectContainerUrlGenerator extends Symfony\Component\Routing\Generator\UrlGenerator
{
private static $declaredRoutes;
private $defaultLocale;
public function __construct(RequestContext $context, LoggerInterface $logger = null, string $defaultLocale = null)
{
$this->context = $context;
$this->logger = $logger;
$this->defaultLocale = $defaultLocale;
if (null === self::$declaredRoutes) {
self::$declaredRoutes = array(
);
}
}
public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)
{
$locale = $parameters['_locale']
?? $this->context->getParameter('_locale')
?: $this->defaultLocale;
if (null !== $locale && (self::$declaredRoutes[$name.'.'.$locale][1]['_canonical_route'] ?? null) === $name) {
unset($parameters['_locale']);
$name .= '.'.$locale;
} elseif (!isset(self::$declaredRoutes[$name])) {
throw new RouteNotFoundException(sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', $name));
}
list($variables, $defaults, $requirements, $tokens, $hostTokens, $requiredSchemes) = self::$declaredRoutes[$name];
return $this->doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostTokens, $requiredSchemes);
}
}
a:7:{i:0;C:46:"Symfony\Component\Config\Resource\GlobResource":170:{a:4:{i:0;s:58:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config";i:1;s:30:"/{routes}/*.{php,xml,yaml,yml}";i:2;b:0;i:3;s:32:"d41d8cd98f00b204e9800998ecf8427e";}}i:1;C:46:"Symfony\Component\Config\Resource\GlobResource":177:{a:4:{i:0;s:58:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config";i:1;s:37:"/{routes}/dev/**/*.{php,xml,yaml,yml}";i:2;b:0;i:3;s:32:"d41d8cd98f00b204e9800998ecf8427e";}}i:2;C:46:"Symfony\Component\Config\Resource\FileResource":78:{s:70:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config/routes.yaml";}i:3;C:46:"Symfony\Component\Config\Resource\GlobResource":168:{a:4:{i:0;s:58:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config";i:1;s:28:"/{routes}.{php,xml,yaml,yml}";i:2;b:0;i:3;s:32:"b7c72b6006adf2d39c266c4c56aad93f";}}i:4;C:46:"Symfony\Component\Config\Resource\FileResource":74:{s:66:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/src/Kernel.php";}i:5;C:46:"Symfony\Component\Config\Resource\FileResource":97:{s:89:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/vendor/symfony/http-kernel/Kernel.php";}i:6;C:72:"Symfony\Component\DependencyInjection\Config\ContainerParametersResource":6:{a:0:{}}}
<?php
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\Routing\RequestContext;
/**
* This class has been auto-generated
* by the Symfony Routing Component.
*/
class srcDevDebugProjectContainerUrlMatcher extends Symfony\Bundle\FrameworkBundle\Routing\RedirectableUrlMatcher
{
public function __construct(RequestContext $context)
{
$this->context = $context;
}
public function match($pathinfo)
{
$allow = $allowSchemes = array();
if ($ret = $this->doMatch($pathinfo, $allow, $allowSchemes)) {
return $ret;
}
if ($allow) {
throw new MethodNotAllowedException(array_keys($allow));
}
if (!in_array($this->context->getMethod(), array('HEAD', 'GET'), true)) {
// no-op
} elseif ($allowSchemes) {
redirect_scheme:
$scheme = $this->context->getScheme();
$this->context->setScheme(key($allowSchemes));
try {
if ($ret = $this->doMatch($pathinfo)) {
return $this->redirect($pathinfo, $ret['_route'], $this->context->getScheme()) + $ret;
}
} finally {
$this->context->setScheme($scheme);
}
} elseif ('/' !== $pathinfo) {
$pathinfo = '/' !== $pathinfo[-1] ? $pathinfo.'/' : substr($pathinfo, 0, -1);
if ($ret = $this->doMatch($pathinfo, $allow, $allowSchemes)) {
return $this->redirect($pathinfo, $ret['_route']) + $ret;
}
if ($allowSchemes) {
goto redirect_scheme;
}
}
throw new ResourceNotFoundException();
}
private function doMatch(string $rawPathinfo, array &$allow = array(), array &$allowSchemes = array()): ?array
{
$allow = $allowSchemes = array();
$pathinfo = rawurldecode($rawPathinfo);
$context = $this->context;
$requestMethod = $canonicalMethod = $context->getMethod();
if ('HEAD' === $requestMethod) {
$canonicalMethod = 'GET';
}
if ('/' === $pathinfo && !$allow && !$allowSchemes) {
throw new Symfony\Component\Routing\Exception\NoConfigurationException();
}
return null;
}
}
a:7:{i:0;C:46:"Symfony\Component\Config\Resource\GlobResource":170:{a:4:{i:0;s:58:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config";i:1;s:30:"/{routes}/*.{php,xml,yaml,yml}";i:2;b:0;i:3;s:32:"d41d8cd98f00b204e9800998ecf8427e";}}i:1;C:46:"Symfony\Component\Config\Resource\GlobResource":177:{a:4:{i:0;s:58:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config";i:1;s:37:"/{routes}/dev/**/*.{php,xml,yaml,yml}";i:2;b:0;i:3;s:32:"d41d8cd98f00b204e9800998ecf8427e";}}i:2;C:46:"Symfony\Component\Config\Resource\FileResource":78:{s:70:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config/routes.yaml";}i:3;C:46:"Symfony\Component\Config\Resource\GlobResource":168:{a:4:{i:0;s:58:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/config";i:1;s:28:"/{routes}.{php,xml,yaml,yml}";i:2;b:0;i:3;s:32:"b7c72b6006adf2d39c266c4c56aad93f";}}i:4;C:46:"Symfony\Component\Config\Resource\FileResource":74:{s:66:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/src/Kernel.php";}i:5;C:46:"Symfony\Component\Config\Resource\FileResource":97:{s:89:"/Users/Dirollo/Documents/Mes sites/BoucherieDirollo/vendor/symfony/http-kernel/Kernel.php";}i:6;C:72:"Symfony\Component\DependencyInjection\Config\ContainerParametersResource":6:{a:0:{}}}
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit9371e9bc0ff619285cd145dcf0b9e4dd::getLoader();
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
);
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
);
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
);
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
'Symfony\\Flex\\' => array($vendorDir . '/symfony/flex/src'),
'Symfony\\Component\\Yaml\\' => array($vendorDir . '/symfony/yaml'),
'Symfony\\Component\\Routing\\' => array($vendorDir . '/symfony/routing'),
'Symfony\\Component\\HttpKernel\\' => array($vendorDir . '/symfony/http-kernel'),
'Symfony\\Component\\HttpFoundation\\' => array($vendorDir . '/symfony/http-foundation'),
'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'),
'Symfony\\Component\\Filesystem\\' => array($vendorDir . '/symfony/filesystem'),
'Symfony\\Component\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher'),
'Symfony\\Component\\Dotenv\\' => array($vendorDir . '/symfony/dotenv'),
'Symfony\\Component\\DependencyInjection\\' => array($vendorDir . '/symfony/dependency-injection'),
'Symfony\\Component\\Debug\\' => array($vendorDir . '/symfony/debug'),
'Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'),
'Symfony\\Component\\Config\\' => array($vendorDir . '/symfony/config'),
'Symfony\\Component\\Cache\\' => array($vendorDir . '/symfony/cache'),
'Symfony\\Bundle\\FrameworkBundle\\' => array($vendorDir . '/symfony/framework-bundle'),
'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'),
'App\\Tests\\' => array($baseDir . '/tests'),
'App\\' => array($baseDir . '/src'),
);
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit9371e9bc0ff619285cd145dcf0b9e4dd
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInit9371e9bc0ff619285cd145dcf0b9e4dd', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit9371e9bc0ff619285cd145dcf0b9e4dd', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit9371e9bc0ff619285cd145dcf0b9e4dd::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->register(true);
if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInit9371e9bc0ff619285cd145dcf0b9e4dd::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire9371e9bc0ff619285cd145dcf0b9e4dd($fileIdentifier, $file);
}
return $loader;
}
}
function composerRequire9371e9bc0ff619285cd145dcf0b9e4dd($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInit9371e9bc0ff619285cd145dcf0b9e4dd
{
public static $files = array (
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
);
public static $prefixLengthsPsr4 = array (
'S' =>
array (
'Symfony\\Polyfill\\Mbstring\\' => 26,
'Symfony\\Flex\\' => 13,
'Symfony\\Component\\Yaml\\' => 23,
'Symfony\\Component\\Routing\\' => 26,
'Symfony\\Component\\HttpKernel\\' => 29,
'Symfony\\Component\\HttpFoundation\\' => 33,
'Symfony\\Component\\Finder\\' => 25,
'Symfony\\Component\\Filesystem\\' => 29,
'Symfony\\Component\\EventDispatcher\\' => 34,
'Symfony\\Component\\Dotenv\\' => 25,
'Symfony\\Component\\DependencyInjection\\' => 38,
'Symfony\\Component\\Debug\\' => 24,
'Symfony\\Component\\Console\\' => 26,
'Symfony\\Component\\Config\\' => 25,
'Symfony\\Component\\Cache\\' => 24,
'Symfony\\Bundle\\FrameworkBundle\\' => 31,
),
'P' =>
array (
'Psr\\SimpleCache\\' => 16,
'Psr\\Log\\' => 8,
'Psr\\Container\\' => 14,
'Psr\\Cache\\' => 10,
),
'A' =>
array (
'App\\Tests\\' => 10,
'App\\' => 4,
),
);
public static $prefixDirsPsr4 = array (
'Symfony\\Polyfill\\Mbstring\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
),
'Symfony\\Flex\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/flex/src',
),
'Symfony\\Component\\Yaml\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/yaml',
),
'Symfony\\Component\\Routing\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/routing',
),
'Symfony\\Component\\HttpKernel\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/http-kernel',
),
'Symfony\\Component\\HttpFoundation\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/http-foundation',
),
'Symfony\\Component\\Finder\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/finder',
),
'Symfony\\Component\\Filesystem\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/filesystem',
),
'Symfony\\Component\\EventDispatcher\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/event-dispatcher',
),
'Symfony\\Component\\Dotenv\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/dotenv',
),
'Symfony\\Component\\DependencyInjection\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/dependency-injection',
),
'Symfony\\Component\\Debug\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/debug',
),
'Symfony\\Component\\Console\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/console',
),
'Symfony\\Component\\Config\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/config',
),
'Symfony\\Component\\Cache\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/cache',
),
'Symfony\\Bundle\\FrameworkBundle\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/framework-bundle',
),
'Psr\\SimpleCache\\' =>
array (
0 => __DIR__ . '/..' . '/psr/simple-cache/src',
),
'Psr\\Log\\' =>
array (
0 => __DIR__ . '/..' . '/psr/log/Psr/Log',
),
'Psr\\Container\\' =>
array (
0 => __DIR__ . '/..' . '/psr/container/src',
),
'Psr\\Cache\\' =>
array (
0 => __DIR__ . '/..' . '/psr/cache/src',
),
'App\\Tests\\' =>
array (
0 => __DIR__ . '/../..' . '/tests',
),
'App\\' =>
array (
0 => __DIR__ . '/../..' . '/src',
),
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit9371e9bc0ff619285cd145dcf0b9e4dd::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit9371e9bc0ff619285cd145dcf0b9e4dd::$prefixDirsPsr4;
}, null, ClassLoader::class);
}
}
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <[email protected]>
* Jordi Boggiano <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <[email protected]>
* @author Jordi Boggiano <[email protected]>
* @see http://www.php-fig.org/psr/psr-0/
* @see http://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
// PSR-4
private $prefixLengthsPsr4 = array();
private $prefixDirsPsr4 = array();
private $fallbackDirsPsr4 = array();
// PSR-0
private $prefixesPsr0 = array();
private $fallbackDirsPsr0 = array();
private $useIncludePath = false;
private $classMap = array();
private $classMapAuthoritative = false;
private $missingClasses = array();
private $apcuPrefix;
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', $this->prefixesPsr0);
}
return array();
}
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array $classMap Class to filename map
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*/
public function add($prefix, $paths, $prepend = false)
{
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 base directories
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
/**
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*/
public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
}
/**
* The APCu prefix in use, or null if APCu caching is not enabled.
*
* @return string|null
*/
public function getApcuPrefix()
{
return $this->apcuPrefix;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
/**
* Unregisters this instance as an autoloader.
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return bool|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
return true;
}
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
if (null !== $this->apcuPrefix) {
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
if ($hit) {
return $file;
}
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if (null !== $this->apcuPrefix) {
apcu_add($this->apcuPrefix.$class, $file);
}
if (false === $file) {
// Remember that this class does not exist.
$this->missingClasses[$class] = true;
}
return $file;
}
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
if (file_exists($file = $dir . $pathEnd)) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*/
function includeFile($file)
{
include $file;
}
[
{
"name": "psr/cache",
"version": "1.0.1",
"version_normalized": "1.0.1.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/cache.git",
"reference": "d11b50ad223250cf17b86e38383413f5a6764bf8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8",
"reference": "d11b50ad223250cf17b86e38383413f5a6764bf8",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"time": "2016-08-06T20:24:11+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Psr\\Cache\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for caching libraries",
"keywords": [
"cache",
"psr",
"psr-6"
]
},
{
"name": "psr/container",
"version": "1.0.0",
"version_normalized": "1.0.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/container.git",
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"time": "2017-02-14T16:28:37+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Psr\\Container\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common Container Interface (PHP FIG PSR-11)",
"homepage": "https://github.com/php-fig/container",
"keywords": [
"PSR-11",
"container",
"container-interface",
"container-interop",
"psr"
]
},
{
"name": "psr/log",
"version": "1.0.2",
"version_normalized": "1.0.2.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
"reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"time": "2016-10-10T12:19:37+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Psr\\Log\\": "Psr/Log/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"homepage": "https://github.com/php-fig/log",
"keywords": [
"log",
"psr",
"psr-3"
]
},
{
"name": "psr/simple-cache",
"version": "1.0.1",
"version_normalized": "1.0.1.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/simple-cache.git",
"reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
"reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"time": "2017-10-23T01:57:42+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Psr\\SimpleCache\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interfaces for simple caching",
"keywords": [
"cache",
"caching",
"psr",
"psr-16",
"simple-cache"
]
},
{
"name": "symfony/cache",
"version": "v4.1.6",
"version_normalized": "4.1.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/cache.git",
"reference": "05ce0ddc8bc1ffe592105398fc2c725cb3080a38"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/cache/zipball/05ce0ddc8bc1ffe592105398fc2c725cb3080a38",
"reference": "05ce0ddc8bc1ffe592105398fc2c725cb3080a38",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"psr/cache": "~1.0",
"psr/log": "~1.0",
"psr/simple-cache": "^1.0"
},
"conflict": {
"symfony/var-dumper": "<3.4"
},
"provide": {
"psr/cache-implementation": "1.0",
"psr/simple-cache-implementation": "1.0"
},
"require-dev": {
"cache/integration-tests": "dev-master",
"doctrine/cache": "~1.6",
"doctrine/dbal": "~2.4",
"predis/predis": "~1.0"
},
"time": "2018-09-30T03:38:13+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\Cache\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Cache component with PSR-6, PSR-16, and tags",
"homepage": "https://symfony.com",
"keywords": [
"caching",
"psr6"
]
},
{
"name": "symfony/config",
"version": "v4.1.6",
"version_normalized": "4.1.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/config.git",
"reference": "b3d4d7b567d7a49e6dfafb6d4760abc921177c96"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/config/zipball/b3d4d7b567d7a49e6dfafb6d4760abc921177c96",
"reference": "b3d4d7b567d7a49e6dfafb6d4760abc921177c96",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"symfony/filesystem": "~3.4|~4.0",
"symfony/polyfill-ctype": "~1.8"
},
"conflict": {
"symfony/finder": "<3.4"
},
"require-dev": {
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/event-dispatcher": "~3.4|~4.0",
"symfony/finder": "~3.4|~4.0",
"symfony/yaml": "~3.4|~4.0"
},
"suggest": {
"symfony/yaml": "To use the yaml reference dumper"
},
"time": "2018-09-08T13:24:10+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\Config\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Config Component",
"homepage": "https://symfony.com"
},
{
"name": "symfony/console",
"version": "v4.1.6",
"version_normalized": "4.1.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "dc7122fe5f6113cfaba3b3de575d31112c9aa60b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/dc7122fe5f6113cfaba3b3de575d31112c9aa60b",
"reference": "dc7122fe5f6113cfaba3b3de575d31112c9aa60b",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"symfony/polyfill-mbstring": "~1.0"
},
"conflict": {
"symfony/dependency-injection": "<3.4",
"symfony/process": "<3.3"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/config": "~3.4|~4.0",
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/event-dispatcher": "~3.4|~4.0",
"symfony/lock": "~3.4|~4.0",
"symfony/process": "~3.4|~4.0"
},
"suggest": {
"psr/log-implementation": "For using the console logger",
"symfony/event-dispatcher": "",
"symfony/lock": "",
"symfony/process": ""
},
"time": "2018-10-03T08:15:46+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\Console\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com"
},
{
"name": "symfony/debug",
"version": "v4.1.6",
"version_normalized": "4.1.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
"reference": "e3f76ce6198f81994e019bb2b4e533e9de1b9b90"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/debug/zipball/e3f76ce6198f81994e019bb2b4e533e9de1b9b90",
"reference": "e3f76ce6198f81994e019bb2b4e533e9de1b9b90",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"psr/log": "~1.0"
},
"conflict": {
"symfony/http-kernel": "<3.4"
},
"require-dev": {
"symfony/http-kernel": "~3.4|~4.0"
},
"time": "2018-10-02T16:36:10+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\Debug\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Debug Component",
"homepage": "https://symfony.com"
},
{
"name": "symfony/dependency-injection",
"version": "v4.1.6",
"version_normalized": "4.1.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/dependency-injection.git",
"reference": "f6b9d893ad28aefd8942dc0469c8397e2216fe30"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/f6b9d893ad28aefd8942dc0469c8397e2216fe30",
"reference": "f6b9d893ad28aefd8942dc0469c8397e2216fe30",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"psr/container": "^1.0"
},
"conflict": {
"symfony/config": "<4.1.1",
"symfony/finder": "<3.4",
"symfony/proxy-manager-bridge": "<3.4",
"symfony/yaml": "<3.4"
},
"provide": {
"psr/container-implementation": "1.0"
},
"require-dev": {
"symfony/config": "~4.1",
"symfony/expression-language": "~3.4|~4.0",
"symfony/yaml": "~3.4|~4.0"
},
"suggest": {
"symfony/config": "",
"symfony/expression-language": "For using expressions in service container configuration",
"symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required",
"symfony/proxy-manager-bridge": "Generate service proxies to lazy load them",
"symfony/yaml": ""
},
"time": "2018-10-02T12:40:59+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\DependencyInjection\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony DependencyInjection Component",
"homepage": "https://symfony.com"
},
{
"name": "symfony/dotenv",
"version": "v4.1.6",
"version_normalized": "4.1.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/dotenv.git",
"reference": "22ca63c46e252b8a8f37b8f9e6da66bff5b3d3e7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/dotenv/zipball/22ca63c46e252b8a8f37b8f9e6da66bff5b3d3e7",
"reference": "22ca63c46e252b8a8f37b8f9e6da66bff5b3d3e7",
"shasum": ""
},
"require": {
"php": "^7.1.3"
},
"require-dev": {
"symfony/process": "~3.4|~4.0"
},
"time": "2018-07-26T11:24:31+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\Dotenv\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Registers environment variables from a .env file",
"homepage": "https://symfony.com",
"keywords": [
"dotenv",
"env",
"environment"
]
},
{
"name": "symfony/event-dispatcher",
"version": "v4.1.6",
"version_normalized": "4.1.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
"reference": "bfb30c2ad377615a463ebbc875eba64a99f6aa3e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/bfb30c2ad377615a463ebbc875eba64a99f6aa3e",
"reference": "bfb30c2ad377615a463ebbc875eba64a99f6aa3e",
"shasum": ""
},
"require": {
"php": "^7.1.3"
},
"conflict": {
"symfony/dependency-injection": "<3.4"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/config": "~3.4|~4.0",
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/expression-language": "~3.4|~4.0",
"symfony/stopwatch": "~3.4|~4.0"
},
"suggest": {
"symfony/dependency-injection": "",
"symfony/http-kernel": ""
},
"time": "2018-07-26T09:10:45+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\EventDispatcher\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com"
},
{
"name": "symfony/filesystem",
"version": "v4.1.6",
"version_normalized": "4.1.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "596d12b40624055c300c8b619755b748ca5cf0b5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/596d12b40624055c300c8b619755b748ca5cf0b5",
"reference": "596d12b40624055c300c8b619755b748ca5cf0b5",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"symfony/polyfill-ctype": "~1.8"
},
"time": "2018-10-02T12:40:59+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\Filesystem\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Filesystem Component",
"homepage": "https://symfony.com"
},
{
"name": "symfony/finder",
"version": "v4.1.6",
"version_normalized": "4.1.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "1f17195b44543017a9c9b2d437c670627e96ad06"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/1f17195b44543017a9c9b2d437c670627e96ad06",
"reference": "1f17195b44543017a9c9b2d437c670627e96ad06",
"shasum": ""
},
"require": {
"php": "^7.1.3"
},
"time": "2018-10-03T08:47:56+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\Finder\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com"
},
{
"name": "symfony/flex",
"version": "v1.1.1",
"version_normalized": "1.1.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/flex.git",
"reference": "9fb60f232af0764d58002e7872acb43a74506d25"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/flex/zipball/9fb60f232af0764d58002e7872acb43a74506d25",
"reference": "9fb60f232af0764d58002e7872acb43a74506d25",
"shasum": ""
},
"require": {
"composer-plugin-api": "^1.0",
"php": "^7.0"
},
"require-dev": {
"composer/composer": "^1.0.2",
"symfony/phpunit-bridge": "^3.2.8"
},
"time": "2018-09-03T08:17:12+00:00",
"type": "composer-plugin",
"extra": {
"branch-alias": {
"dev-master": "1.1-dev"
},
"class": "Symfony\\Flex\\Flex"
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Flex\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
}
],
"description": "Composer plugin for Symfony"
},
{
"name": "symfony/framework-bundle",
"version": "v4.1.6",
"version_normalized": "4.1.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/framework-bundle.git",
"reference": "3a0f2ec035c6ecc0f751fda1a76b02310bc9bbfe"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/framework-bundle/zipball/3a0f2ec035c6ecc0f751fda1a76b02310bc9bbfe",
"reference": "3a0f2ec035c6ecc0f751fda1a76b02310bc9bbfe",
"shasum": ""
},
"require": {
"ext-xml": "*",
"php": "^7.1.3",
"symfony/cache": "~3.4|~4.0",
"symfony/config": "~3.4|~4.0",
"symfony/dependency-injection": "^4.1.1",
"symfony/event-dispatcher": "^4.1",
"symfony/filesystem": "~3.4|~4.0",
"symfony/finder": "~3.4|~4.0",
"symfony/http-foundation": "^4.1",
"symfony/http-kernel": "^4.1",
"symfony/polyfill-mbstring": "~1.0",
"symfony/routing": "^4.1"
},
"conflict": {
"phpdocumentor/reflection-docblock": "<3.0",
"phpdocumentor/type-resolver": "<0.2.1",
"phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0",
"symfony/asset": "<3.4",
"symfony/console": "<3.4",
"symfony/form": "<4.1",
"symfony/messenger": ">=4.2",
"symfony/property-info": "<3.4",
"symfony/serializer": "<4.1",
"symfony/stopwatch": "<3.4",
"symfony/translation": "<3.4",
"symfony/twig-bridge": "<4.1.1",
"symfony/validator": "<4.1",
"symfony/workflow": "<4.1"
},
"require-dev": {
"doctrine/annotations": "~1.0",
"doctrine/cache": "~1.0",
"fig/link-util": "^1.0",
"phpdocumentor/reflection-docblock": "^3.0|^4.0",
"symfony/asset": "~3.4|~4.0",
"symfony/browser-kit": "~3.4|~4.0",
"symfony/console": "~3.4|~4.0",
"symfony/css-selector": "~3.4|~4.0",
"symfony/dom-crawler": "~3.4|~4.0",
"symfony/expression-language": "~3.4|~4.0",
"symfony/form": "^4.1",
"symfony/lock": "~3.4|~4.0",
"symfony/messenger": "^4.1",
"symfony/polyfill-intl-icu": "~1.0",
"symfony/process": "~3.4|~4.0",
"symfony/property-info": "~3.4|~4.0",
"symfony/security": "~3.4|~4.0",
"symfony/security-core": "~3.4|~4.0",
"symfony/security-csrf": "~3.4|~4.0",
"symfony/serializer": "^4.1",
"symfony/stopwatch": "~3.4|~4.0",
"symfony/templating": "~3.4|~4.0",
"symfony/translation": "~3.4|~4.0",
"symfony/validator": "^4.1",
"symfony/var-dumper": "~3.4|~4.0",
"symfony/web-link": "~3.4|~4.0",
"symfony/workflow": "^4.1",
"symfony/yaml": "~3.4|~4.0",
"twig/twig": "~1.34|~2.4"
},
"suggest": {
"ext-apcu": "For best performance of the system caches",
"symfony/console": "For using the console commands",
"symfony/form": "For using forms",
"symfony/property-info": "For using the property_info service",
"symfony/serializer": "For using the serializer service",
"symfony/validator": "For using validation",
"symfony/web-link": "For using web links, features such as preloading, prefetching or prerendering",
"symfony/yaml": "For using the debug:config and lint:yaml commands"
},
"time": "2018-10-03T08:47:56+00:00",
"type": "symfony-bundle",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Bundle\\FrameworkBundle\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony FrameworkBundle",
"homepage": "https://symfony.com"
},
{
"name": "symfony/http-foundation",
"version": "v4.1.6",
"version_normalized": "4.1.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
"reference": "d528136617ff24f530e70df9605acc1b788b08d4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/d528136617ff24f530e70df9605acc1b788b08d4",
"reference": "d528136617ff24f530e70df9605acc1b788b08d4",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"symfony/polyfill-mbstring": "~1.1"
},
"require-dev": {
"predis/predis": "~1.0",
"symfony/expression-language": "~3.4|~4.0"
},
"time": "2018-10-03T08:48:45+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\HttpFoundation\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony HttpFoundation Component",
"homepage": "https://symfony.com"
},
{
"name": "symfony/http-kernel",
"version": "v4.1.6",
"version_normalized": "4.1.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
"reference": "f5e7c15a5d010be0e16ce798594c5960451d4220"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/f5e7c15a5d010be0e16ce798594c5960451d4220",
"reference": "f5e7c15a5d010be0e16ce798594c5960451d4220",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"psr/log": "~1.0",
"symfony/debug": "~3.4|~4.0",
"symfony/event-dispatcher": "~4.1",
"symfony/http-foundation": "^4.1.1",
"symfony/polyfill-ctype": "~1.8"
},
"conflict": {
"symfony/config": "<3.4",
"symfony/dependency-injection": "<4.1",
"symfony/var-dumper": "<4.1.1",
"twig/twig": "<1.34|<2.4,>=2"
},
"provide": {
"psr/log-implementation": "1.0"
},
"require-dev": {
"psr/cache": "~1.0",
"symfony/browser-kit": "~3.4|~4.0",
"symfony/config": "~3.4|~4.0",
"symfony/console": "~3.4|~4.0",
"symfony/css-selector": "~3.4|~4.0",
"symfony/dependency-injection": "^4.1",
"symfony/dom-crawler": "~3.4|~4.0",
"symfony/expression-language": "~3.4|~4.0",
"symfony/finder": "~3.4|~4.0",
"symfony/process": "~3.4|~4.0",
"symfony/routing": "~3.4|~4.0",
"symfony/stopwatch": "~3.4|~4.0",
"symfony/templating": "~3.4|~4.0",
"symfony/translation": "~3.4|~4.0",
"symfony/var-dumper": "^4.1.1"
},
"suggest": {
"symfony/browser-kit": "",
"symfony/config": "",
"symfony/console": "",
"symfony/dependency-injection": "",
"symfony/var-dumper": ""
},
"time": "2018-10-03T12:53:38+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\HttpKernel\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony HttpKernel Component",
"homepage": "https://symfony.com"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.9.0",
"version_normalized": "1.9.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d0cd638f4634c16d8df4508e847f14e9e43168b8",
"reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"time": "2018-08-06T14:22:27+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.9-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
]
},
{
"name": "symfony/routing",
"version": "v4.1.6",
"version_normalized": "4.1.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/routing.git",
"reference": "537803f0bdfede36b9acef052d2e4d447d9fa0e9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/routing/zipball/537803f0bdfede36b9acef052d2e4d447d9fa0e9",
"reference": "537803f0bdfede36b9acef052d2e4d447d9fa0e9",
"shasum": ""
},
"require": {
"php": "^7.1.3"
},
"conflict": {
"symfony/config": "<3.4",
"symfony/dependency-injection": "<3.4",
"symfony/yaml": "<3.4"
},
"require-dev": {
"doctrine/annotations": "~1.0",
"psr/log": "~1.0",
"symfony/config": "~3.4|~4.0",
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/expression-language": "~3.4|~4.0",
"symfony/http-foundation": "~3.4|~4.0",
"symfony/yaml": "~3.4|~4.0"
},
"suggest": {
"doctrine/annotations": "For using the annotation loader",
"symfony/config": "For using the all-in-one router or any loader",
"symfony/dependency-injection": "For loading routes from a service",
"symfony/expression-language": "For using expression matching",
"symfony/http-foundation": "For using a Symfony Request object",
"symfony/yaml": "For using the YAML loader"
},
"time": "2018-10-02T12:40:59+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\Routing\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Routing Component",
"homepage": "https://symfony.com",
"keywords": [
"router",
"routing",
"uri",
"url"
]
},
{
"name": "symfony/yaml",
"version": "v4.1.6",
"version_normalized": "4.1.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "367e689b2fdc19965be435337b50bc8adf2746c9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/367e689b2fdc19965be435337b50bc8adf2746c9",
"reference": "367e689b2fdc19965be435337b50bc8adf2746c9",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"symfony/polyfill-ctype": "~1.8"
},
"conflict": {
"symfony/console": "<3.4"
},
"require-dev": {
"symfony/console": "~3.4|~4.0"
},
"suggest": {
"symfony/console": "For validating YAML files using the lint command"
},
"time": "2018-10-02T16:36:10+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\Yaml\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com"
}
]
Copyright (c) Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Changelog

All notable changes to this project will be documented in this file, in reverse chronological order by release.

1.0.1 - 2016-08-06

Fixed

  • Make spacing consistent in phpdoc annotations php-fig/cache#9 - chalasr
  • Fix grammar in phpdoc annotations php-fig/cache#10 - chalasr
  • Be more specific in docblocks that getItems() and deleteItems() take an array of strings (string[]) compared to just array php-fig/cache#8 - GrahamCampbell
  • For expiresAt() and expiresAfter() in CacheItemInterface fix docblock to specify null as a valid parameters as well as an implementation of DateTimeInterface php-fig/cache#7 - GrahamCampbell

1.0.0 - 2015-12-11

Initial stable release; reflects accepted PSR-6 specification

{
"name": "psr/cache",
"description": "Common interface for caching libraries",
"keywords": ["psr", "psr-6", "cache"],
"license": "MIT",
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"require": {
"php": ">=5.3.0"
},
"autoload": {
"psr-4": {
"Psr\\Cache\\": "src/"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
}
}
Copyright (c) 2015 PHP Framework Interoperability Group
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

PSR Cache

This repository holds all interfaces defined by PSR-6.

Note that this is not a Cache implementation of its own. It is merely an interface that describes a Cache implementation. See the specification for more details.

<?php
namespace Psr\Cache;
/**
* Exception interface for all exceptions thrown by an Implementing Library.
*/
interface CacheException
{
}
<?php
namespace Psr\Cache;
/**
* CacheItemInterface defines an interface for interacting with objects inside a cache.
*
* Each Item object MUST be associated with a specific key, which can be set
* according to the implementing system and is typically passed by the
* Cache\CacheItemPoolInterface object.
*
* The Cache\CacheItemInterface object encapsulates the storage and retrieval of
* cache items. Each Cache\CacheItemInterface is generated by a
* Cache\CacheItemPoolInterface object, which is responsible for any required
* setup as well as associating the object with a unique Key.
* Cache\CacheItemInterface objects MUST be able to store and retrieve any type
* of PHP value defined in the Data section of the specification.
*
* Calling Libraries MUST NOT instantiate Item objects themselves. They may only
* be requested from a Pool object via the getItem() method. Calling Libraries
* SHOULD NOT assume that an Item created by one Implementing Library is
* compatible with a Pool from another Implementing Library.
*/
interface CacheItemInterface
{
/**
* Returns the key for the current cache item.
*
* The key is loaded by the Implementing Library, but should be available to
* the higher level callers when needed.
*
* @return string
* The key string for this cache item.
*/
public function getKey();
/**
* Retrieves the value of the item from the cache associated with this object's key.
*
* The value returned must be identical to the value originally stored by set().
*
* If isHit() returns false, this method MUST return null. Note that null
* is a legitimate cached value, so the isHit() method SHOULD be used to
* differentiate between "null value was found" and "no value was found."
*
* @return mixed
* The value corresponding to this cache item's key, or null if not found.
*/
public function get();
/**
* Confirms if the cache item lookup resulted in a cache hit.
*
* Note: This method MUST NOT have a race condition between calling isHit()
* and calling get().
*
* @return bool
* True if the request resulted in a cache hit. False otherwise.
*/
public function isHit();
/**
* Sets the value represented by this cache item.
*
* The $value argument may be any item that can be serialized by PHP,
* although the method of serialization is left up to the Implementing
* Library.
*
* @param mixed $value
* The serializable value to be stored.
*
* @return static
* The invoked object.
*/
public function set($value);
/**
* Sets the expiration time for this cache item.
*
* @param \DateTimeInterface|null $expiration
* The point in time after which the item MUST be considered expired.
* If null is passed explicitly, a default value MAY be used. If none is set,
* the value should be stored permanently or for as long as the
* implementation allows.
*
* @return static
* The called object.
*/
public function expiresAt($expiration);
/**
* Sets the expiration time for this cache item.
*
* @param int|\DateInterval|null $time
* The period of time from the present after which the item MUST be considered
* expired. An integer parameter is understood to be the time in seconds until
* expiration. If null is passed explicitly, a default value MAY be used.
* If none is set, the value should be stored permanently or for as long as the
* implementation allows.
*
* @return static
* The called object.
*/
public function expiresAfter($time);
}
<?php
namespace Psr\Cache;
/**
* CacheItemPoolInterface generates CacheItemInterface objects.
*
* The primary purpose of Cache\CacheItemPoolInterface is to accept a key from
* the Calling Library and return the associated Cache\CacheItemInterface object.
* It is also the primary point of interaction with the entire cache collection.
* All configuration and initialization of the Pool is left up to an
* Implementing Library.
*/
interface CacheItemPoolInterface
{
/**
* Returns a Cache Item representing the specified key.
*
* This method must always return a CacheItemInterface object, even in case of
* a cache miss. It MUST NOT return null.
*
* @param string $key
* The key for which to return the corresponding Cache Item.
*
* @throws InvalidArgumentException
* If the $key string is not a legal value a \Psr\Cache\InvalidArgumentException
* MUST be thrown.
*
* @return CacheItemInterface
* The corresponding Cache Item.
*/
public function getItem($key);
/**
* Returns a traversable set of cache items.
*
* @param string[] $keys
* An indexed array of keys of items to retrieve.
*
* @throws InvalidArgumentException
* If any of the keys in $keys are not a legal value a \Psr\Cache\InvalidArgumentException
* MUST be thrown.
*
* @return array|\Traversable
* A traversable collection of Cache Items keyed by the cache keys of
* each item. A Cache item will be returned for each key, even if that
* key is not found. However, if no keys are specified then an empty
* traversable MUST be returned instead.
*/
public function getItems(array $keys = array());
/**
* Confirms if the cache contains specified cache item.
*
* Note: This method MAY avoid retrieving the cached value for performance reasons.
* This could result in a race condition with CacheItemInterface::get(). To avoid
* such situation use CacheItemInterface::isHit() instead.
*
* @param string $key
* The key for which to check existence.
*
* @throws InvalidArgumentException
* If the $key string is not a legal value a \Psr\Cache\InvalidArgumentException
* MUST be thrown.
*
* @return bool
* True if item exists in the cache, false otherwise.
*/
public function hasItem($key);
/**
* Deletes all items in the pool.
*
* @return bool
* True if the pool was successfully cleared. False if there was an error.
*/
public function clear();
/**
* Removes the item from the pool.
*
* @param string $key
* The key to delete.
*
* @throws InvalidArgumentException
* If the $key string is not a legal value a \Psr\Cache\InvalidArgumentException
* MUST be thrown.
*
* @return bool
* True if the item was successfully removed. False if there was an error.
*/
public function deleteItem($key);
/**
* Removes multiple items from the pool.
*
* @param string[] $keys
* An array of keys that should be removed from the pool.
* @throws InvalidArgumentException
* If any of the keys in $keys are not a legal value a \Psr\Cache\InvalidArgumentException
* MUST be thrown.
*
* @return bool
* True if the items were successfully removed. False if there was an error.
*/
public function deleteItems(array $keys);
/**
* Persists a cache item immediately.
*
* @param CacheItemInterface $item
* The cache item to save.
*
* @return bool
* True if the item was successfully persisted. False if there was an error.
*/
public function save(CacheItemInterface $item);
/**
* Sets a cache item to be persisted later.
*
* @param CacheItemInterface $item
* The cache item to save.
*
* @return bool
* False if the item could not be queued or if a commit was attempted and failed. True otherwise.
*/
public function saveDeferred(CacheItemInterface $item);
/**
* Persists any deferred cache items.
*
* @return bool
* True if all not-yet-saved items were successfully saved or there were none. False otherwise.
*/
public function commit();
}
<?php
namespace Psr\Cache;
/**
* Exception interface for invalid cache arguments.
*
* Any time an invalid argument is passed into a method it must throw an
* exception class which implements Psr\Cache\InvalidArgumentException.
*/
interface InvalidArgumentException extends CacheException
{
}
{
"name": "psr/container",
"type": "library",
"description": "Common Container Interface (PHP FIG PSR-11)",
"keywords": ["psr", "psr-11", "container", "container-interop", "container-interface"],
"homepage": "https://github.com/php-fig/container",
"license": "MIT",
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"require": {
"php": ">=5.3.0"
},
"autoload": {
"psr-4": {
"Psr\\Container\\": "src/"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
}
}
The MIT License (MIT)
Copyright (c) 2013-2016 container-interop
Copyright (c) 2016 PHP Framework Interoperability Group
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

PSR Container

This repository holds all interfaces/classes/traits related to PSR-11.

Note that this is not a container implementation of its own. See the specification for more details.

<?php
/**
* @license http://www.opensource.org/licenses/mit-license.php MIT (see the LICENSE file)
*/
namespace Psr\Container;
/**
* Base interface representing a generic exception in a container.
*/
interface ContainerExceptionInterface
{
}
<?php
/**
* @license http://www.opensource.org/licenses/mit-license.php MIT (see the LICENSE file)
*/
namespace Psr\Container;
/**
* Describes the interface of a container that exposes methods to read its entries.
*/
interface ContainerInterface
{
/**
* Finds an entry of the container by its identifier and returns it.
*
* @param string $id Identifier of the entry to look for.
*
* @throws NotFoundExceptionInterface No entry was found for **this** identifier.
* @throws ContainerExceptionInterface Error while retrieving the entry.
*
* @return mixed Entry.
*/
public function get($id);
/**
* Returns true if the container can return an entry for the given identifier.
* Returns false otherwise.
*
* `has($id)` returning true does not mean that `get($id)` will not throw an exception.
* It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`.
*
* @param string $id Identifier of the entry to look for.
*
* @return bool
*/
public function has($id);
}
<?php
/**
* @license http://www.opensource.org/licenses/mit-license.php MIT (see the LICENSE file)
*/
namespace Psr\Container;
/**
* No entry was found in the container.
*/
interface NotFoundExceptionInterface extends ContainerExceptionInterface
{
}
{
"name": "psr/log",
"description": "Common interface for logging libraries",
"keywords": ["psr", "psr-3", "log"],
"homepage": "https://github.com/php-fig/log",
"license": "MIT",
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"require": {
"php": ">=5.3.0"
},
"autoload": {
"psr-4": {
"Psr\\Log\\": "Psr/Log/"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
}
}
Copyright (c) 2012 PHP Framework Interoperability Group
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
<?php
namespace Psr\Log;
/**
* This is a simple Logger implementation that other Loggers can inherit from.
*
* It simply delegates all log-level-specific methods to the `log` method to
* reduce boilerplate code that a simple Logger that does the same thing with
* messages regardless of the error level has to implement.
*/
abstract class AbstractLogger implements LoggerInterface
{
/**
* System is unusable.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function emergency($message, array $context = array())
{
$this->log(LogLevel::EMERGENCY, $message, $context);
}
/**
* Action must be taken immediately.
*
* Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function alert($message, array $context = array())
{
$this->log(LogLevel::ALERT, $message, $context);
}
/**
* Critical conditions.
*
* Example: Application component unavailable, unexpected exception.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function critical($message, array $context = array())
{
$this->log(LogLevel::CRITICAL, $message, $context);
}
/**
* Runtime errors that do not require immediate action but should typically
* be logged and monitored.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function error($message, array $context = array())
{
$this->log(LogLevel::ERROR, $message, $context);
}
/**
* Exceptional occurrences that are not errors.
*
* Example: Use of deprecated APIs, poor use of an API, undesirable things
* that are not necessarily wrong.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function warning($message, array $context = array())
{
$this->log(LogLevel::WARNING, $message, $context);
}
/**
* Normal but significant events.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function notice($message, array $context = array())
{
$this->log(LogLevel::NOTICE, $message, $context);
}
/**
* Interesting events.
*
* Example: User logs in, SQL logs.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function info($message, array $context = array())
{
$this->log(LogLevel::INFO, $message, $context);
}
/**
* Detailed debug information.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function debug($message, array $context = array())
{
$this->log(LogLevel::DEBUG, $message, $context);
}
}
<?php
namespace Psr\Log;
class InvalidArgumentException extends \InvalidArgumentException
{
}
<?php
namespace Psr\Log;
/**
* Describes a logger-aware instance.
*/
interface LoggerAwareInterface
{
/**
* Sets a logger instance on the object.
*
* @param LoggerInterface $logger
*
* @return void
*/
public function setLogger(LoggerInterface $logger);
}
<?php
namespace Psr\Log;
/**
* Basic Implementation of LoggerAwareInterface.
*/
trait LoggerAwareTrait
{
/**
* The logger instance.
*
* @var LoggerInterface
*/
protected $logger;
/**
* Sets a logger.
*
* @param LoggerInterface $logger
*/
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
}
}
<?php
namespace Psr\Log;
/**
* Describes a logger instance.
*
* The message MUST be a string or object implementing __toString().
*
* The message MAY contain placeholders in the form: {foo} where foo
* will be replaced by the context data in key "foo".
*
* The context array can contain arbitrary data. The only assumption that
* can be made by implementors is that if an Exception instance is given
* to produce a stack trace, it MUST be in a key named "exception".
*
* See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
* for the full interface specification.
*/
interface LoggerInterface
{
/**
* System is unusable.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function emergency($message, array $context = array());
/**
* Action must be taken immediately.
*
* Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function alert($message, array $context = array());
/**
* Critical conditions.
*
* Example: Application component unavailable, unexpected exception.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function critical($message, array $context = array());
/**
* Runtime errors that do not require immediate action but should typically
* be logged and monitored.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function error($message, array $context = array());
/**
* Exceptional occurrences that are not errors.
*
* Example: Use of deprecated APIs, poor use of an API, undesirable things
* that are not necessarily wrong.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function warning($message, array $context = array());
/**
* Normal but significant events.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function notice($message, array $context = array());
/**
* Interesting events.
*
* Example: User logs in, SQL logs.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function info($message, array $context = array());
/**
* Detailed debug information.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function debug($message, array $context = array());
/**
* Logs with an arbitrary level.
*
* @param mixed $level
* @param string $message
* @param array $context
*
* @return void
*/
public function log($level, $message, array $context = array());
}
<?php
namespace Psr\Log;
/**
* This is a simple Logger trait that classes unable to extend AbstractLogger
* (because they extend another class, etc) can include.
*
* It simply delegates all log-level-specific methods to the `log` method to
* reduce boilerplate code that a simple Logger that does the same thing with
* messages regardless of the error level has to implement.
*/
trait LoggerTrait
{
/**
* System is unusable.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function emergency($message, array $context = array())
{
$this->log(LogLevel::EMERGENCY, $message, $context);
}
/**
* Action must be taken immediately.
*
* Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function alert($message, array $context = array())
{
$this->log(LogLevel::ALERT, $message, $context);
}
/**
* Critical conditions.
*
* Example: Application component unavailable, unexpected exception.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function critical($message, array $context = array())
{
$this->log(LogLevel::CRITICAL, $message, $context);
}
/**
* Runtime errors that do not require immediate action but should typically
* be logged and monitored.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function error($message, array $context = array())
{
$this->log(LogLevel::ERROR, $message, $context);
}
/**
* Exceptional occurrences that are not errors.
*
* Example: Use of deprecated APIs, poor use of an API, undesirable things
* that are not necessarily wrong.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function warning($message, array $context = array())
{
$this->log(LogLevel::WARNING, $message, $context);
}
/**
* Normal but significant events.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function notice($message, array $context = array())
{
$this->log(LogLevel::NOTICE, $message, $context);
}
/**
* Interesting events.
*
* Example: User logs in, SQL logs.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function info($message, array $context = array())
{
$this->log(LogLevel::INFO, $message, $context);
}
/**
* Detailed debug information.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function debug($message, array $context = array())
{
$this->log(LogLevel::DEBUG, $message, $context);
}
/**
* Logs with an arbitrary level.
*
* @param mixed $level
* @param string $message
* @param array $context
*
* @return void
*/
abstract public function log($level, $message, array $context = array());
}
<?php
namespace Psr\Log;
/**
* Describes log levels.
*/
class LogLevel
{
const EMERGENCY = 'emergency';
const ALERT = 'alert';
const CRITICAL = 'critical';
const ERROR = 'error';
const WARNING = 'warning';
const NOTICE = 'notice';
const INFO = 'info';
const DEBUG = 'debug';
}
<?php
namespace Psr\Log;
/**
* This Logger can be used to avoid conditional log calls.
*
* Logging should always be optional, and if no logger is provided to your
* library creating a NullLogger instance to have something to throw logs at
* is a good way to avoid littering your code with `if ($this->logger) { }`
* blocks.
*/
class NullLogger extends AbstractLogger
{
/**
* Logs with an arbitrary level.
*
* @param mixed $level
* @param string $message
* @param array $context
*
* @return void
*/
public function log($level, $message, array $context = array())
{
// noop
}
}
<?php
namespace Psr\Log\Test;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
/**
* Provides a base test class for ensuring compliance with the LoggerInterface.
*
* Implementors can extend the class and implement abstract methods to run this
* as part of their test suite.
*/
abstract class LoggerInterfaceTest extends \PHPUnit_Framework_TestCase
{
/**
* @return LoggerInterface
*/
abstract public function getLogger();
/**
* This must return the log messages in order.
*
* The simple formatting of the messages is: "<LOG LEVEL> <MESSAGE>".
*
* Example ->error('Foo') would yield "error Foo".
*
* @return string[]
*/
abstract public function getLogs();
public function testImplements()
{
$this->assertInstanceOf('Psr\Log\LoggerInterface', $this->getLogger());
}
/**
* @dataProvider provideLevelsAndMessages
*/
public function testLogsAtAllLevels($level, $message)
{
$logger = $this->getLogger();
$logger->{$level}($message, array('user' => 'Bob'));
$logger->log($level, $message, array('user' => 'Bob'));
$expected = array(
$level.' message of level '.$level.' with context: Bob',
$level.' message of level '.$level.' with context: Bob',
);
$this->assertEquals($expected, $this->getLogs());
}
public function provideLevelsAndMessages()
{
return array(
LogLevel::EMERGENCY => array(LogLevel::EMERGENCY, 'message of level emergency with context: {user}'),
LogLevel::ALERT => array(LogLevel::ALERT, 'message of level alert with context: {user}'),
LogLevel::CRITICAL => array(LogLevel::CRITICAL, 'message of level critical with context: {user}'),
LogLevel::ERROR => array(LogLevel::ERROR, 'message of level error with context: {user}'),
LogLevel::WARNING => array(LogLevel::WARNING, 'message of level warning with context: {user}'),
LogLevel::NOTICE => array(LogLevel::NOTICE, 'message of level notice with context: {user}'),
LogLevel::INFO => array(LogLevel::INFO, 'message of level info with context: {user}'),
LogLevel::DEBUG => array(LogLevel::DEBUG, 'message of level debug with context: {user}'),
);
}
/**
* @expectedException \Psr\Log\InvalidArgumentException
*/
public function testThrowsOnInvalidLevel()
{
$logger = $this->getLogger();
$logger->log('invalid level', 'Foo');
}
public function testContextReplacement()
{
$logger = $this->getLogger();
$logger->info('{Message {nothing} {user} {foo.bar} a}', array('user' => 'Bob', 'foo.bar' => 'Bar'));
$expected = array('info {Message {nothing} Bob Bar a}');
$this->assertEquals($expected, $this->getLogs());
}
public function testObjectCastToString()
{
if (method_exists($this, 'createPartialMock')) {
$dummy = $this->createPartialMock('Psr\Log\Test\DummyTest', array('__toString'));
} else {
$dummy = $this->getMock('Psr\Log\Test\DummyTest', array('__toString'));
}
$dummy->expects($this->once())
->method('__toString')
->will($this->returnValue('DUMMY'));
$this->getLogger()->warning($dummy);
$expected = array('warning DUMMY');
$this->assertEquals($expected, $this->getLogs());
}
public function testContextCanContainAnything()
{
$context = array(
'bool' => true,
'null' => null,
'string' => 'Foo',
'int' => 0,
'float' => 0.5,
'nested' => array('with object' => new DummyTest),
'object' => new \DateTime,
'resource' => fopen('php://memory', 'r'),
);
$this->getLogger()->warning('Crazy context data', $context);
$expected = array('warning Crazy context data');
$this->assertEquals($expected, $this->getLogs());
}
public function testContextExceptionKeyCanBeExceptionOrOtherValues()
{
$logger = $this->getLogger();
$logger->warning('Random message', array('exception' => 'oops'));
$logger->critical('Uncaught Exception!', array('exception' => new \LogicException('Fail')));
$expected = array(
'warning Random message',
'critical Uncaught Exception!'
);
$this->assertEquals($expected, $this->getLogs());
}
}
class DummyTest
{
public function __toString()
{
}
}

PSR Log

This repository holds all interfaces/classes/traits related to PSR-3.

Note that this is not a logger of its own. It is merely an interface that describes a logger. See the specification for more details.

Usage

If you need a logger, you can use the interface like this:

<?php

use Psr\Log\LoggerInterface;

class Foo
{
    private $logger;

    public function __construct(LoggerInterface $logger = null)
    {
        $this->logger = $logger;
    }

    public function doSomething()
    {
        if ($this->logger) {
            $this->logger->info('Doing work');
        }

        // do something useful
    }
}

You can then pick one of the implementations of the interface to get a logger.

If you want to implement the interface, you can require this package and implement Psr\Log\LoggerInterface in your code. Please read the specification text for details.

; This file is for unifying the coding style for different editors and IDEs.
; More information at http://editorconfig.org
root = true
[*]
charset = utf-8
indent_size = 4
indent_style = space
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
{
"name": "psr/simple-cache",
"description": "Common interfaces for simple caching",
"keywords": ["psr", "psr-16", "cache", "simple-cache", "caching"],
"license": "MIT",
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"require": {
"php": ">=5.3.0"
},
"autoload": {
"psr-4": {
"Psr\\SimpleCache\\": "src/"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
}
}

The MIT License (MIT)

Copyright (c) 2016 PHP Framework Interoperability Group

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

PHP FIG Simple Cache PSR

This repository holds all interfaces related to PSR-16.

Note that this is not a cache implementation of its own. It is merely an interface that describes a cache implementation. See the specification for more details.

You can find implementations of the specification by looking for packages providing the psr/simple-cache-implementation virtual package.

<?php
namespace Psr\SimpleCache;
/**
* Interface used for all types of exceptions thrown by the implementing library.
*/
interface CacheException
{
}
<?php
namespace Psr\SimpleCache;
interface CacheInterface
{
/**
* Fetches a value from the cache.
*
* @param string $key The unique key of this item in the cache.
* @param mixed $default Default value to return if the key does not exist.
*
* @return mixed The value of the item from the cache, or $default in case of cache miss.
*
* @throws \Psr\SimpleCache\InvalidArgumentException
* MUST be thrown if the $key string is not a legal value.
*/
public function get($key, $default = null);
/**
* Persists data in the cache, uniquely referenced by a key with an optional expiration TTL time.
*
* @param string $key The key of the item to store.
* @param mixed $value The value of the item to store, must be serializable.
* @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and
* the driver supports TTL then the library may set a default value
* for it or let the driver take care of that.
*
* @return bool True on success and false on failure.
*
* @throws \Psr\SimpleCache\InvalidArgumentException
* MUST be thrown if the $key string is not a legal value.
*/
public function set($key, $value, $ttl = null);
/**
* Delete an item from the cache by its unique key.
*
* @param string $key The unique cache key of the item to delete.
*
* @return bool True if the item was successfully removed. False if there was an error.
*
* @throws \Psr\SimpleCache\InvalidArgumentException
* MUST be thrown if the $key string is not a legal value.
*/
public function delete($key);
/**
* Wipes clean the entire cache's keys.
*
* @return bool True on success and false on failure.
*/
public function clear();
/**
* Obtains multiple cache items by their unique keys.
*
* @param iterable $keys A list of keys that can obtained in a single operation.
* @param mixed $default Default value to return for keys that do not exist.
*
* @return iterable A list of key => value pairs. Cache keys that do not exist or are stale will have $default as value.
*
* @throws \Psr\SimpleCache\InvalidArgumentException
* MUST be thrown if $keys is neither an array nor a Traversable,
* or if any of the $keys are not a legal value.
*/
public function getMultiple($keys, $default = null);
/**
* Persists a set of key => value pairs in the cache, with an optional TTL.
*
* @param iterable $values A list of key => value pairs for a multiple-set operation.
* @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and
* the driver supports TTL then the library may set a default value
* for it or let the driver take care of that.
*
* @return bool True on success and false on failure.
*
* @throws \Psr\SimpleCache\InvalidArgumentException
* MUST be thrown if $values is neither an array nor a Traversable,
* or if any of the $values are not a legal value.
*/
public function setMultiple($values, $ttl = null);
/**
* Deletes multiple cache items in a single operation.
*
* @param iterable $keys A list of string-based keys to be deleted.
*
* @return bool True if the items were successfully removed. False if there was an error.
*
* @throws \Psr\SimpleCache\InvalidArgumentException
* MUST be thrown if $keys is neither an array nor a Traversable,
* or if any of the $keys are not a legal value.
*/
public function deleteMultiple($keys);
/**
* Determines whether an item is present in the cache.
*
* NOTE: It is recommended that has() is only to be used for cache warming type purposes
* and not to be used within your live applications operations for get/set, as this method
* is subject to a race condition where your has() will return true and immediately after,
* another script can remove it making the state of your app out of date.
*
* @param string $key The cache item key.
*
* @return bool
*
* @throws \Psr\SimpleCache\InvalidArgumentException
* MUST be thrown if the $key string is not a legal value.
*/
public function has($key);
}
<?php
namespace Psr\SimpleCache;
/**
* Exception interface for invalid cache arguments.
*
* When an invalid argument is passed it must throw an exception which implements
* this interface
*/
interface InvalidArgumentException extends CacheException
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
use Psr\Cache\CacheItemInterface;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\ResettableInterface;
use Symfony\Component\Cache\Traits\AbstractTrait;
/**
* @author Nicolas Grekas <[email protected]>
*/
abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface, ResettableInterface
{
use AbstractTrait;
private static $apcuSupported;
private static $phpFilesSupported;
private $createCacheItem;
private $mergeByLifetime;
protected function __construct(string $namespace = '', int $defaultLifetime = 0)
{
$this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).':';
if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) {
throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s")', $this->maxIdLength - 24, \strlen($namespace), $namespace));
}
$this->createCacheItem = \Closure::bind(
function ($key, $value, $isHit) use ($defaultLifetime) {
$item = new CacheItem();
$item->key = $key;
$item->value = $value;
$item->isHit = $isHit;
$item->defaultLifetime = $defaultLifetime;
return $item;
},
null,
CacheItem::class
);
$getId = \Closure::fromCallable(array($this, 'getId'));
$this->mergeByLifetime = \Closure::bind(
function ($deferred, $namespace, &$expiredIds) use ($getId) {
$byLifetime = array();
$now = time();
$expiredIds = array();
foreach ($deferred as $key => $item) {
$key = (string) $key;
if (null === $item->expiry) {
$byLifetime[0 < $item->defaultLifetime ? $item->defaultLifetime : 0][$getId($key)] = $item->value;
} elseif ($item->expiry > $now) {
$byLifetime[$item->expiry - $now][$getId($key)] = $item->value;
} else {
$expiredIds[] = $getId($key);
}
}
return $byLifetime;
},
null,
CacheItem::class
);
}
/**
* @param string $namespace
* @param int $defaultLifetime
* @param string $version
* @param string $directory
* @param LoggerInterface|null $logger
*
* @return AdapterInterface
*/
public static function createSystemCache($namespace, $defaultLifetime, $version, $directory, LoggerInterface $logger = null)
{
if (null === self::$apcuSupported) {
self::$apcuSupported = ApcuAdapter::isSupported();
}
if (!self::$apcuSupported && null === self::$phpFilesSupported) {
self::$phpFilesSupported = PhpFilesAdapter::isSupported();
}
if (self::$phpFilesSupported) {
$opcache = new PhpFilesAdapter($namespace, $defaultLifetime, $directory);
if (null !== $logger) {
$opcache->setLogger($logger);
}
return $opcache;
}
$fs = new FilesystemAdapter($namespace, $defaultLifetime, $directory);
if (null !== $logger) {
$fs->setLogger($logger);
}
if (!self::$apcuSupported) {
return $fs;
}
$apcu = new ApcuAdapter($namespace, (int) $defaultLifetime / 5, $version);
if ('cli' === \PHP_SAPI && !ini_get('apc.enable_cli')) {
$apcu->setLogger(new NullLogger());
} elseif (null !== $logger) {
$apcu->setLogger($logger);
}
return new ChainAdapter(array($apcu, $fs));
}
public static function createConnection($dsn, array $options = array())
{
if (!\is_string($dsn)) {
throw new InvalidArgumentException(sprintf('The %s() method expect argument #1 to be string, %s given.', __METHOD__, \gettype($dsn)));
}
if (0 === strpos($dsn, 'redis://')) {
return RedisAdapter::createConnection($dsn, $options);
}
if (0 === strpos($dsn, 'memcached://')) {
return MemcachedAdapter::createConnection($dsn, $options);
}
throw new InvalidArgumentException(sprintf('Unsupported DSN: %s.', $dsn));
}
/**
* {@inheritdoc}
*/
public function getItem($key)
{
if ($this->deferred) {
$this->commit();
}
$id = $this->getId($key);
$f = $this->createCacheItem;
$isHit = false;
$value = null;
try {
foreach ($this->doFetch(array($id)) as $value) {
$isHit = true;
}
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to fetch key "{key}"', array('key' => $key, 'exception' => $e));
}
return $f($key, $value, $isHit);
}
/**
* {@inheritdoc}
*/
public function getItems(array $keys = array())
{
if ($this->deferred) {
$this->commit();
}
$ids = array();
foreach ($keys as $key) {
$ids[] = $this->getId($key);
}
try {
$items = $this->doFetch($ids);
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to fetch requested items', array('keys' => $keys, 'exception' => $e));
$items = array();
}
$ids = array_combine($ids, $keys);
return $this->generateItems($items, $ids);
}
/**
* {@inheritdoc}
*/
public function save(CacheItemInterface $item)
{
if (!$item instanceof CacheItem) {
return false;
}
$this->deferred[$item->getKey()] = $item;
return $this->commit();
}
/**
* {@inheritdoc}
*/
public function saveDeferred(CacheItemInterface $item)
{
if (!$item instanceof CacheItem) {
return false;
}
$this->deferred[$item->getKey()] = $item;
return true;
}
/**
* {@inheritdoc}
*/
public function commit()
{
$ok = true;
$byLifetime = $this->mergeByLifetime;
$byLifetime = $byLifetime($this->deferred, $this->namespace, $expiredIds);
$retry = $this->deferred = array();
if ($expiredIds) {
$this->doDelete($expiredIds);
}
foreach ($byLifetime as $lifetime => $values) {
try {
$e = $this->doSave($values, $lifetime);
} catch (\Exception $e) {
}
if (true === $e || array() === $e) {
continue;
}
if (\is_array($e) || 1 === \count($values)) {
foreach (\is_array($e) ? $e : array_keys($values) as $id) {
$ok = false;
$v = $values[$id];
$type = \is_object($v) ? \get_class($v) : \gettype($v);
CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', array('key' => substr($id, \strlen($this->namespace)), 'type' => $type, 'exception' => $e instanceof \Exception ? $e : null));
}
} else {
foreach ($values as $id => $v) {
$retry[$lifetime][] = $id;
}
}
}
// When bulk-save failed, retry each item individually
foreach ($retry as $lifetime => $ids) {
foreach ($ids as $id) {
try {
$v = $byLifetime[$lifetime][$id];
$e = $this->doSave(array($id => $v), $lifetime);
} catch (\Exception $e) {
}
if (true === $e || array() === $e) {
continue;
}
$ok = false;
$type = \is_object($v) ? \get_class($v) : \gettype($v);
CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', array('key' => substr($id, \strlen($this->namespace)), 'type' => $type, 'exception' => $e instanceof \Exception ? $e : null));
}
}
return $ok;
}
public function __destruct()
{
if ($this->deferred) {
$this->commit();
}
}
private function generateItems($items, &$keys)
{
$f = $this->createCacheItem;
try {
foreach ($items as $id => $value) {
if (!isset($keys[$id])) {
$id = key($keys);
}
$key = $keys[$id];
unset($keys[$id]);
yield $key => $f($key, $value, true);
}
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to fetch requested items', array('keys' => array_values($keys), 'exception' => $e));
}
foreach ($keys as $key) {
yield $key => $f($key, null, false);
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\CacheItem;
/**
* Interface for adapters managing instances of Symfony's CacheItem.
*
* @author Kévin Dunglas <[email protected]>
*/
interface AdapterInterface extends CacheItemPoolInterface
{
/**
* {@inheritdoc}
*
* @return CacheItem
*/
public function getItem($key);
/**
* {@inheritdoc}
*
* @return \Traversable|CacheItem[]
*/
public function getItems(array $keys = array());
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
use Symfony\Component\Cache\Traits\ApcuTrait;
class ApcuAdapter extends AbstractAdapter
{
use ApcuTrait;
/**
* @throws CacheException if APCu is not enabled
*/
public function __construct(string $namespace = '', int $defaultLifetime = 0, string $version = null)
{
$this->init($namespace, $defaultLifetime, $version);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
use Psr\Cache\CacheItemInterface;
use Psr\Log\LoggerAwareInterface;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\ResettableInterface;
use Symfony\Component\Cache\Traits\ArrayTrait;
/**
* @author Nicolas Grekas <[email protected]>
*/
class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, ResettableInterface
{
use ArrayTrait;
private $createCacheItem;
/**
* @param int $defaultLifetime
* @param bool $storeSerialized Disabling serialization can lead to cache corruptions when storing mutable values but increases performance otherwise
*/
public function __construct(int $defaultLifetime = 0, bool $storeSerialized = true)
{
$this->storeSerialized = $storeSerialized;
$this->createCacheItem = \Closure::bind(
function ($key, $value, $isHit) use ($defaultLifetime) {
$item = new CacheItem();
$item->key = $key;
$item->value = $value;
$item->isHit = $isHit;
$item->defaultLifetime = $defaultLifetime;
return $item;
},
null,
CacheItem::class
);
}
/**
* {@inheritdoc}
*/
public function getItem($key)
{
$isHit = $this->hasItem($key);
try {
if (!$isHit) {
$this->values[$key] = $value = null;
} elseif (!$this->storeSerialized) {
$value = $this->values[$key];
} elseif ('b:0;' === $value = $this->values[$key]) {
$value = false;
} elseif (false === $value = unserialize($value)) {
$this->values[$key] = $value = null;
$isHit = false;
}
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to unserialize key "{key}"', array('key' => $key, 'exception' => $e));
$this->values[$key] = $value = null;
$isHit = false;
}
$f = $this->createCacheItem;
return $f($key, $value, $isHit);
}
/**
* {@inheritdoc}
*/
public function getItems(array $keys = array())
{
foreach ($keys as $key) {
CacheItem::validateKey($key);
}
return $this->generateItems($keys, time(), $this->createCacheItem);
}
/**
* {@inheritdoc}
*/
public function deleteItems(array $keys)
{
foreach ($keys as $key) {
$this->deleteItem($key);
}
return true;
}
/**
* {@inheritdoc}
*/
public function save(CacheItemInterface $item)
{
if (!$item instanceof CacheItem) {
return false;
}
$item = (array) $item;
$key = $item["\0*\0key"];
$value = $item["\0*\0value"];
$expiry = $item["\0*\0expiry"];
if (null !== $expiry && $expiry <= time()) {
$this->deleteItem($key);
return true;
}
if ($this->storeSerialized) {
try {
$value = serialize($value);
} catch (\Exception $e) {
$type = \is_object($value) ? \get_class($value) : \gettype($value);
CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', array('key' => $key, 'type' => $type, 'exception' => $e));
return false;
}
}
if (null === $expiry && 0 < $item["\0*\0defaultLifetime"]) {
$expiry = time() + $item["\0*\0defaultLifetime"];
}
$this->values[$key] = $value;
$this->expiries[$key] = null !== $expiry ? $expiry : PHP_INT_MAX;
return true;
}
/**
* {@inheritdoc}
*/
public function saveDeferred(CacheItemInterface $item)
{
return $this->save($item);
}
/**
* {@inheritdoc}
*/
public function commit()
{
return true;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\ResettableInterface;
/**
* Chains several adapters together.
*
* Cached items are fetched from the first adapter having them in its data store.
* They are saved and deleted in all adapters at once.
*
* @author Kévin Dunglas <[email protected]>
*/
class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableInterface
{
private $adapters = array();
private $adapterCount;
private $syncItem;
/**
* @param CacheItemPoolInterface[] $adapters The ordered list of adapters used to fetch cached items
* @param int $defaultLifetime The default lifetime of items propagated from lower adapters to upper ones
*/
public function __construct(array $adapters, int $defaultLifetime = 0)
{
if (!$adapters) {
throw new InvalidArgumentException('At least one adapter must be specified.');
}
foreach ($adapters as $adapter) {
if (!$adapter instanceof CacheItemPoolInterface) {
throw new InvalidArgumentException(sprintf('The class "%s" does not implement the "%s" interface.', \get_class($adapter), CacheItemPoolInterface::class));
}
if ($adapter instanceof AdapterInterface) {
$this->adapters[] = $adapter;
} else {
$this->adapters[] = new ProxyAdapter($adapter);
}
}
$this->adapterCount = \count($this->adapters);
$this->syncItem = \Closure::bind(
function ($sourceItem, $item) use ($defaultLifetime) {
$item->value = $sourceItem->value;
$item->expiry = $sourceItem->expiry;
$item->isHit = $sourceItem->isHit;
if (0 < $sourceItem->defaultLifetime && $sourceItem->defaultLifetime < $defaultLifetime) {
$defaultLifetime = $sourceItem->defaultLifetime;
}
if (0 < $defaultLifetime && ($item->defaultLifetime <= 0 || $defaultLifetime < $item->defaultLifetime)) {
$item->defaultLifetime = $defaultLifetime;
}
return $item;
},
null,
CacheItem::class
);
}
/**
* {@inheritdoc}
*/
public function getItem($key)
{
$syncItem = $this->syncItem;
$misses = array();
foreach ($this->adapters as $i => $adapter) {
$item = $adapter->getItem($key);
if ($item->isHit()) {
while (0 <= --$i) {
$this->adapters[$i]->save($syncItem($item, $misses[$i]));
}
return $item;
}
$misses[$i] = $item;
}
return $item;
}
/**
* {@inheritdoc}
*/
public function getItems(array $keys = array())
{
return $this->generateItems($this->adapters[0]->getItems($keys), 0);
}
private function generateItems($items, $adapterIndex)
{
$missing = array();
$misses = array();
$nextAdapterIndex = $adapterIndex + 1;
$nextAdapter = isset($this->adapters[$nextAdapterIndex]) ? $this->adapters[$nextAdapterIndex] : null;
foreach ($items as $k => $item) {
if (!$nextAdapter || $item->isHit()) {
yield $k => $item;
} else {
$missing[] = $k;
$misses[$k] = $item;
}
}
if ($missing) {
$syncItem = $this->syncItem;
$adapter = $this->adapters[$adapterIndex];
$items = $this->generateItems($nextAdapter->getItems($missing), $nextAdapterIndex);
foreach ($items as $k => $item) {
if ($item->isHit()) {
$adapter->save($syncItem($item, $misses[$k]));
}
yield $k => $item;
}
}
}
/**
* {@inheritdoc}
*/
public function hasItem($key)
{
foreach ($this->adapters as $adapter) {
if ($adapter->hasItem($key)) {
return true;
}
}
return false;
}
/**
* {@inheritdoc}
*/
public function clear()
{
$cleared = true;
$i = $this->adapterCount;
while ($i--) {
$cleared = $this->adapters[$i]->clear() && $cleared;
}
return $cleared;
}
/**
* {@inheritdoc}
*/
public function deleteItem($key)
{
$deleted = true;
$i = $this->adapterCount;
while ($i--) {
$deleted = $this->adapters[$i]->deleteItem($key) && $deleted;
}
return $deleted;
}
/**
* {@inheritdoc}
*/
public function deleteItems(array $keys)
{
$deleted = true;
$i = $this->adapterCount;
while ($i--) {
$deleted = $this->adapters[$i]->deleteItems($keys) && $deleted;
}
return $deleted;
}
/**
* {@inheritdoc}
*/
public function save(CacheItemInterface $item)
{
$saved = true;
$i = $this->adapterCount;
while ($i--) {
$saved = $this->adapters[$i]->save($item) && $saved;
}
return $saved;
}
/**
* {@inheritdoc}
*/
public function saveDeferred(CacheItemInterface $item)
{
$saved = true;
$i = $this->adapterCount;
while ($i--) {
$saved = $this->adapters[$i]->saveDeferred($item) && $saved;
}
return $saved;
}
/**
* {@inheritdoc}
*/
public function commit()
{
$committed = true;
$i = $this->adapterCount;
while ($i--) {
$committed = $this->adapters[$i]->commit() && $committed;
}
return $committed;
}
/**
* {@inheritdoc}
*/
public function prune()
{
$pruned = true;
foreach ($this->adapters as $adapter) {
if ($adapter instanceof PruneableInterface) {
$pruned = $adapter->prune() && $pruned;
}
}
return $pruned;
}
/**
* {@inheritdoc}
*/
public function reset()
{
foreach ($this->adapters as $adapter) {
if ($adapter instanceof ResettableInterface) {
$adapter->reset();
}
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
use Doctrine\Common\Cache\CacheProvider;
use Symfony\Component\Cache\Traits\DoctrineTrait;
class DoctrineAdapter extends AbstractAdapter
{
use DoctrineTrait;
public function __construct(CacheProvider $provider, string $namespace = '', int $defaultLifetime = 0)
{
parent::__construct('', $defaultLifetime);
$this->provider = $provider;
$provider->setNamespace($namespace);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\Traits\FilesystemTrait;
class FilesystemAdapter extends AbstractAdapter implements PruneableInterface
{
use FilesystemTrait;
public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null)
{
parent::__construct('', $defaultLifetime);
$this->init($namespace, $directory);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
use Symfony\Component\Cache\Traits\MemcachedTrait;
class MemcachedAdapter extends AbstractAdapter
{
use MemcachedTrait;
protected $maxIdLength = 250;
/**
* Using a MemcachedAdapter with a TagAwareAdapter for storing tags is discouraged.
* Using a RedisAdapter is recommended instead. If you cannot do otherwise, be aware that:
* - the Memcached::OPT_BINARY_PROTOCOL must be enabled
* (that's the default when using MemcachedAdapter::createConnection());
* - tags eviction by Memcached's LRU algorithm will break by-tags invalidation;
* your Memcached memory should be large enough to never trigger LRU.
*
* Using a MemcachedAdapter as a pure items store is fine.
*/
public function __construct(\Memcached $client, string $namespace = '', int $defaultLifetime = 0)
{
$this->init($client, $namespace, $defaultLifetime);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
use Psr\Cache\CacheItemInterface;
use Symfony\Component\Cache\CacheItem;
/**
* @author Titouan Galopin <[email protected]>
*/
class NullAdapter implements AdapterInterface
{
private $createCacheItem;
public function __construct()
{
$this->createCacheItem = \Closure::bind(
function ($key) {
$item = new CacheItem();
$item->key = $key;
$item->isHit = false;
return $item;
},
$this,
CacheItem::class
);
}
/**
* {@inheritdoc}
*/
public function getItem($key)
{
$f = $this->createCacheItem;
return $f($key);
}
/**
* {@inheritdoc}
*/
public function getItems(array $keys = array())
{
return $this->generateItems($keys);
}
/**
* {@inheritdoc}
*/
public function hasItem($key)
{
return false;
}
/**
* {@inheritdoc}
*/
public function clear()
{
return true;
}
/**
* {@inheritdoc}
*/
public function deleteItem($key)
{
return true;
}
/**
* {@inheritdoc}
*/
public function deleteItems(array $keys)
{
return true;
}
/**
* {@inheritdoc}
*/
public function save(CacheItemInterface $item)
{
return false;
}
/**
* {@inheritdoc}
*/
public function saveDeferred(CacheItemInterface $item)
{
return false;
}
/**
* {@inheritdoc}
*/
public function commit()
{
return false;
}
private function generateItems(array $keys)
{
$f = $this->createCacheItem;
foreach ($keys as $key) {
yield $key => $f($key);
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
use Doctrine\DBAL\Connection;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\Traits\PdoTrait;
class PdoAdapter extends AbstractAdapter implements PruneableInterface
{
use PdoTrait;
protected $maxIdLength = 255;
/**
* You can either pass an existing database connection as PDO instance or
* a Doctrine DBAL Connection or a DSN string that will be used to
* lazy-connect to the database when the cache is actually used.
*
* List of available options:
* * db_table: The name of the table [default: cache_items]
* * db_id_col: The column where to store the cache id [default: item_id]
* * db_data_col: The column where to store the cache data [default: item_data]
* * db_lifetime_col: The column where to store the lifetime [default: item_lifetime]
* * db_time_col: The column where to store the timestamp [default: item_time]
* * db_username: The username when lazy-connect [default: '']
* * db_password: The password when lazy-connect [default: '']
* * db_connection_options: An array of driver-specific connection options [default: array()]
*
* @param \PDO|Connection|string $connOrDsn a \PDO or Connection instance or DSN string or null
*
* @throws InvalidArgumentException When first argument is not PDO nor Connection nor string
* @throws InvalidArgumentException When PDO error mode is not PDO::ERRMODE_EXCEPTION
* @throws InvalidArgumentException When namespace contains invalid characters
*/
public function __construct($connOrDsn, string $namespace = '', int $defaultLifetime = 0, array $options = array())
{
$this->init($connOrDsn, $namespace, $defaultLifetime, $options);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\ResettableInterface;
use Symfony\Component\Cache\Traits\PhpArrayTrait;
/**
* Caches items at warm up time using a PHP array that is stored in shared memory by OPCache since PHP 7.0.
* Warmed up items are read-only and run-time discovered items are cached using a fallback adapter.
*
* @author Titouan Galopin <[email protected]>
* @author Nicolas Grekas <[email protected]>
*/
class PhpArrayAdapter implements AdapterInterface, PruneableInterface, ResettableInterface
{
use PhpArrayTrait;
private $createCacheItem;
/**
* @param string $file The PHP file were values are cached
* @param AdapterInterface $fallbackPool A pool to fallback on when an item is not hit
*/
public function __construct(string $file, AdapterInterface $fallbackPool)
{
$this->file = $file;
$this->pool = $fallbackPool;
$this->zendDetectUnicode = ini_get('zend.detect_unicode');
$this->createCacheItem = \Closure::bind(
function ($key, $value, $isHit) {
$item = new CacheItem();
$item->key = $key;
$item->value = $value;
$item->isHit = $isHit;
return $item;
},
null,
CacheItem::class
);
}
/**
* This adapter takes advantage of how PHP stores arrays in its latest versions.
*
* @param string $file The PHP file were values are cached
* @param CacheItemPoolInterface $fallbackPool Fallback when opcache is disabled
*
* @return CacheItemPoolInterface
*/
public static function create($file, CacheItemPoolInterface $fallbackPool)
{
// Shared memory is available in PHP 7.0+ with OPCache enabled
if (ini_get('opcache.enable')) {
if (!$fallbackPool instanceof AdapterInterface) {
$fallbackPool = new ProxyAdapter($fallbackPool);
}
return new static($file, $fallbackPool);
}
return $fallbackPool;
}
/**
* {@inheritdoc}
*/
public function getItem($key)
{
if (!\is_string($key)) {
throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
}
if (null === $this->values) {
$this->initialize();
}
if (!isset($this->values[$key])) {
return $this->pool->getItem($key);
}
$value = $this->values[$key];
$isHit = true;
if ('N;' === $value) {
$value = null;
} elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
try {
$value = unserialize($value);
} catch (\Throwable $e) {
$value = null;
$isHit = false;
}
}
$f = $this->createCacheItem;
return $f($key, $value, $isHit);
}
/**
* {@inheritdoc}
*/
public function getItems(array $keys = array())
{
foreach ($keys as $key) {
if (!\is_string($key)) {
throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
}
}
if (null === $this->values) {
$this->initialize();
}
return $this->generateItems($keys);
}
/**
* {@inheritdoc}
*/
public function hasItem($key)
{
if (!\is_string($key)) {
throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
}
if (null === $this->values) {
$this->initialize();
}
return isset($this->values[$key]) || $this->pool->hasItem($key);
}
/**
* {@inheritdoc}
*/
public function deleteItem($key)
{
if (!\is_string($key)) {
throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
}
if (null === $this->values) {
$this->initialize();
}
return !isset($this->values[$key]) && $this->pool->deleteItem($key);
}
/**
* {@inheritdoc}
*/
public function deleteItems(array $keys)
{
$deleted = true;
$fallbackKeys = array();
foreach ($keys as $key) {
if (!\is_string($key)) {
throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
}
if (isset($this->values[$key])) {
$deleted = false;
} else {
$fallbackKeys[] = $key;
}
}
if (null === $this->values) {
$this->initialize();
}
if ($fallbackKeys) {
$deleted = $this->pool->deleteItems($fallbackKeys) && $deleted;
}
return $deleted;
}
/**
* {@inheritdoc}
*/
public function save(CacheItemInterface $item)
{
if (null === $this->values) {
$this->initialize();
}
return !isset($this->values[$item->getKey()]) && $this->pool->save($item);
}
/**
* {@inheritdoc}
*/
public function saveDeferred(CacheItemInterface $item)
{
if (null === $this->values) {
$this->initialize();
}
return !isset($this->values[$item->getKey()]) && $this->pool->saveDeferred($item);
}
/**
* {@inheritdoc}
*/
public function commit()
{
return $this->pool->commit();
}
private function generateItems(array $keys): \Generator
{
$f = $this->createCacheItem;
$fallbackKeys = array();
foreach ($keys as $key) {
if (isset($this->values[$key])) {
$value = $this->values[$key];
if ('N;' === $value) {
yield $key => $f($key, null, true);
} elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
try {
yield $key => $f($key, unserialize($value), true);
} catch (\Throwable $e) {
yield $key => $f($key, null, false);
}
} else {
yield $key => $f($key, $value, true);
}
} else {
$fallbackKeys[] = $key;
}
}
if ($fallbackKeys) {
foreach ($this->pool->getItems($fallbackKeys) as $key => $item) {
yield $key => $item;
}
}
}
/**
* @throws \ReflectionException When $class is not found and is required
*
* @internal
*/
public static function throwOnRequiredClass($class)
{
$e = new \ReflectionException("Class $class does not exist");
$trace = $e->getTrace();
$autoloadFrame = array(
'function' => 'spl_autoload_call',
'args' => array($class),
);
$i = 1 + array_search($autoloadFrame, $trace, true);
if (isset($trace[$i]['function']) && !isset($trace[$i]['class'])) {
switch ($trace[$i]['function']) {
case 'get_class_methods':
case 'get_class_vars':
case 'get_parent_class':
case 'is_a':
case 'is_subclass_of':
case 'class_exists':
case 'class_implements':
case 'class_parents':
case 'trait_exists':
case 'defined':
case 'interface_exists':
case 'method_exists':
case 'property_exists':
case 'is_callable':
return;
}
}
throw $e;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
use Symfony\Component\Cache\Exception\CacheException;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\Traits\PhpFilesTrait;
class PhpFilesAdapter extends AbstractAdapter implements PruneableInterface
{
use PhpFilesTrait;
/**
* @throws CacheException if OPcache is not enabled
*/
public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null)
{
if (!static::isSupported()) {
throw new CacheException('OPcache is not enabled');
}
parent::__construct('', $defaultLifetime);
$this->init($namespace, $directory);
$e = new \Exception();
$this->includeHandler = function () use ($e) { throw $e; };
$this->zendDetectUnicode = ini_get('zend.detect_unicode');
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\ResettableInterface;
use Symfony\Component\Cache\Traits\ProxyTrait;
/**
* @author Nicolas Grekas <[email protected]>
*/
class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableInterface
{
use ProxyTrait;
private $namespace;
private $namespaceLen;
private $createCacheItem;
private $poolHash;
public function __construct(CacheItemPoolInterface $pool, string $namespace = '', int $defaultLifetime = 0)
{
$this->pool = $pool;
$this->poolHash = $poolHash = spl_object_hash($pool);
$this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace);
$this->namespaceLen = \strlen($namespace);
$this->createCacheItem = \Closure::bind(
function ($key, $innerItem) use ($defaultLifetime, $poolHash) {
$item = new CacheItem();
$item->key = $key;
$item->value = $innerItem->get();
$item->isHit = $innerItem->isHit();
$item->defaultLifetime = $defaultLifetime;
$item->innerItem = $innerItem;
$item->poolHash = $poolHash;
$innerItem->set(null);
return $item;
},
null,
CacheItem::class
);
}
/**
* {@inheritdoc}
*/
public function getItem($key)
{
$f = $this->createCacheItem;
$item = $this->pool->getItem($this->getId($key));
return $f($key, $item);
}
/**
* {@inheritdoc}
*/
public function getItems(array $keys = array())
{
if ($this->namespaceLen) {
foreach ($keys as $i => $key) {
$keys[$i] = $this->getId($key);
}
}
return $this->generateItems($this->pool->getItems($keys));
}
/**
* {@inheritdoc}
*/
public function hasItem($key)
{
return $this->pool->hasItem($this->getId($key));
}
/**
* {@inheritdoc}
*/
public function clear()
{
return $this->pool->clear();
}
/**
* {@inheritdoc}
*/
public function deleteItem($key)
{
return $this->pool->deleteItem($this->getId($key));
}
/**
* {@inheritdoc}
*/
public function deleteItems(array $keys)
{
if ($this->namespaceLen) {
foreach ($keys as $i => $key) {
$keys[$i] = $this->getId($key);
}
}
return $this->pool->deleteItems($keys);
}
/**
* {@inheritdoc}
*/
public function save(CacheItemInterface $item)
{
return $this->doSave($item, __FUNCTION__);
}
/**
* {@inheritdoc}
*/
public function saveDeferred(CacheItemInterface $item)
{
return $this->doSave($item, __FUNCTION__);
}
/**
* {@inheritdoc}
*/
public function commit()
{
return $this->pool->commit();
}
private function doSave(CacheItemInterface $item, $method)
{
if (!$item instanceof CacheItem) {
return false;
}
$item = (array) $item;
$expiry = $item["\0*\0expiry"];
if (null === $expiry && 0 < $item["\0*\0defaultLifetime"]) {
$expiry = time() + $item["\0*\0defaultLifetime"];
}
$innerItem = $item["\0*\0poolHash"] === $this->poolHash ? $item["\0*\0innerItem"] : $this->pool->getItem($this->namespace.$item["\0*\0key"]);
$innerItem->set($item["\0*\0value"]);
$innerItem->expiresAt(null !== $expiry ? \DateTime::createFromFormat('U', $expiry) : null);
return $this->pool->$method($innerItem);
}
private function generateItems($items)
{
$f = $this->createCacheItem;
foreach ($items as $key => $item) {
if ($this->namespaceLen) {
$key = substr($key, $this->namespaceLen);
}
yield $key => $f($key, $item);
}
}
private function getId($key)
{
CacheItem::validateKey($key);
return $this->namespace.$key;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
use Symfony\Component\Cache\Traits\RedisTrait;
class RedisAdapter extends AbstractAdapter
{
use RedisTrait;
/**
* @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient The redis client
* @param string $namespace The default namespace
* @param int $defaultLifetime The default lifetime
*/
public function __construct($redisClient, string $namespace = '', int $defaultLifetime = 0)
{
$this->init($redisClient, $namespace, $defaultLifetime);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
use Psr\SimpleCache\CacheInterface;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\ResettableInterface;
use Symfony\Component\Cache\Traits\ProxyTrait;
/**
* @author Nicolas Grekas <[email protected]>
*/
class SimpleCacheAdapter extends AbstractAdapter implements PruneableInterface, ResettableInterface
{
use ProxyTrait;
private $miss;
public function __construct(CacheInterface $pool, string $namespace = '', int $defaultLifetime = 0)
{
parent::__construct($namespace, $defaultLifetime);
$this->pool = $pool;
$this->miss = new \stdClass();
}
/**
* {@inheritdoc}
*/
protected function doFetch(array $ids)
{
foreach ($this->pool->getMultiple($ids, $this->miss) as $key => $value) {
if ($this->miss !== $value) {
yield $key => $value;
}
}
}
/**
* {@inheritdoc}
*/
protected function doHave($id)
{
return $this->pool->has($id);
}
/**
* {@inheritdoc}
*/
protected function doClear($namespace)
{
return $this->pool->clear();
}
/**
* {@inheritdoc}
*/
protected function doDelete(array $ids)
{
return $this->pool->deleteMultiple($ids);
}
/**
* {@inheritdoc}
*/
protected function doSave(array $values, $lifetime)
{
return $this->pool->setMultiple($values, 0 === $lifetime ? null : $lifetime);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\InvalidArgumentException;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\ResettableInterface;
use Symfony\Component\Cache\Traits\ProxyTrait;
/**
* @author Nicolas Grekas <[email protected]>
*/
class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, ResettableInterface
{
const TAGS_PREFIX = "\0tags\0";
use ProxyTrait;
private $deferred = array();
private $createCacheItem;
private $setCacheItemTags;
private $getTagsByKey;
private $invalidateTags;
private $tags;
private $knownTagVersions = array();
private $knownTagVersionsTtl;
public function __construct(AdapterInterface $itemsPool, AdapterInterface $tagsPool = null, float $knownTagVersionsTtl = 0.15)
{
$this->pool = $itemsPool;
$this->tags = $tagsPool ?: $itemsPool;
$this->knownTagVersionsTtl = $knownTagVersionsTtl;
$this->createCacheItem = \Closure::bind(
function ($key, $value, CacheItem $protoItem) {
$item = new CacheItem();
$item->key = $key;
$item->value = $value;
$item->defaultLifetime = $protoItem->defaultLifetime;
$item->expiry = $protoItem->expiry;
$item->innerItem = $protoItem->innerItem;
$item->poolHash = $protoItem->poolHash;
return $item;
},
null,
CacheItem::class
);
$this->setCacheItemTags = \Closure::bind(
function (CacheItem $item, $key, array &$itemTags) {
if (!$item->isHit) {
return $item;
}
if (isset($itemTags[$key])) {
foreach ($itemTags[$key] as $tag => $version) {
$item->prevTags[$tag] = $tag;
}
unset($itemTags[$key]);
} else {
$item->value = null;
$item->isHit = false;
}
return $item;
},
null,
CacheItem::class
);
$this->getTagsByKey = \Closure::bind(
function ($deferred) {
$tagsByKey = array();
foreach ($deferred as $key => $item) {
$tagsByKey[$key] = $item->tags;
}
return $tagsByKey;
},
null,
CacheItem::class
);
$this->invalidateTags = \Closure::bind(
function (AdapterInterface $tagsAdapter, array $tags) {
foreach ($tags as $v) {
$v->defaultLifetime = 0;
$v->expiry = null;
$tagsAdapter->saveDeferred($v);
}
return $tagsAdapter->commit();
},
null,
CacheItem::class
);
}
/**
* {@inheritdoc}
*/
public function invalidateTags(array $tags)
{
$ok = true;
$tagsByKey = array();
$invalidatedTags = array();
foreach ($tags as $tag) {
CacheItem::validateKey($tag);
$invalidatedTags[$tag] = 0;
}
if ($this->deferred) {
$items = $this->deferred;
foreach ($items as $key => $item) {
if (!$this->pool->saveDeferred($item)) {
unset($this->deferred[$key]);
$ok = false;
}
}
$f = $this->getTagsByKey;
$tagsByKey = $f($items);
$this->deferred = array();
}
$tagVersions = $this->getTagVersions($tagsByKey, $invalidatedTags);
$f = $this->createCacheItem;
foreach ($tagsByKey as $key => $tags) {
$this->pool->saveDeferred($f(static::TAGS_PREFIX.$key, array_intersect_key($tagVersions, $tags), $items[$key]));
}
$ok = $this->pool->commit() && $ok;
if ($invalidatedTags) {
$f = $this->invalidateTags;
$ok = $f($this->tags, $invalidatedTags) && $ok;
}
return $ok;
}
/**
* {@inheritdoc}
*/
public function hasItem($key)
{
if ($this->deferred) {
$this->commit();
}
if (!$this->pool->hasItem($key)) {
return false;
}
if (!$itemTags = $this->pool->getItem(static::TAGS_PREFIX.$key)->get()) {
return true;
}
foreach ($this->getTagVersions(array($itemTags)) as $tag => $version) {
if ($itemTags[$tag] !== $version && 1 !== $itemTags[$tag] - $version) {
return false;
}
}
return true;
}
/**
* {@inheritdoc}
*/
public function getItem($key)
{
foreach ($this->getItems(array($key)) as $item) {
return $item;
}
}
/**
* {@inheritdoc}
*/
public function getItems(array $keys = array())
{
if ($this->deferred) {
$this->commit();
}
$tagKeys = array();
foreach ($keys as $key) {
if ('' !== $key && \is_string($key)) {
$key = static::TAGS_PREFIX.$key;
$tagKeys[$key] = $key;
}
}
try {
$items = $this->pool->getItems($tagKeys + $keys);
} catch (InvalidArgumentException $e) {
$this->pool->getItems($keys); // Should throw an exception
throw $e;
}
return $this->generateItems($items, $tagKeys);
}
/**
* {@inheritdoc}
*/
public function clear()
{
$this->deferred = array();
return $this->pool->clear();
}
/**
* {@inheritdoc}
*/
public function deleteItem($key)
{
return $this->deleteItems(array($key));
}
/**
* {@inheritdoc}
*/
public function deleteItems(array $keys)
{
foreach ($keys as $key) {
if ('' !== $key && \is_string($key)) {
$keys[] = static::TAGS_PREFIX.$key;
}
}
return $this->pool->deleteItems($keys);
}
/**
* {@inheritdoc}
*/
public function save(CacheItemInterface $item)
{
if (!$item instanceof CacheItem) {
return false;
}
$this->deferred[$item->getKey()] = $item;
return $this->commit();
}
/**
* {@inheritdoc}
*/
public function saveDeferred(CacheItemInterface $item)
{
if (!$item instanceof CacheItem) {
return false;
}
$this->deferred[$item->getKey()] = $item;
return true;
}
/**
* {@inheritdoc}
*/
public function commit()
{
return $this->invalidateTags(array());
}
public function __destruct()
{
$this->commit();
}
private function generateItems($items, array $tagKeys)
{
$bufferedItems = $itemTags = array();
$f = $this->setCacheItemTags;
foreach ($items as $key => $item) {
if (!$tagKeys) {
yield $key => $f($item, static::TAGS_PREFIX.$key, $itemTags);
continue;
}
if (!isset($tagKeys[$key])) {
$bufferedItems[$key] = $item;
continue;
}
unset($tagKeys[$key]);
$itemTags[$key] = $item->get() ?: array();
if (!$tagKeys) {
$tagVersions = $this->getTagVersions($itemTags);
foreach ($itemTags as $key => $tags) {
foreach ($tags as $tag => $version) {
if ($tagVersions[$tag] !== $version && 1 !== $version - $tagVersions[$tag]) {
unset($itemTags[$key]);
continue 2;
}
}
}
$tagVersions = $tagKeys = null;
foreach ($bufferedItems as $key => $item) {
yield $key => $f($item, static::TAGS_PREFIX.$key, $itemTags);
}
$bufferedItems = null;
}
}
}
private function getTagVersions(array $tagsByKey, array &$invalidatedTags = array())
{
$tagVersions = $invalidatedTags;
foreach ($tagsByKey as $tags) {
$tagVersions += $tags;
}
if (!$tagVersions) {
return array();
}
if (!$fetchTagVersions = 1 !== \func_num_args()) {
foreach ($tagsByKey as $tags) {
foreach ($tags as $tag => $version) {
if ($tagVersions[$tag] > $version) {
$tagVersions[$tag] = $version;
}
}
}
}
$now = microtime(true);
$tags = array();
foreach ($tagVersions as $tag => $version) {
$tags[$tag.static::TAGS_PREFIX] = $tag;
if ($fetchTagVersions || !isset($this->knownTagVersions[$tag])) {
$fetchTagVersions = true;
continue;
}
$version -= $this->knownTagVersions[$tag][1];
if ((0 !== $version && 1 !== $version) || $this->knownTagVersionsTtl > $now - $this->knownTagVersions[$tag][0]) {
// reuse previously fetched tag versions up to the ttl, unless we are storing items or a potential miss arises
$fetchTagVersions = true;
} else {
$this->knownTagVersions[$tag][1] += $version;
}
}
if (!$fetchTagVersions) {
return $tagVersions;
}
foreach ($this->tags->getItems(array_keys($tags)) as $tag => $version) {
$tagVersions[$tag = $tags[$tag]] = $version->get() ?: 0;
if (isset($invalidatedTags[$tag])) {
$invalidatedTags[$tag] = $version->set(++$tagVersions[$tag]);
}
$this->knownTagVersions[$tag] = array($now, $tagVersions[$tag]);
}
return $tagVersions;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
use Psr\Cache\InvalidArgumentException;
/**
* Interface for invalidating cached items using tags.
*
* @author Nicolas Grekas <[email protected]>
*/
interface TagAwareAdapterInterface extends AdapterInterface
{
/**
* Invalidates cached items using tags.
*
* @param string[] $tags An array of tags to invalidate
*
* @return bool True on success
*
* @throws InvalidArgumentException When $tags is not valid
*/
public function invalidateTags(array $tags);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
use Psr\Cache\CacheItemInterface;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\ResettableInterface;
/**
* An adapter that collects data about all cache calls.
*
* @author Aaron Scherer <[email protected]>
* @author Tobias Nyholm <[email protected]>
* @author Nicolas Grekas <[email protected]>
*/
class TraceableAdapter implements AdapterInterface, PruneableInterface, ResettableInterface
{
protected $pool;
private $calls = array();
public function __construct(AdapterInterface $pool)
{
$this->pool = $pool;
}
/**
* {@inheritdoc}
*/
public function getItem($key)
{
$event = $this->start(__FUNCTION__);
try {
$item = $this->pool->getItem($key);
} finally {
$event->end = microtime(true);
}
if ($event->result[$key] = $item->isHit()) {
++$event->hits;
} else {
++$event->misses;
}
return $item;
}
/**
* {@inheritdoc}
*/
public function hasItem($key)
{
$event = $this->start(__FUNCTION__);
try {
return $event->result[$key] = $this->pool->hasItem($key);
} finally {
$event->end = microtime(true);
}
}
/**
* {@inheritdoc}
*/
public function deleteItem($key)
{
$event = $this->start(__FUNCTION__);
try {
return $event->result[$key] = $this->pool->deleteItem($key);
} finally {
$event->end = microtime(true);
}
}
/**
* {@inheritdoc}
*/
public function save(CacheItemInterface $item)
{
$event = $this->start(__FUNCTION__);
try {
return $event->result[$item->getKey()] = $this->pool->save($item);
} finally {
$event->end = microtime(true);
}
}
/**
* {@inheritdoc}
*/
public function saveDeferred(CacheItemInterface $item)
{
$event = $this->start(__FUNCTION__);
try {
return $event->result[$item->getKey()] = $this->pool->saveDeferred($item);
} finally {
$event->end = microtime(true);
}
}
/**
* {@inheritdoc}
*/
public function getItems(array $keys = array())
{
$event = $this->start(__FUNCTION__);
try {
$result = $this->pool->getItems($keys);
} finally {
$event->end = microtime(true);
}
$f = function () use ($result, $event) {
$event->result = array();
foreach ($result as $key => $item) {
if ($event->result[$key] = $item->isHit()) {
++$event->hits;
} else {
++$event->misses;
}
yield $key => $item;
}
};
return $f();
}
/**
* {@inheritdoc}
*/
public function clear()
{
$event = $this->start(__FUNCTION__);
try {
return $event->result = $this->pool->clear();
} finally {
$event->end = microtime(true);
}
}
/**
* {@inheritdoc}
*/
public function deleteItems(array $keys)
{
$event = $this->start(__FUNCTION__);
$event->result['keys'] = $keys;
try {
return $event->result['result'] = $this->pool->deleteItems($keys);
} finally {
$event->end = microtime(true);
}
}
/**
* {@inheritdoc}
*/
public function commit()
{
$event = $this->start(__FUNCTION__);
try {
return $event->result = $this->pool->commit();
} finally {
$event->end = microtime(true);
}
}
/**
* {@inheritdoc}
*/
public function prune()
{
if (!$this->pool instanceof PruneableInterface) {
return false;
}
$event = $this->start(__FUNCTION__);
try {
return $event->result = $this->pool->prune();
} finally {
$event->end = microtime(true);
}
}
/**
* {@inheritdoc}
*/
public function reset()
{
if (!$this->pool instanceof ResettableInterface) {
return;
}
$event = $this->start(__FUNCTION__);
try {
$this->pool->reset();
} finally {
$event->end = microtime(true);
}
}
public function getCalls()
{
return $this->calls;
}
public function clearCalls()
{
$this->calls = array();
}
protected function start($name)
{
$this->calls[] = $event = new TraceableAdapterEvent();
$event->name = $name;
$event->start = microtime(true);
return $event;
}
}
class TraceableAdapterEvent
{
public $name;
public $start;
public $end;
public $result;
public $hits = 0;
public $misses = 0;
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Adapter;
/**
* @author Robin Chalas <[email protected]>
*/
class TraceableTagAwareAdapter extends TraceableAdapter implements TagAwareAdapterInterface
{
public function __construct(TagAwareAdapterInterface $pool)
{
parent::__construct($pool);
}
/**
* {@inheritdoc}
*/
public function invalidateTags(array $tags)
{
$event = $this->start(__FUNCTION__);
try {
return $event->result = $this->pool->invalidateTags($tags);
} finally {
$event->end = microtime(true);
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache;
use Psr\Cache\CacheItemInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
/**
* @author Nicolas Grekas <[email protected]>
*/
final class CacheItem implements CacheItemInterface
{
protected $key;
protected $value;
protected $isHit = false;
protected $expiry;
protected $defaultLifetime;
protected $tags = array();
protected $prevTags = array();
protected $innerItem;
protected $poolHash;
/**
* {@inheritdoc}
*/
public function getKey()
{
return $this->key;
}
/**
* {@inheritdoc}
*/
public function get()
{
return $this->value;
}
/**
* {@inheritdoc}
*/
public function isHit()
{
return $this->isHit;
}
/**
* {@inheritdoc}
*/
public function set($value)
{
$this->value = $value;
return $this;
}
/**
* {@inheritdoc}
*/
public function expiresAt($expiration)
{
if (null === $expiration) {
$this->expiry = $this->defaultLifetime > 0 ? time() + $this->defaultLifetime : null;
} elseif ($expiration instanceof \DateTimeInterface) {
$this->expiry = (int) $expiration->format('U');
} else {
throw new InvalidArgumentException(sprintf('Expiration date must implement DateTimeInterface or be null, "%s" given', \is_object($expiration) ? \get_class($expiration) : \gettype($expiration)));
}
return $this;
}
/**
* {@inheritdoc}
*/
public function expiresAfter($time)
{
if (null === $time) {
$this->expiry = $this->defaultLifetime > 0 ? time() + $this->defaultLifetime : null;
} elseif ($time instanceof \DateInterval) {
$this->expiry = (int) \DateTime::createFromFormat('U', time())->add($time)->format('U');
} elseif (\is_int($time)) {
$this->expiry = $time + time();
} else {
throw new InvalidArgumentException(sprintf('Expiration date must be an integer, a DateInterval or null, "%s" given', \is_object($time) ? \get_class($time) : \gettype($time)));
}
return $this;
}
/**
* Adds a tag to a cache item.
*
* @param string|string[] $tags A tag or array of tags
*
* @return static
*
* @throws InvalidArgumentException When $tag is not valid
*/
public function tag($tags)
{
if (!\is_array($tags)) {
$tags = array($tags);
}
foreach ($tags as $tag) {
if (!\is_string($tag)) {
throw new InvalidArgumentException(sprintf('Cache tag must be string, "%s" given', \is_object($tag) ? \get_class($tag) : \gettype($tag)));
}
if (isset($this->tags[$tag])) {
continue;
}
if ('' === $tag) {
throw new InvalidArgumentException('Cache tag length must be greater than zero');
}
if (false !== strpbrk($tag, '{}()/\@:')) {
throw new InvalidArgumentException(sprintf('Cache tag "%s" contains reserved characters {}()/\@:', $tag));
}
$this->tags[$tag] = $tag;
}
return $this;
}
/**
* Returns the list of tags bound to the value coming from the pool storage if any.
*
* @return array
*/
public function getPreviousTags()
{
return $this->prevTags;
}
/**
* Validates a cache key according to PSR-6.
*
* @param string $key The key to validate
*
* @return string
*
* @throws InvalidArgumentException When $key is not valid
*/
public static function validateKey($key)
{
if (!\is_string($key)) {
throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given', \is_object($key) ? \get_class($key) : \gettype($key)));
}
if ('' === $key) {
throw new InvalidArgumentException('Cache key length must be greater than zero');
}
if (false !== strpbrk($key, '{}()/\@:')) {
throw new InvalidArgumentException(sprintf('Cache key "%s" contains reserved characters {}()/\@:', $key));
}
return $key;
}
/**
* Internal logging helper.
*
* @internal
*/
public static function log(LoggerInterface $logger = null, $message, $context = array())
{
if ($logger) {
$logger->warning($message, $context);
} else {
$replace = array();
foreach ($context as $k => $v) {
if (is_scalar($v)) {
$replace['{'.$k.'}'] = $v;
}
}
@trigger_error(strtr($message, $replace), E_USER_WARNING);
}
}
}

CHANGELOG

3.4.0

  • added using options from Memcached DSN
  • added PruneableInterface so PSR-6 or PSR-16 cache implementations can declare support for manual stale cache pruning
  • added prune logic to FilesystemTrait, PhpFilesTrait, PdoTrait, TagAwareAdapter and ChainTrait
  • now FilesystemAdapter, PhpFilesAdapter, FilesystemCache, PhpFilesCache, PdoAdapter, PdoCache, ChainAdapter, and ChainCache implement PruneableInterface and support manual stale cache pruning

3.3.0

  • [EXPERIMENTAL] added CacheItem::getPreviousTags() to get bound tags coming from the pool storage if any
  • added PSR-16 "Simple Cache" implementations for all existing PSR-6 adapters
  • added Psr6Cache and SimpleCacheAdapter for bidirectional interoperability between PSR-6 and PSR-16
  • added MemcachedAdapter (PSR-6) and MemcachedCache (PSR-16)
  • added TraceableAdapter (PSR-6) and TraceableCache (PSR-16)

3.2.0

  • added TagAwareAdapter for tags-based invalidation
  • added PdoAdapter with PDO and Doctrine DBAL support
  • added PhpArrayAdapter and PhpFilesAdapter for OPcache-backed shared memory storage (PHP 7+ only)
  • added NullAdapter

3.1.0

  • added the component with strict PSR-6 implementations
  • added ApcuAdapter, ArrayAdapter, FilesystemAdapter and RedisAdapter
  • added AbstractAdapter, ChainAdapter and ProxyAdapter
  • added DoctrineAdapter and DoctrineProvider for bidirectional interoperability with Doctrine Cache
{
"name": "symfony/cache",
"type": "library",
"description": "Symfony Cache component with PSR-6, PSR-16, and tags",
"keywords": ["caching", "psr6"],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Nicolas Grekas",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"provide": {
"psr/cache-implementation": "1.0",
"psr/simple-cache-implementation": "1.0"
},
"require": {
"php": "^7.1.3",
"psr/cache": "~1.0",
"psr/log": "~1.0",
"psr/simple-cache": "^1.0"
},
"require-dev": {
"cache/integration-tests": "dev-master",
"doctrine/cache": "~1.6",
"doctrine/dbal": "~2.4",
"predis/predis": "~1.0"
},
"conflict": {
"symfony/var-dumper": "<3.4"
},
"autoload": {
"psr-4": { "Symfony\\Component\\Cache\\": "" },
"exclude-from-classmap": [
"/Tests/"
]
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\DataCollector;
use Symfony\Component\Cache\Adapter\TraceableAdapter;
use Symfony\Component\Cache\Adapter\TraceableAdapterEvent;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface;
/**
* @author Aaron Scherer <[email protected]>
* @author Tobias Nyholm <[email protected]>
*/
class CacheDataCollector extends DataCollector implements LateDataCollectorInterface
{
/**
* @var TraceableAdapter[]
*/
private $instances = array();
/**
* @param string $name
* @param TraceableAdapter $instance
*/
public function addInstance($name, TraceableAdapter $instance)
{
$this->instances[$name] = $instance;
}
/**
* {@inheritdoc}
*/
public function collect(Request $request, Response $response, \Exception $exception = null)
{
$empty = array('calls' => array(), 'config' => array(), 'options' => array(), 'statistics' => array());
$this->data = array('instances' => $empty, 'total' => $empty);
foreach ($this->instances as $name => $instance) {
$this->data['instances']['calls'][$name] = $instance->getCalls();
}
$this->data['instances']['statistics'] = $this->calculateStatistics();
$this->data['total']['statistics'] = $this->calculateTotalStatistics();
}
public function reset()
{
$this->data = array();
foreach ($this->instances as $instance) {
$instance->clearCalls();
}
}
public function lateCollect()
{
$this->data = $this->cloneVar($this->data);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'cache';
}
/**
* Method returns amount of logged Cache reads: "get" calls.
*
* @return array
*/
public function getStatistics()
{
return $this->data['instances']['statistics'];
}
/**
* Method returns the statistic totals.
*
* @return array
*/
public function getTotals()
{
return $this->data['total']['statistics'];
}
/**
* Method returns all logged Cache call objects.
*
* @return mixed
*/
public function getCalls()
{
return $this->data['instances']['calls'];
}
private function calculateStatistics(): array
{
$statistics = array();
foreach ($this->data['instances']['calls'] as $name => $calls) {
$statistics[$name] = array(
'calls' => 0,
'time' => 0,
'reads' => 0,
'writes' => 0,
'deletes' => 0,
'hits' => 0,
'misses' => 0,
);
/** @var TraceableAdapterEvent $call */
foreach ($calls as $call) {
++$statistics[$name]['calls'];
$statistics[$name]['time'] += $call->end - $call->start;
if ('getItem' === $call->name) {
++$statistics[$name]['reads'];
if ($call->hits) {
++$statistics[$name]['hits'];
} else {
++$statistics[$name]['misses'];
}
} elseif ('getItems' === $call->name) {
$statistics[$name]['reads'] += $call->hits + $call->misses;
$statistics[$name]['hits'] += $call->hits;
$statistics[$name]['misses'] += $call->misses;
} elseif ('hasItem' === $call->name) {
++$statistics[$name]['reads'];
if (false === $call->result) {
++$statistics[$name]['misses'];
} else {
++$statistics[$name]['hits'];
}
} elseif ('save' === $call->name) {
++$statistics[$name]['writes'];
} elseif ('deleteItem' === $call->name) {
++$statistics[$name]['deletes'];
}
}
if ($statistics[$name]['reads']) {
$statistics[$name]['hit_read_ratio'] = round(100 * $statistics[$name]['hits'] / $statistics[$name]['reads'], 2);
} else {
$statistics[$name]['hit_read_ratio'] = null;
}
}
return $statistics;
}
private function calculateTotalStatistics(): array
{
$statistics = $this->getStatistics();
$totals = array(
'calls' => 0,
'time' => 0,
'reads' => 0,
'writes' => 0,
'deletes' => 0,
'hits' => 0,
'misses' => 0,
);
foreach ($statistics as $name => $values) {
foreach ($totals as $key => $value) {
$totals[$key] += $statistics[$name][$key];
}
}
if ($totals['reads']) {
$totals['hit_read_ratio'] = round(100 * $totals['hits'] / $totals['reads'], 2);
} else {
$totals['hit_read_ratio'] = null;
}
return $totals;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache;
use Doctrine\Common\Cache\CacheProvider;
use Psr\Cache\CacheItemPoolInterface;
/**
* @author Nicolas Grekas <[email protected]>
*/
class DoctrineProvider extends CacheProvider implements PruneableInterface, ResettableInterface
{
private $pool;
public function __construct(CacheItemPoolInterface $pool)
{
$this->pool = $pool;
}
/**
* {@inheritdoc}
*/
public function prune()
{
return $this->pool instanceof PruneableInterface && $this->pool->prune();
}
/**
* {@inheritdoc}
*/
public function reset()
{
if ($this->pool instanceof ResettableInterface) {
$this->pool->reset();
}
$this->setNamespace($this->getNamespace());
}
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
$item = $this->pool->getItem(rawurlencode($id));
return $item->isHit() ? $item->get() : false;
}
/**
* {@inheritdoc}
*/
protected function doContains($id)
{
return $this->pool->hasItem(rawurlencode($id));
}
/**
* {@inheritdoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
$item = $this->pool->getItem(rawurlencode($id));
if (0 < $lifeTime) {
$item->expiresAfter($lifeTime);
}
return $this->pool->save($item->set($data));
}
/**
* {@inheritdoc}
*/
protected function doDelete($id)
{
return $this->pool->deleteItem(rawurlencode($id));
}
/**
* {@inheritdoc}
*/
protected function doFlush()
{
$this->pool->clear();
}
/**
* {@inheritdoc}
*/
protected function doGetStats()
{
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Exception;
use Psr\Cache\CacheException as Psr6CacheInterface;
use Psr\SimpleCache\CacheException as SimpleCacheInterface;
class CacheException extends \Exception implements Psr6CacheInterface, SimpleCacheInterface
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Exception;
use Psr\Cache\InvalidArgumentException as Psr6CacheInterface;
use Psr\SimpleCache\InvalidArgumentException as SimpleCacheInterface;
class InvalidArgumentException extends \InvalidArgumentException implements Psr6CacheInterface, SimpleCacheInterface
{
}
Copyright (c) 2016-2018 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="vendor/autoload.php"
failOnRisky="true"
failOnWarning="true"
>
<php>
<ini name="error_reporting" value="-1" />
<env name="REDIS_HOST" value="localhost" />
<env name="MEMCACHED_HOST" value="localhost" />
</php>
<testsuites>
<testsuite name="Symfony Cache Component Test Suite">
<directory>./Tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./</directory>
<exclude>
<directory>./Tests</directory>
<directory>./vendor</directory>
</exclude>
</whitelist>
</filter>
<listeners>
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener">
<arguments>
<array>
<element key="time-sensitive">
<array>
<element><string>Cache\IntegrationTests</string></element>
<element><string>Doctrine\Common\Cache</string></element>
<element><string>Symfony\Component\Cache</string></element>
<element><string>Symfony\Component\Cache\Tests\Fixtures</string></element>
<element><string>Symfony\Component\Cache\Traits</string></element>
</array>
</element>
</array>
</arguments>
</listener>
</listeners>
</phpunit>
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache;
/**
* Interface extends psr-6 and psr-16 caches to allow for pruning (deletion) of all expired cache items.
*/
interface PruneableInterface
{
/**
* @return bool
*/
public function prune();
}

Symfony PSR-6 implementation for caching

This component provides an extended PSR-6 implementation for adding cache to your applications. It is designed to have a low overhead so that caching is fastest. It ships with a few caching adapters for the most widespread and suited to caching backends. It also provides a doctrine/cache proxy adapter to cover more advanced caching needs and a proxy adapter for greater interoperability between PSR-6 implementations.

Resources

<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache;
/**
* Resets a pool's local state.
*/
interface ResettableInterface
{
public function reset();
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Simple;
use Psr\Log\LoggerAwareInterface;
use Psr\SimpleCache\CacheInterface;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\ResettableInterface;
use Symfony\Component\Cache\Traits\AbstractTrait;
/**
* @author Nicolas Grekas <[email protected]>
*/
abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, ResettableInterface
{
use AbstractTrait {
deleteItems as private;
AbstractTrait::deleteItem as delete;
AbstractTrait::hasItem as has;
}
private $defaultLifetime;
protected function __construct(string $namespace = '', int $defaultLifetime = 0)
{
$this->defaultLifetime = max(0, $defaultLifetime);
$this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).':';
if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) {
throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s")', $this->maxIdLength - 24, \strlen($namespace), $namespace));
}
}
/**
* {@inheritdoc}
*/
public function get($key, $default = null)
{
$id = $this->getId($key);
try {
foreach ($this->doFetch(array($id)) as $value) {
return $value;
}
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to fetch key "{key}"', array('key' => $key, 'exception' => $e));
}
return $default;
}
/**
* {@inheritdoc}
*/
public function set($key, $value, $ttl = null)
{
CacheItem::validateKey($key);
return $this->setMultiple(array($key => $value), $ttl);
}
/**
* {@inheritdoc}
*/
public function getMultiple($keys, $default = null)
{
if ($keys instanceof \Traversable) {
$keys = iterator_to_array($keys, false);
} elseif (!\is_array($keys)) {
throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given', \is_object($keys) ? \get_class($keys) : \gettype($keys)));
}
$ids = array();
foreach ($keys as $key) {
$ids[] = $this->getId($key);
}
try {
$values = $this->doFetch($ids);
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to fetch requested values', array('keys' => $keys, 'exception' => $e));
$values = array();
}
$ids = array_combine($ids, $keys);
return $this->generateValues($values, $ids, $default);
}
/**
* {@inheritdoc}
*/
public function setMultiple($values, $ttl = null)
{
if (!\is_array($values) && !$values instanceof \Traversable) {
throw new InvalidArgumentException(sprintf('Cache values must be array or Traversable, "%s" given', \is_object($values) ? \get_class($values) : \gettype($values)));
}
$valuesById = array();
foreach ($values as $key => $value) {
if (\is_int($key)) {
$key = (string) $key;
}
$valuesById[$this->getId($key)] = $value;
}
if (false === $ttl = $this->normalizeTtl($ttl)) {
return $this->doDelete(array_keys($valuesById));
}
try {
$e = $this->doSave($valuesById, $ttl);
} catch (\Exception $e) {
}
if (true === $e || array() === $e) {
return true;
}
$keys = array();
foreach (\is_array($e) ? $e : array_keys($valuesById) as $id) {
$keys[] = substr($id, \strlen($this->namespace));
}
CacheItem::log($this->logger, 'Failed to save values', array('keys' => $keys, 'exception' => $e instanceof \Exception ? $e : null));
return false;
}
/**
* {@inheritdoc}
*/
public function deleteMultiple($keys)
{
if ($keys instanceof \Traversable) {
$keys = iterator_to_array($keys, false);
} elseif (!\is_array($keys)) {
throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given', \is_object($keys) ? \get_class($keys) : \gettype($keys)));
}
return $this->deleteItems($keys);
}
private function normalizeTtl($ttl)
{
if (null === $ttl) {
return $this->defaultLifetime;
}
if ($ttl instanceof \DateInterval) {
$ttl = (int) \DateTime::createFromFormat('U', 0)->add($ttl)->format('U');
}
if (\is_int($ttl)) {
return 0 < $ttl ? $ttl : false;
}
throw new InvalidArgumentException(sprintf('Expiration date must be an integer, a DateInterval or null, "%s" given', \is_object($ttl) ? \get_class($ttl) : \gettype($ttl)));
}
private function generateValues($values, &$keys, $default)
{
try {
foreach ($values as $id => $value) {
if (!isset($keys[$id])) {
$id = key($keys);
}
$key = $keys[$id];
unset($keys[$id]);
yield $key => $value;
}
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to fetch requested values', array('keys' => array_values($keys), 'exception' => $e));
}
foreach ($keys as $key) {
yield $key => $default;
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Simple;
use Symfony\Component\Cache\Traits\ApcuTrait;
class ApcuCache extends AbstractCache
{
use ApcuTrait;
public function __construct(string $namespace = '', int $defaultLifetime = 0, string $version = null)
{
$this->init($namespace, $defaultLifetime, $version);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Simple;
use Psr\Log\LoggerAwareInterface;
use Psr\SimpleCache\CacheInterface;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\ResettableInterface;
use Symfony\Component\Cache\Traits\ArrayTrait;
/**
* @author Nicolas Grekas <[email protected]>
*/
class ArrayCache implements CacheInterface, LoggerAwareInterface, ResettableInterface
{
use ArrayTrait {
ArrayTrait::deleteItem as delete;
ArrayTrait::hasItem as has;
}
private $defaultLifetime;
/**
* @param int $defaultLifetime
* @param bool $storeSerialized Disabling serialization can lead to cache corruptions when storing mutable values but increases performance otherwise
*/
public function __construct(int $defaultLifetime = 0, bool $storeSerialized = true)
{
$this->defaultLifetime = $defaultLifetime;
$this->storeSerialized = $storeSerialized;
}
/**
* {@inheritdoc}
*/
public function get($key, $default = null)
{
foreach ($this->getMultiple(array($key), $default) as $v) {
return $v;
}
}
/**
* {@inheritdoc}
*/
public function getMultiple($keys, $default = null)
{
if ($keys instanceof \Traversable) {
$keys = iterator_to_array($keys, false);
} elseif (!\is_array($keys)) {
throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given', \is_object($keys) ? \get_class($keys) : \gettype($keys)));
}
foreach ($keys as $key) {
CacheItem::validateKey($key);
}
return $this->generateItems($keys, time(), function ($k, $v, $hit) use ($default) { return $hit ? $v : $default; });
}
/**
* {@inheritdoc}
*/
public function deleteMultiple($keys)
{
if (!\is_array($keys) && !$keys instanceof \Traversable) {
throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given', \is_object($keys) ? \get_class($keys) : \gettype($keys)));
}
foreach ($keys as $key) {
$this->delete($key);
}
return true;
}
/**
* {@inheritdoc}
*/
public function set($key, $value, $ttl = null)
{
CacheItem::validateKey($key);
return $this->setMultiple(array($key => $value), $ttl);
}
/**
* {@inheritdoc}
*/
public function setMultiple($values, $ttl = null)
{
if (!\is_array($values) && !$values instanceof \Traversable) {
throw new InvalidArgumentException(sprintf('Cache values must be array or Traversable, "%s" given', \is_object($values) ? \get_class($values) : \gettype($values)));
}
$valuesArray = array();
foreach ($values as $key => $value) {
\is_int($key) || CacheItem::validateKey($key);
$valuesArray[$key] = $value;
}
if (false === $ttl = $this->normalizeTtl($ttl)) {
return $this->deleteMultiple(array_keys($valuesArray));
}
if ($this->storeSerialized) {
foreach ($valuesArray as $key => $value) {
try {
$valuesArray[$key] = serialize($value);
} catch (\Exception $e) {
$type = \is_object($value) ? \get_class($value) : \gettype($value);
CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', array('key' => $key, 'type' => $type, 'exception' => $e));
return false;
}
}
}
$expiry = 0 < $ttl ? time() + $ttl : PHP_INT_MAX;
foreach ($valuesArray as $key => $value) {
$this->values[$key] = $value;
$this->expiries[$key] = $expiry;
}
return true;
}
private function normalizeTtl($ttl)
{
if (null === $ttl) {
return $this->defaultLifetime;
}
if ($ttl instanceof \DateInterval) {
$ttl = (int) \DateTime::createFromFormat('U', 0)->add($ttl)->format('U');
}
if (\is_int($ttl)) {
return 0 < $ttl ? $ttl : false;
}
throw new InvalidArgumentException(sprintf('Expiration date must be an integer, a DateInterval or null, "%s" given', \is_object($ttl) ? \get_class($ttl) : \gettype($ttl)));
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Simple;
use Psr\SimpleCache\CacheInterface;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\ResettableInterface;
/**
* Chains several caches together.
*
* Cached items are fetched from the first cache having them in its data store.
* They are saved and deleted in all caches at once.
*
* @author Nicolas Grekas <[email protected]>
*/
class ChainCache implements CacheInterface, PruneableInterface, ResettableInterface
{
private $miss;
private $caches = array();
private $defaultLifetime;
private $cacheCount;
/**
* @param CacheInterface[] $caches The ordered list of caches used to fetch cached items
* @param int $defaultLifetime The lifetime of items propagated from lower caches to upper ones
*/
public function __construct(array $caches, int $defaultLifetime = 0)
{
if (!$caches) {
throw new InvalidArgumentException('At least one cache must be specified.');
}
foreach ($caches as $cache) {
if (!$cache instanceof CacheInterface) {
throw new InvalidArgumentException(sprintf('The class "%s" does not implement the "%s" interface.', \get_class($cache), CacheInterface::class));
}
}
$this->miss = new \stdClass();
$this->caches = array_values($caches);
$this->cacheCount = \count($this->caches);
$this->defaultLifetime = 0 < $defaultLifetime ? $defaultLifetime : null;
}
/**
* {@inheritdoc}
*/
public function get($key, $default = null)
{
$miss = null !== $default && \is_object($default) ? $default : $this->miss;
foreach ($this->caches as $i => $cache) {
$value = $cache->get($key, $miss);
if ($miss !== $value) {
while (0 <= --$i) {
$this->caches[$i]->set($key, $value, $this->defaultLifetime);
}
return $value;
}
}
return $default;
}
/**
* {@inheritdoc}
*/
public function getMultiple($keys, $default = null)
{
$miss = null !== $default && \is_object($default) ? $default : $this->miss;
return $this->generateItems($this->caches[0]->getMultiple($keys, $miss), 0, $miss, $default);
}
private function generateItems($values, $cacheIndex, $miss, $default)
{
$missing = array();
$nextCacheIndex = $cacheIndex + 1;
$nextCache = isset($this->caches[$nextCacheIndex]) ? $this->caches[$nextCacheIndex] : null;
foreach ($values as $k => $value) {
if ($miss !== $value) {
yield $k => $value;
} elseif (!$nextCache) {
yield $k => $default;
} else {
$missing[] = $k;
}
}
if ($missing) {
$cache = $this->caches[$cacheIndex];
$values = $this->generateItems($nextCache->getMultiple($missing, $miss), $nextCacheIndex, $miss, $default);
foreach ($values as $k => $value) {
if ($miss !== $value) {
$cache->set($k, $value, $this->defaultLifetime);
yield $k => $value;
} else {
yield $k => $default;
}
}
}
}
/**
* {@inheritdoc}
*/
public function has($key)
{
foreach ($this->caches as $cache) {
if ($cache->has($key)) {
return true;
}
}
return false;
}
/**
* {@inheritdoc}
*/
public function clear()
{
$cleared = true;
$i = $this->cacheCount;
while ($i--) {
$cleared = $this->caches[$i]->clear() && $cleared;
}
return $cleared;
}
/**
* {@inheritdoc}
*/
public function delete($key)
{
$deleted = true;
$i = $this->cacheCount;
while ($i--) {
$deleted = $this->caches[$i]->delete($key) && $deleted;
}
return $deleted;
}
/**
* {@inheritdoc}
*/
public function deleteMultiple($keys)
{
if ($keys instanceof \Traversable) {
$keys = iterator_to_array($keys, false);
}
$deleted = true;
$i = $this->cacheCount;
while ($i--) {
$deleted = $this->caches[$i]->deleteMultiple($keys) && $deleted;
}
return $deleted;
}
/**
* {@inheritdoc}
*/
public function set($key, $value, $ttl = null)
{
$saved = true;
$i = $this->cacheCount;
while ($i--) {
$saved = $this->caches[$i]->set($key, $value, $ttl) && $saved;
}
return $saved;
}
/**
* {@inheritdoc}
*/
public function setMultiple($values, $ttl = null)
{
if ($values instanceof \Traversable) {
$valuesIterator = $values;
$values = function () use ($valuesIterator, &$values) {
$generatedValues = array();
foreach ($valuesIterator as $key => $value) {
yield $key => $value;
$generatedValues[$key] = $value;
}
$values = $generatedValues;
};
$values = $values();
}
$saved = true;
$i = $this->cacheCount;
while ($i--) {
$saved = $this->caches[$i]->setMultiple($values, $ttl) && $saved;
}
return $saved;
}
/**
* {@inheritdoc}
*/
public function prune()
{
$pruned = true;
foreach ($this->caches as $cache) {
if ($cache instanceof PruneableInterface) {
$pruned = $cache->prune() && $pruned;
}
}
return $pruned;
}
/**
* {@inheritdoc}
*/
public function reset()
{
foreach ($this->caches as $cache) {
if ($cache instanceof ResettableInterface) {
$cache->reset();
}
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Simple;
use Doctrine\Common\Cache\CacheProvider;
use Symfony\Component\Cache\Traits\DoctrineTrait;
class DoctrineCache extends AbstractCache
{
use DoctrineTrait;
public function __construct(CacheProvider $provider, string $namespace = '', int $defaultLifetime = 0)
{
parent::__construct('', $defaultLifetime);
$this->provider = $provider;
$provider->setNamespace($namespace);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Simple;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\Traits\FilesystemTrait;
class FilesystemCache extends AbstractCache implements PruneableInterface
{
use FilesystemTrait;
public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null)
{
parent::__construct('', $defaultLifetime);
$this->init($namespace, $directory);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Simple;
use Symfony\Component\Cache\Traits\MemcachedTrait;
class MemcachedCache extends AbstractCache
{
use MemcachedTrait;
protected $maxIdLength = 250;
public function __construct(\Memcached $client, string $namespace = '', int $defaultLifetime = 0)
{
$this->init($client, $namespace, $defaultLifetime);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Simple;
use Psr\SimpleCache\CacheInterface;
/**
* @author Nicolas Grekas <[email protected]>
*/
class NullCache implements CacheInterface
{
/**
* {@inheritdoc}
*/
public function get($key, $default = null)
{
return $default;
}
/**
* {@inheritdoc}
*/
public function getMultiple($keys, $default = null)
{
foreach ($keys as $key) {
yield $key => $default;
}
}
/**
* {@inheritdoc}
*/
public function has($key)
{
return false;
}
/**
* {@inheritdoc}
*/
public function clear()
{
return true;
}
/**
* {@inheritdoc}
*/
public function delete($key)
{
return true;
}
/**
* {@inheritdoc}
*/
public function deleteMultiple($keys)
{
return true;
}
/**
* {@inheritdoc}
*/
public function set($key, $value, $ttl = null)
{
return false;
}
/**
* {@inheritdoc}
*/
public function setMultiple($values, $ttl = null)
{
return false;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Simple;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\Traits\PdoTrait;
class PdoCache extends AbstractCache implements PruneableInterface
{
use PdoTrait;
protected $maxIdLength = 255;
/**
* You can either pass an existing database connection as PDO instance or
* a Doctrine DBAL Connection or a DSN string that will be used to
* lazy-connect to the database when the cache is actually used.
*
* List of available options:
* * db_table: The name of the table [default: cache_items]
* * db_id_col: The column where to store the cache id [default: item_id]
* * db_data_col: The column where to store the cache data [default: item_data]
* * db_lifetime_col: The column where to store the lifetime [default: item_lifetime]
* * db_time_col: The column where to store the timestamp [default: item_time]
* * db_username: The username when lazy-connect [default: '']
* * db_password: The password when lazy-connect [default: '']
* * db_connection_options: An array of driver-specific connection options [default: array()]
*
* @param \PDO|Connection|string $connOrDsn a \PDO or Connection instance or DSN string or null
*
* @throws InvalidArgumentException When first argument is not PDO nor Connection nor string
* @throws InvalidArgumentException When PDO error mode is not PDO::ERRMODE_EXCEPTION
* @throws InvalidArgumentException When namespace contains invalid characters
*/
public function __construct($connOrDsn, string $namespace = '', int $defaultLifetime = 0, array $options = array())
{
$this->init($connOrDsn, $namespace, $defaultLifetime, $options);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Simple;
use Psr\SimpleCache\CacheInterface;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\ResettableInterface;
use Symfony\Component\Cache\Traits\PhpArrayTrait;
/**
* Caches items at warm up time using a PHP array that is stored in shared memory by OPCache since PHP 7.0.
* Warmed up items are read-only and run-time discovered items are cached using a fallback adapter.
*
* @author Titouan Galopin <[email protected]>
* @author Nicolas Grekas <[email protected]>
*/
class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInterface
{
use PhpArrayTrait;
/**
* @param string $file The PHP file were values are cached
* @param CacheInterface $fallbackPool A pool to fallback on when an item is not hit
*/
public function __construct(string $file, CacheInterface $fallbackPool)
{
$this->file = $file;
$this->pool = $fallbackPool;
$this->zendDetectUnicode = ini_get('zend.detect_unicode');
}
/**
* This adapter takes advantage of how PHP stores arrays in its latest versions.
*
* @param string $file The PHP file were values are cached
*
* @return CacheInterface
*/
public static function create($file, CacheInterface $fallbackPool)
{
// Shared memory is available in PHP 7.0+ with OPCache enabled
if (ini_get('opcache.enable')) {
return new static($file, $fallbackPool);
}
return $fallbackPool;
}
/**
* {@inheritdoc}
*/
public function get($key, $default = null)
{
if (!\is_string($key)) {
throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
}
if (null === $this->values) {
$this->initialize();
}
if (!isset($this->values[$key])) {
return $this->pool->get($key, $default);
}
$value = $this->values[$key];
if ('N;' === $value) {
return null;
}
if (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
try {
return unserialize($value);
} catch (\Throwable $e) {
return $default;
}
}
return $value;
}
/**
* {@inheritdoc}
*/
public function getMultiple($keys, $default = null)
{
if ($keys instanceof \Traversable) {
$keys = iterator_to_array($keys, false);
} elseif (!\is_array($keys)) {
throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given', \is_object($keys) ? \get_class($keys) : \gettype($keys)));
}
foreach ($keys as $key) {
if (!\is_string($key)) {
throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
}
}
if (null === $this->values) {
$this->initialize();
}
return $this->generateItems($keys, $default);
}
/**
* {@inheritdoc}
*/
public function has($key)
{
if (!\is_string($key)) {
throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
}
if (null === $this->values) {
$this->initialize();
}
return isset($this->values[$key]) || $this->pool->has($key);
}
/**
* {@inheritdoc}
*/
public function delete($key)
{
if (!\is_string($key)) {
throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
}
if (null === $this->values) {
$this->initialize();
}
return !isset($this->values[$key]) && $this->pool->delete($key);
}
/**
* {@inheritdoc}
*/
public function deleteMultiple($keys)
{
if (!\is_array($keys) && !$keys instanceof \Traversable) {
throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given', \is_object($keys) ? \get_class($keys) : \gettype($keys)));
}
$deleted = true;
$fallbackKeys = array();
foreach ($keys as $key) {
if (!\is_string($key)) {
throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
}
if (isset($this->values[$key])) {
$deleted = false;
} else {
$fallbackKeys[] = $key;
}
}
if (null === $this->values) {
$this->initialize();
}
if ($fallbackKeys) {
$deleted = $this->pool->deleteMultiple($fallbackKeys) && $deleted;
}
return $deleted;
}
/**
* {@inheritdoc}
*/
public function set($key, $value, $ttl = null)
{
if (!\is_string($key)) {
throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
}
if (null === $this->values) {
$this->initialize();
}
return !isset($this->values[$key]) && $this->pool->set($key, $value, $ttl);
}
/**
* {@inheritdoc}
*/
public function setMultiple($values, $ttl = null)
{
if (!\is_array($values) && !$values instanceof \Traversable) {
throw new InvalidArgumentException(sprintf('Cache values must be array or Traversable, "%s" given', \is_object($values) ? \get_class($values) : \gettype($values)));
}
$saved = true;
$fallbackValues = array();
foreach ($values as $key => $value) {
if (!\is_string($key) && !\is_int($key)) {
throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
}
if (isset($this->values[$key])) {
$saved = false;
} else {
$fallbackValues[$key] = $value;
}
}
if ($fallbackValues) {
$saved = $this->pool->setMultiple($fallbackValues, $ttl) && $saved;
}
return $saved;
}
private function generateItems(array $keys, $default)
{
$fallbackKeys = array();
foreach ($keys as $key) {
if (isset($this->values[$key])) {
$value = $this->values[$key];
if ('N;' === $value) {
yield $key => null;
} elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
try {
yield $key => unserialize($value);
} catch (\Throwable $e) {
yield $key => $default;
}
} else {
yield $key => $value;
}
} else {
$fallbackKeys[] = $key;
}
}
if ($fallbackKeys) {
foreach ($this->pool->getMultiple($fallbackKeys, $default) as $key => $item) {
yield $key => $item;
}
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Simple;
use Symfony\Component\Cache\Exception\CacheException;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\Traits\PhpFilesTrait;
class PhpFilesCache extends AbstractCache implements PruneableInterface
{
use PhpFilesTrait;
/**
* @throws CacheException if OPcache is not enabled
*/
public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null)
{
if (!static::isSupported()) {
throw new CacheException('OPcache is not enabled');
}
parent::__construct('', $defaultLifetime);
$this->init($namespace, $directory);
$e = new \Exception();
$this->includeHandler = function () use ($e) { throw $e; };
$this->zendDetectUnicode = ini_get('zend.detect_unicode');
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Simple;
use Psr\Cache\CacheException as Psr6CacheException;
use Psr\Cache\CacheItemPoolInterface;
use Psr\SimpleCache\CacheException as SimpleCacheException;
use Psr\SimpleCache\CacheInterface;
use Symfony\Component\Cache\Adapter\AbstractAdapter;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\ResettableInterface;
use Symfony\Component\Cache\Traits\ProxyTrait;
/**
* @author Nicolas Grekas <[email protected]>
*/
class Psr6Cache implements CacheInterface, PruneableInterface, ResettableInterface
{
use ProxyTrait;
private $createCacheItem;
public function __construct(CacheItemPoolInterface $pool)
{
$this->pool = $pool;
if ($pool instanceof AbstractAdapter) {
$this->createCacheItem = \Closure::bind(
function ($key, $value, $allowInt = false) {
if ($allowInt && \is_int($key)) {
$key = (string) $key;
} else {
CacheItem::validateKey($key);
}
$f = $this->createCacheItem;
return $f($key, $value, false);
},
$pool,
AbstractAdapter::class
);
}
}
/**
* {@inheritdoc}
*/
public function get($key, $default = null)
{
try {
$item = $this->pool->getItem($key);
} catch (SimpleCacheException $e) {
throw $e;
} catch (Psr6CacheException $e) {
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
return $item->isHit() ? $item->get() : $default;
}
/**
* {@inheritdoc}
*/
public function set($key, $value, $ttl = null)
{
try {
if (null !== $f = $this->createCacheItem) {
$item = $f($key, $value);
} else {
$item = $this->pool->getItem($key)->set($value);
}
} catch (SimpleCacheException $e) {
throw $e;
} catch (Psr6CacheException $e) {
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
if (null !== $ttl) {
$item->expiresAfter($ttl);
}
return $this->pool->save($item);
}
/**
* {@inheritdoc}
*/
public function delete($key)
{
try {
return $this->pool->deleteItem($key);
} catch (SimpleCacheException $e) {
throw $e;
} catch (Psr6CacheException $e) {
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* {@inheritdoc}
*/
public function clear()
{
return $this->pool->clear();
}
/**
* {@inheritdoc}
*/
public function getMultiple($keys, $default = null)
{
if ($keys instanceof \Traversable) {
$keys = iterator_to_array($keys, false);
} elseif (!\is_array($keys)) {
throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given', \is_object($keys) ? \get_class($keys) : \gettype($keys)));
}
try {
$items = $this->pool->getItems($keys);
} catch (SimpleCacheException $e) {
throw $e;
} catch (Psr6CacheException $e) {
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
$values = array();
foreach ($items as $key => $item) {
$values[$key] = $item->isHit() ? $item->get() : $default;
}
return $values;
}
/**
* {@inheritdoc}
*/
public function setMultiple($values, $ttl = null)
{
$valuesIsArray = \is_array($values);
if (!$valuesIsArray && !$values instanceof \Traversable) {
throw new InvalidArgumentException(sprintf('Cache values must be array or Traversable, "%s" given', \is_object($values) ? \get_class($values) : \gettype($values)));
}
$items = array();
try {
if (null !== $f = $this->createCacheItem) {
$valuesIsArray = false;
foreach ($values as $key => $value) {
$items[$key] = $f($key, $value, true);
}
} elseif ($valuesIsArray) {
$items = array();
foreach ($values as $key => $value) {
$items[] = (string) $key;
}
$items = $this->pool->getItems($items);
} else {
foreach ($values as $key => $value) {
if (\is_int($key)) {
$key = (string) $key;
}
$items[$key] = $this->pool->getItem($key)->set($value);
}
}
} catch (SimpleCacheException $e) {
throw $e;
} catch (Psr6CacheException $e) {
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
$ok = true;
foreach ($items as $key => $item) {
if ($valuesIsArray) {
$item->set($values[$key]);
}
if (null !== $ttl) {
$item->expiresAfter($ttl);
}
$ok = $this->pool->saveDeferred($item) && $ok;
}
return $this->pool->commit() && $ok;
}
/**
* {@inheritdoc}
*/
public function deleteMultiple($keys)
{
if ($keys instanceof \Traversable) {
$keys = iterator_to_array($keys, false);
} elseif (!\is_array($keys)) {
throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given', \is_object($keys) ? \get_class($keys) : \gettype($keys)));
}
try {
return $this->pool->deleteItems($keys);
} catch (SimpleCacheException $e) {
throw $e;
} catch (Psr6CacheException $e) {
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* {@inheritdoc}
*/
public function has($key)
{
try {
return $this->pool->hasItem($key);
} catch (SimpleCacheException $e) {
throw $e;
} catch (Psr6CacheException $e) {
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Simple;
use Symfony\Component\Cache\Traits\RedisTrait;
class RedisCache extends AbstractCache
{
use RedisTrait;
/**
* @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient
* @param string $namespace
* @param int $defaultLifetime
*/
public function __construct($redisClient, string $namespace = '', int $defaultLifetime = 0)
{
$this->init($redisClient, $namespace, $defaultLifetime);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Simple;
use Psr\SimpleCache\CacheInterface;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\ResettableInterface;
/**
* An adapter that collects data about all cache calls.
*
* @author Nicolas Grekas <[email protected]>
*/
class TraceableCache implements CacheInterface, PruneableInterface, ResettableInterface
{
private $pool;
private $miss;
private $calls = array();
public function __construct(CacheInterface $pool)
{
$this->pool = $pool;
$this->miss = new \stdClass();
}
/**
* {@inheritdoc}
*/
public function get($key, $default = null)
{
$miss = null !== $default && \is_object($default) ? $default : $this->miss;
$event = $this->start(__FUNCTION__);
try {
$value = $this->pool->get($key, $miss);
} finally {
$event->end = microtime(true);
}
if ($event->result[$key] = $miss !== $value) {
++$event->hits;
} else {
++$event->misses;
$value = $default;
}
return $value;
}
/**
* {@inheritdoc}
*/
public function has($key)
{
$event = $this->start(__FUNCTION__);
try {
return $event->result[$key] = $this->pool->has($key);
} finally {
$event->end = microtime(true);
}
}
/**
* {@inheritdoc}
*/
public function delete($key)
{
$event = $this->start(__FUNCTION__);
try {
return $event->result[$key] = $this->pool->delete($key);
} finally {
$event->end = microtime(true);
}
}
/**
* {@inheritdoc}
*/
public function set($key, $value, $ttl = null)
{
$event = $this->start(__FUNCTION__);
try {
return $event->result[$key] = $this->pool->set($key, $value, $ttl);
} finally {
$event->end = microtime(true);
}
}
/**
* {@inheritdoc}
*/
public function setMultiple($values, $ttl = null)
{
$event = $this->start(__FUNCTION__);
$event->result['keys'] = array();
if ($values instanceof \Traversable) {
$values = function () use ($values, $event) {
foreach ($values as $k => $v) {
$event->result['keys'][] = $k;
yield $k => $v;
}
};
$values = $values();
} elseif (\is_array($values)) {
$event->result['keys'] = array_keys($values);
}
try {
return $event->result['result'] = $this->pool->setMultiple($values, $ttl);
} finally {
$event->end = microtime(true);
}
}
/**
* {@inheritdoc}
*/
public function getMultiple($keys, $default = null)
{
$miss = null !== $default && \is_object($default) ? $default : $this->miss;
$event = $this->start(__FUNCTION__);
try {
$result = $this->pool->getMultiple($keys, $miss);
} finally {
$event->end = microtime(true);
}
$f = function () use ($result, $event, $miss, $default) {
$event->result = array();
foreach ($result as $key => $value) {
if ($event->result[$key] = $miss !== $value) {
++$event->hits;
} else {
++$event->misses;
$value = $default;
}
yield $key => $value;
}
};
return $f();
}
/**
* {@inheritdoc}
*/
public function clear()
{
$event = $this->start(__FUNCTION__);
try {
return $event->result = $this->pool->clear();
} finally {
$event->end = microtime(true);
}
}
/**
* {@inheritdoc}
*/
public function deleteMultiple($keys)
{
$event = $this->start(__FUNCTION__);
if ($keys instanceof \Traversable) {
$keys = $event->result['keys'] = iterator_to_array($keys, false);
} else {
$event->result['keys'] = $keys;
}
try {
return $event->result['result'] = $this->pool->deleteMultiple($keys);
} finally {
$event->end = microtime(true);
}
}
/**
* {@inheritdoc}
*/
public function prune()
{
if (!$this->pool instanceof PruneableInterface) {
return false;
}
$event = $this->start(__FUNCTION__);
try {
return $event->result = $this->pool->prune();
} finally {
$event->end = microtime(true);
}
}
/**
* {@inheritdoc}
*/
public function reset()
{
if (!$this->pool instanceof ResettableInterface) {
return;
}
$event = $this->start(__FUNCTION__);
try {
$this->pool->reset();
} finally {
$event->end = microtime(true);
}
}
public function getCalls()
{
try {
return $this->calls;
} finally {
$this->calls = array();
}
}
private function start($name)
{
$this->calls[] = $event = new TraceableCacheEvent();
$event->name = $name;
$event->start = microtime(true);
return $event;
}
}
class TraceableCacheEvent
{
public $name;
public $start;
public $end;
public $result;
public $hits = 0;
public $misses = 0;
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use Symfony\Component\Cache\Adapter\RedisAdapter;
abstract class AbstractRedisAdapterTest extends AdapterTestCase
{
protected $skippedTests = array(
'testExpiration' => 'Testing expiration slows down the test suite',
'testHasItemReturnsFalseWhenDeferredItemIsExpired' => 'Testing expiration slows down the test suite',
'testDefaultLifeTime' => 'Testing expiration slows down the test suite',
);
protected static $redis;
public function createCachePool($defaultLifetime = 0)
{
return new RedisAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime);
}
public static function setupBeforeClass()
{
if (!\extension_loaded('redis')) {
self::markTestSkipped('Extension redis required.');
}
if (!@((new \Redis())->connect(getenv('REDIS_HOST')))) {
$e = error_get_last();
self::markTestSkipped($e['message']);
}
}
public static function tearDownAfterClass()
{
self::$redis = null;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use Cache\IntegrationTests\CachePoolTest;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\PruneableInterface;
abstract class AdapterTestCase extends CachePoolTest
{
protected function setUp()
{
parent::setUp();
if (!array_key_exists('testPrune', $this->skippedTests) && !$this->createCachePool() instanceof PruneableInterface) {
$this->skippedTests['testPrune'] = 'Not a pruneable cache pool.';
}
}
public function testDefaultLifeTime()
{
if (isset($this->skippedTests[__FUNCTION__])) {
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
}
$cache = $this->createCachePool(2);
$item = $cache->getItem('key.dlt');
$item->set('value');
$cache->save($item);
sleep(1);
$item = $cache->getItem('key.dlt');
$this->assertTrue($item->isHit());
sleep(2);
$item = $cache->getItem('key.dlt');
$this->assertFalse($item->isHit());
}
public function testExpiration()
{
if (isset($this->skippedTests[__FUNCTION__])) {
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
}
$cache = $this->createCachePool();
$cache->save($cache->getItem('k1')->set('v1')->expiresAfter(2));
$cache->save($cache->getItem('k2')->set('v2')->expiresAfter(366 * 86400));
sleep(3);
$item = $cache->getItem('k1');
$this->assertFalse($item->isHit());
$this->assertNull($item->get(), "Item's value must be null when isHit() is false.");
$item = $cache->getItem('k2');
$this->assertTrue($item->isHit());
$this->assertSame('v2', $item->get());
}
public function testNotUnserializable()
{
if (isset($this->skippedTests[__FUNCTION__])) {
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
}
$cache = $this->createCachePool();
$item = $cache->getItem('foo');
$cache->save($item->set(new NotUnserializable()));
$item = $cache->getItem('foo');
$this->assertFalse($item->isHit());
foreach ($cache->getItems(array('foo')) as $item) {
}
$cache->save($item->set(new NotUnserializable()));
foreach ($cache->getItems(array('foo')) as $item) {
}
$this->assertFalse($item->isHit());
}
public function testPrune()
{
if (isset($this->skippedTests[__FUNCTION__])) {
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
}
if (!method_exists($this, 'isPruned')) {
$this->fail('Test classes for pruneable caches must implement `isPruned($cache, $name)` method.');
}
/** @var PruneableInterface|CacheItemPoolInterface $cache */
$cache = $this->createCachePool();
$doSet = function ($name, $value, \DateInterval $expiresAfter = null) use ($cache) {
$item = $cache->getItem($name);
$item->set($value);
if ($expiresAfter) {
$item->expiresAfter($expiresAfter);
}
$cache->save($item);
};
$doSet('foo', 'foo-val', new \DateInterval('PT05S'));
$doSet('bar', 'bar-val', new \DateInterval('PT10S'));
$doSet('baz', 'baz-val', new \DateInterval('PT15S'));
$doSet('qux', 'qux-val', new \DateInterval('PT20S'));
sleep(30);
$cache->prune();
$this->assertTrue($this->isPruned($cache, 'foo'));
$this->assertTrue($this->isPruned($cache, 'bar'));
$this->assertTrue($this->isPruned($cache, 'baz'));
$this->assertTrue($this->isPruned($cache, 'qux'));
$doSet('foo', 'foo-val');
$doSet('bar', 'bar-val', new \DateInterval('PT20S'));
$doSet('baz', 'baz-val', new \DateInterval('PT40S'));
$doSet('qux', 'qux-val', new \DateInterval('PT80S'));
$cache->prune();
$this->assertFalse($this->isPruned($cache, 'foo'));
$this->assertFalse($this->isPruned($cache, 'bar'));
$this->assertFalse($this->isPruned($cache, 'baz'));
$this->assertFalse($this->isPruned($cache, 'qux'));
sleep(30);
$cache->prune();
$this->assertFalse($this->isPruned($cache, 'foo'));
$this->assertTrue($this->isPruned($cache, 'bar'));
$this->assertFalse($this->isPruned($cache, 'baz'));
$this->assertFalse($this->isPruned($cache, 'qux'));
sleep(30);
$cache->prune();
$this->assertFalse($this->isPruned($cache, 'foo'));
$this->assertTrue($this->isPruned($cache, 'baz'));
$this->assertFalse($this->isPruned($cache, 'qux'));
sleep(30);
$cache->prune();
$this->assertFalse($this->isPruned($cache, 'foo'));
$this->assertTrue($this->isPruned($cache, 'qux'));
}
}
class NotUnserializable implements \Serializable
{
public function serialize()
{
return serialize(123);
}
public function unserialize($ser)
{
throw new \Exception(__CLASS__);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use Psr\Log\NullLogger;
use Symfony\Component\Cache\Adapter\ApcuAdapter;
class ApcuAdapterTest extends AdapterTestCase
{
protected $skippedTests = array(
'testExpiration' => 'Testing expiration slows down the test suite',
'testHasItemReturnsFalseWhenDeferredItemIsExpired' => 'Testing expiration slows down the test suite',
'testDefaultLifeTime' => 'Testing expiration slows down the test suite',
);
public function createCachePool($defaultLifetime = 0)
{
if (!\function_exists('apcu_fetch') || !ini_get('apc.enabled')) {
$this->markTestSkipped('APCu extension is required.');
}
if ('cli' === \PHP_SAPI && !ini_get('apc.enable_cli')) {
if ('testWithCliSapi' !== $this->getName()) {
$this->markTestSkipped('apc.enable_cli=1 is required.');
}
}
if ('\\' === \DIRECTORY_SEPARATOR) {
$this->markTestSkipped('Fails transiently on Windows.');
}
return new ApcuAdapter(str_replace('\\', '.', __CLASS__), $defaultLifetime);
}
public function testUnserializable()
{
$pool = $this->createCachePool();
$item = $pool->getItem('foo');
$item->set(function () {});
$this->assertFalse($pool->save($item));
$item = $pool->getItem('foo');
$this->assertFalse($item->isHit());
}
public function testVersion()
{
$namespace = str_replace('\\', '.', \get_class($this));
$pool1 = new ApcuAdapter($namespace, 0, 'p1');
$item = $pool1->getItem('foo');
$this->assertFalse($item->isHit());
$this->assertTrue($pool1->save($item->set('bar')));
$item = $pool1->getItem('foo');
$this->assertTrue($item->isHit());
$this->assertSame('bar', $item->get());
$pool2 = new ApcuAdapter($namespace, 0, 'p2');
$item = $pool2->getItem('foo');
$this->assertFalse($item->isHit());
$this->assertNull($item->get());
$item = $pool1->getItem('foo');
$this->assertFalse($item->isHit());
$this->assertNull($item->get());
}
public function testNamespace()
{
$namespace = str_replace('\\', '.', \get_class($this));
$pool1 = new ApcuAdapter($namespace.'_1', 0, 'p1');
$item = $pool1->getItem('foo');
$this->assertFalse($item->isHit());
$this->assertTrue($pool1->save($item->set('bar')));
$item = $pool1->getItem('foo');
$this->assertTrue($item->isHit());
$this->assertSame('bar', $item->get());
$pool2 = new ApcuAdapter($namespace.'_2', 0, 'p1');
$item = $pool2->getItem('foo');
$this->assertFalse($item->isHit());
$this->assertNull($item->get());
$item = $pool1->getItem('foo');
$this->assertTrue($item->isHit());
$this->assertSame('bar', $item->get());
}
public function testWithCliSapi()
{
try {
// disable PHPUnit error handler to mimic a production environment
$isCalled = false;
set_error_handler(function () use (&$isCalled) {
$isCalled = true;
});
$pool = new ApcuAdapter(str_replace('\\', '.', __CLASS__));
$pool->setLogger(new NullLogger());
$item = $pool->getItem('foo');
$item->isHit();
$pool->save($item->set('bar'));
$this->assertFalse($isCalled);
} finally {
restore_error_handler();
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
/**
* @group time-sensitive
*/
class ArrayAdapterTest extends AdapterTestCase
{
protected $skippedTests = array(
'testDeferredSaveWithoutCommit' => 'Assumes a shared cache which ArrayAdapter is not.',
'testSaveWithoutExpire' => 'Assumes a shared cache which ArrayAdapter is not.',
);
public function createCachePool($defaultLifetime = 0)
{
return new ArrayAdapter($defaultLifetime);
}
public function testGetValuesHitAndMiss()
{
/** @var ArrayAdapter $cache */
$cache = $this->createCachePool();
// Hit
$item = $cache->getItem('foo');
$item->set('4711');
$cache->save($item);
$fooItem = $cache->getItem('foo');
$this->assertTrue($fooItem->isHit());
$this->assertEquals('4711', $fooItem->get());
// Miss (should be present as NULL in $values)
$cache->getItem('bar');
$values = $cache->getValues();
$this->assertCount(2, $values);
$this->assertArrayHasKey('foo', $values);
$this->assertSame(serialize('4711'), $values['foo']);
$this->assertArrayHasKey('bar', $values);
$this->assertNull($values['bar']);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use Symfony\Component\Cache\Adapter\AdapterInterface;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\Adapter\ChainAdapter;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\Tests\Fixtures\ExternalAdapter;
/**
* @author Kévin Dunglas <[email protected]>
* @group time-sensitive
*/
class ChainAdapterTest extends AdapterTestCase
{
public function createCachePool($defaultLifetime = 0)
{
return new ChainAdapter(array(new ArrayAdapter($defaultLifetime), new ExternalAdapter(), new FilesystemAdapter('', $defaultLifetime)), $defaultLifetime);
}
/**
* @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException
* @expectedExceptionMessage At least one adapter must be specified.
*/
public function testEmptyAdaptersException()
{
new ChainAdapter(array());
}
/**
* @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException
* @expectedExceptionMessage The class "stdClass" does not implement
*/
public function testInvalidAdapterException()
{
new ChainAdapter(array(new \stdClass()));
}
public function testPrune()
{
if (isset($this->skippedTests[__FUNCTION__])) {
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
}
$cache = new ChainAdapter(array(
$this->getPruneableMock(),
$this->getNonPruneableMock(),
$this->getPruneableMock(),
));
$this->assertTrue($cache->prune());
$cache = new ChainAdapter(array(
$this->getPruneableMock(),
$this->getFailingPruneableMock(),
$this->getPruneableMock(),
));
$this->assertFalse($cache->prune());
}
/**
* @return \PHPUnit_Framework_MockObject_MockObject|PruneableCacheInterface
*/
private function getPruneableMock()
{
$pruneable = $this
->getMockBuilder(PruneableCacheInterface::class)
->getMock();
$pruneable
->expects($this->atLeastOnce())
->method('prune')
->will($this->returnValue(true));
return $pruneable;
}
/**
* @return \PHPUnit_Framework_MockObject_MockObject|PruneableCacheInterface
*/
private function getFailingPruneableMock()
{
$pruneable = $this
->getMockBuilder(PruneableCacheInterface::class)
->getMock();
$pruneable
->expects($this->atLeastOnce())
->method('prune')
->will($this->returnValue(false));
return $pruneable;
}
/**
* @return \PHPUnit_Framework_MockObject_MockObject|AdapterInterface
*/
private function getNonPruneableMock()
{
return $this
->getMockBuilder(AdapterInterface::class)
->getMock();
}
}
interface PruneableCacheInterface extends PruneableInterface, AdapterInterface
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use Symfony\Component\Cache\Adapter\DoctrineAdapter;
use Symfony\Component\Cache\Tests\Fixtures\ArrayCache;
/**
* @group time-sensitive
*/
class DoctrineAdapterTest extends AdapterTestCase
{
protected $skippedTests = array(
'testDeferredSaveWithoutCommit' => 'Assumes a shared cache which ArrayCache is not.',
'testSaveWithoutExpire' => 'Assumes a shared cache which ArrayCache is not.',
'testNotUnserializable' => 'ArrayCache does not use serialize/unserialize',
);
public function createCachePool($defaultLifetime = 0)
{
return new DoctrineAdapter(new ArrayCache($defaultLifetime), '', $defaultLifetime);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
/**
* @group time-sensitive
*/
class FilesystemAdapterTest extends AdapterTestCase
{
public function createCachePool($defaultLifetime = 0)
{
return new FilesystemAdapter('', $defaultLifetime);
}
public static function tearDownAfterClass()
{
self::rmdir(sys_get_temp_dir().'/symfony-cache');
}
public static function rmdir($dir)
{
if (!file_exists($dir)) {
return;
}
if (!$dir || 0 !== strpos(\dirname($dir), sys_get_temp_dir())) {
throw new \Exception(__METHOD__."() operates only on subdirs of system's temp dir");
}
$children = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS),
\RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($children as $child) {
if ($child->isDir()) {
rmdir($child);
} else {
unlink($child);
}
}
rmdir($dir);
}
protected function isPruned(CacheItemPoolInterface $cache, $name)
{
$getFileMethod = (new \ReflectionObject($cache))->getMethod('getFile');
$getFileMethod->setAccessible(true);
return !file_exists($getFileMethod->invoke($cache, $name));
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Cache\Adapter\AbstractAdapter;
class MaxIdLengthAdapterTest extends TestCase
{
public function testLongKey()
{
$cache = $this->getMockBuilder(MaxIdLengthAdapter::class)
->setConstructorArgs(array(str_repeat('-', 10)))
->setMethods(array('doHave', 'doFetch', 'doDelete', 'doSave', 'doClear'))
->getMock();
$cache->expects($this->exactly(2))
->method('doHave')
->withConsecutive(
array($this->equalTo('----------:0GTYWa9n4ed8vqNlOT2iEr:')),
array($this->equalTo('----------:---------------------------------------'))
);
$cache->hasItem(str_repeat('-', 40));
$cache->hasItem(str_repeat('-', 39));
}
public function testLongKeyVersioning()
{
$cache = $this->getMockBuilder(MaxIdLengthAdapter::class)
->setConstructorArgs(array(str_repeat('-', 26)))
->getMock();
$reflectionClass = new \ReflectionClass(AbstractAdapter::class);
$reflectionMethod = $reflectionClass->getMethod('getId');
$reflectionMethod->setAccessible(true);
// No versioning enabled
$this->assertEquals('--------------------------:------------', $reflectionMethod->invokeArgs($cache, array(str_repeat('-', 12))));
$this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, array(str_repeat('-', 12)))));
$this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, array(str_repeat('-', 23)))));
$this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, array(str_repeat('-', 40)))));
$reflectionProperty = $reflectionClass->getProperty('versioningIsEnabled');
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue($cache, true);
// Versioning enabled
$this->assertEquals('--------------------------:1:------------', $reflectionMethod->invokeArgs($cache, array(str_repeat('-', 12))));
$this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, array(str_repeat('-', 12)))));
$this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, array(str_repeat('-', 23)))));
$this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, array(str_repeat('-', 40)))));
}
/**
* @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException
* @expectedExceptionMessage Namespace must be 26 chars max, 40 given ("----------------------------------------")
*/
public function testTooLongNamespace()
{
$cache = $this->getMockBuilder(MaxIdLengthAdapter::class)
->setConstructorArgs(array(str_repeat('-', 40)))
->getMock();
}
}
abstract class MaxIdLengthAdapter extends AbstractAdapter
{
protected $maxIdLength = 50;
public function __construct($ns)
{
parent::__construct($ns);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use Symfony\Component\Cache\Adapter\AbstractAdapter;
use Symfony\Component\Cache\Adapter\MemcachedAdapter;
class MemcachedAdapterTest extends AdapterTestCase
{
protected $skippedTests = array(
'testHasItemReturnsFalseWhenDeferredItemIsExpired' => 'Testing expiration slows down the test suite',
'testDefaultLifeTime' => 'Testing expiration slows down the test suite',
);
protected static $client;
public static function setupBeforeClass()
{
if (!MemcachedAdapter::isSupported()) {
self::markTestSkipped('Extension memcached >=2.2.0 required.');
}
self::$client = AbstractAdapter::createConnection('memcached://'.getenv('MEMCACHED_HOST'), array('binary_protocol' => false));
self::$client->get('foo');
$code = self::$client->getResultCode();
if (\Memcached::RES_SUCCESS !== $code && \Memcached::RES_NOTFOUND !== $code) {
self::markTestSkipped('Memcached error: '.strtolower(self::$client->getResultMessage()));
}
}
public function createCachePool($defaultLifetime = 0)
{
$client = $defaultLifetime ? AbstractAdapter::createConnection('memcached://'.getenv('MEMCACHED_HOST')) : self::$client;
return new MemcachedAdapter($client, str_replace('\\', '.', __CLASS__), $defaultLifetime);
}
public function testOptions()
{
$client = MemcachedAdapter::createConnection(array(), array(
'libketama_compatible' => false,
'distribution' => 'modula',
'compression' => true,
'serializer' => 'php',
'hash' => 'md5',
));
$this->assertSame(\Memcached::SERIALIZER_PHP, $client->getOption(\Memcached::OPT_SERIALIZER));
$this->assertSame(\Memcached::HASH_MD5, $client->getOption(\Memcached::OPT_HASH));
$this->assertTrue($client->getOption(\Memcached::OPT_COMPRESSION));
$this->assertSame(0, $client->getOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE));
$this->assertSame(\Memcached::DISTRIBUTION_MODULA, $client->getOption(\Memcached::OPT_DISTRIBUTION));
}
/**
* @dataProvider provideBadOptions
* @expectedException \ErrorException
* @expectedExceptionMessage constant(): Couldn't find constant Memcached::
*/
public function testBadOptions($name, $value)
{
MemcachedAdapter::createConnection(array(), array($name => $value));
}
public function provideBadOptions()
{
return array(
array('foo', 'bar'),
array('hash', 'zyx'),
array('serializer', 'zyx'),
array('distribution', 'zyx'),
);
}
public function testDefaultOptions()
{
$this->assertTrue(MemcachedAdapter::isSupported());
$client = MemcachedAdapter::createConnection(array());
$this->assertTrue($client->getOption(\Memcached::OPT_COMPRESSION));
$this->assertSame(1, $client->getOption(\Memcached::OPT_BINARY_PROTOCOL));
$this->assertSame(1, $client->getOption(\Memcached::OPT_TCP_NODELAY));
$this->assertSame(1, $client->getOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE));
}
/**
* @expectedException \Symfony\Component\Cache\Exception\CacheException
* @expectedExceptionMessage MemcachedAdapter: "serializer" option must be "php" or "igbinary".
*/
public function testOptionSerializer()
{
if (!\Memcached::HAVE_JSON) {
$this->markTestSkipped('Memcached::HAVE_JSON required');
}
new MemcachedAdapter(MemcachedAdapter::createConnection(array(), array('serializer' => 'json')));
}
/**
* @dataProvider provideServersSetting
*/
public function testServersSetting($dsn, $host, $port)
{
$client1 = MemcachedAdapter::createConnection($dsn);
$client2 = MemcachedAdapter::createConnection(array($dsn));
$client3 = MemcachedAdapter::createConnection(array(array($host, $port)));
$expect = array(
'host' => $host,
'port' => $port,
);
$f = function ($s) { return array('host' => $s['host'], 'port' => $s['port']); };
$this->assertSame(array($expect), array_map($f, $client1->getServerList()));
$this->assertSame(array($expect), array_map($f, $client2->getServerList()));
$this->assertSame(array($expect), array_map($f, $client3->getServerList()));
}
public function provideServersSetting()
{
yield array(
'memcached://127.0.0.1/50',
'127.0.0.1',
11211,
);
yield array(
'memcached://localhost:11222?weight=25',
'localhost',
11222,
);
if (ini_get('memcached.use_sasl')) {
yield array(
'memcached://user:[email protected]?weight=50',
'127.0.0.1',
11211,
);
}
yield array(
'memcached:///var/run/memcached.sock?weight=25',
'/var/run/memcached.sock',
0,
);
yield array(
'memcached:///var/local/run/memcached.socket?weight=25',
'/var/local/run/memcached.socket',
0,
);
if (ini_get('memcached.use_sasl')) {
yield array(
'memcached://user:password@/var/local/run/memcached.socket?weight=25',
'/var/local/run/memcached.socket',
0,
);
}
}
/**
* @dataProvider provideDsnWithOptions
*/
public function testDsnWithOptions($dsn, array $options, array $expectedOptions)
{
$client = MemcachedAdapter::createConnection($dsn, $options);
foreach ($expectedOptions as $option => $expect) {
$this->assertSame($expect, $client->getOption($option));
}
}
public function provideDsnWithOptions()
{
if (!class_exists('\Memcached')) {
self::markTestSkipped('Extension memcached required.');
}
yield array(
'memcached://localhost:11222?retry_timeout=10',
array(\Memcached::OPT_RETRY_TIMEOUT => 8),
array(\Memcached::OPT_RETRY_TIMEOUT => 10),
);
yield array(
'memcached://localhost:11222?socket_recv_size=1&socket_send_size=2',
array(\Memcached::OPT_RETRY_TIMEOUT => 8),
array(\Memcached::OPT_SOCKET_RECV_SIZE => 1, \Memcached::OPT_SOCKET_SEND_SIZE => 2, \Memcached::OPT_RETRY_TIMEOUT => 8),
);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\Adapter\ProxyAdapter;
/**
* @group time-sensitive
*/
class NamespacedProxyAdapterTest extends ProxyAdapterTest
{
public function createCachePool($defaultLifetime = 0)
{
return new ProxyAdapter(new ArrayAdapter($defaultLifetime), 'foo', $defaultLifetime);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use PHPUnit\Framework\TestCase;
use Psr\Cache\CacheItemInterface;
use Symfony\Component\Cache\Adapter\NullAdapter;
/**
* @group time-sensitive
*/
class NullAdapterTest extends TestCase
{
public function createCachePool()
{
return new NullAdapter();
}
public function testGetItem()
{
$adapter = $this->createCachePool();
$item = $adapter->getItem('key');
$this->assertFalse($item->isHit());
$this->assertNull($item->get(), "Item's value must be null when isHit is false.");
}
public function testHasItem()
{
$this->assertFalse($this->createCachePool()->hasItem('key'));
}
public function testGetItems()
{
$adapter = $this->createCachePool();
$keys = array('foo', 'bar', 'baz', 'biz');
/** @var CacheItemInterface[] $items */
$items = $adapter->getItems($keys);
$count = 0;
foreach ($items as $key => $item) {
$itemKey = $item->getKey();
$this->assertEquals($itemKey, $key, 'Keys must be preserved when fetching multiple items');
$this->assertContains($key, $keys, 'Cache key can not change.');
$this->assertFalse($item->isHit());
// Remove $key for $keys
foreach ($keys as $k => $v) {
if ($v === $key) {
unset($keys[$k]);
}
}
++$count;
}
$this->assertSame(4, $count);
}
public function testIsHit()
{
$adapter = $this->createCachePool();
$item = $adapter->getItem('key');
$this->assertFalse($item->isHit());
}
public function testClear()
{
$this->assertTrue($this->createCachePool()->clear());
}
public function testDeleteItem()
{
$this->assertTrue($this->createCachePool()->deleteItem('key'));
}
public function testDeleteItems()
{
$this->assertTrue($this->createCachePool()->deleteItems(array('key', 'foo', 'bar')));
}
public function testSave()
{
$adapter = $this->createCachePool();
$item = $adapter->getItem('key');
$this->assertFalse($item->isHit());
$this->assertNull($item->get(), "Item's value must be null when isHit is false.");
$this->assertFalse($adapter->save($item));
}
public function testDeferredSave()
{
$adapter = $this->createCachePool();
$item = $adapter->getItem('key');
$this->assertFalse($item->isHit());
$this->assertNull($item->get(), "Item's value must be null when isHit is false.");
$this->assertFalse($adapter->saveDeferred($item));
}
public function testCommit()
{
$adapter = $this->createCachePool();
$item = $adapter->getItem('key');
$this->assertFalse($item->isHit());
$this->assertNull($item->get(), "Item's value must be null when isHit is false.");
$this->assertFalse($adapter->saveDeferred($item));
$this->assertFalse($this->createCachePool()->commit());
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use Symfony\Component\Cache\Adapter\PdoAdapter;
use Symfony\Component\Cache\Tests\Traits\PdoPruneableTrait;
/**
* @group time-sensitive
*/
class PdoAdapterTest extends AdapterTestCase
{
use PdoPruneableTrait;
protected static $dbFile;
public static function setupBeforeClass()
{
if (!\extension_loaded('pdo_sqlite')) {
self::markTestSkipped('Extension pdo_sqlite required.');
}
self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
$pool = new PdoAdapter('sqlite:'.self::$dbFile);
$pool->createTable();
}
public static function tearDownAfterClass()
{
@unlink(self::$dbFile);
}
public function createCachePool($defaultLifetime = 0)
{
return new PdoAdapter('sqlite:'.self::$dbFile, 'ns', $defaultLifetime);
}
public function testCleanupExpiredItems()
{
$pdo = new \PDO('sqlite:'.self::$dbFile);
$getCacheItemCount = function () use ($pdo) {
return (int) $pdo->query('SELECT COUNT(*) FROM cache_items')->fetch(\PDO::FETCH_COLUMN);
};
$this->assertSame(0, $getCacheItemCount());
$cache = $this->createCachePool();
$item = $cache->getItem('some_nice_key');
$item->expiresAfter(1);
$item->set(1);
$cache->save($item);
$this->assertSame(1, $getCacheItemCount());
sleep(2);
$newItem = $cache->getItem($item->getKey());
$this->assertFalse($newItem->isHit());
$this->assertSame(0, $getCacheItemCount(), 'PDOAdapter must clean up expired items');
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use Doctrine\DBAL\DriverManager;
use Symfony\Component\Cache\Adapter\PdoAdapter;
use Symfony\Component\Cache\Tests\Traits\PdoPruneableTrait;
/**
* @group time-sensitive
*/
class PdoDbalAdapterTest extends AdapterTestCase
{
use PdoPruneableTrait;
protected static $dbFile;
public static function setupBeforeClass()
{
if (!\extension_loaded('pdo_sqlite')) {
self::markTestSkipped('Extension pdo_sqlite required.');
}
self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
$pool = new PdoAdapter(DriverManager::getConnection(array('driver' => 'pdo_sqlite', 'path' => self::$dbFile)));
$pool->createTable();
}
public static function tearDownAfterClass()
{
@unlink(self::$dbFile);
}
public function createCachePool($defaultLifetime = 0)
{
return new PdoAdapter(DriverManager::getConnection(array('driver' => 'pdo_sqlite', 'path' => self::$dbFile)), '', $defaultLifetime);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use Psr\Cache\CacheItemInterface;
use Symfony\Component\Cache\Adapter\NullAdapter;
use Symfony\Component\Cache\Adapter\PhpArrayAdapter;
/**
* @group time-sensitive
*/
class PhpArrayAdapterTest extends AdapterTestCase
{
protected $skippedTests = array(
'testBasicUsage' => 'PhpArrayAdapter is read-only.',
'testBasicUsageWithLongKey' => 'PhpArrayAdapter is read-only.',
'testClear' => 'PhpArrayAdapter is read-only.',
'testClearWithDeferredItems' => 'PhpArrayAdapter is read-only.',
'testDeleteItem' => 'PhpArrayAdapter is read-only.',
'testSaveExpired' => 'PhpArrayAdapter is read-only.',
'testSaveWithoutExpire' => 'PhpArrayAdapter is read-only.',
'testDeferredSave' => 'PhpArrayAdapter is read-only.',
'testDeferredSaveWithoutCommit' => 'PhpArrayAdapter is read-only.',
'testDeleteItems' => 'PhpArrayAdapter is read-only.',
'testDeleteDeferredItem' => 'PhpArrayAdapter is read-only.',
'testCommit' => 'PhpArrayAdapter is read-only.',
'testSaveDeferredWhenChangingValues' => 'PhpArrayAdapter is read-only.',
'testSaveDeferredOverwrite' => 'PhpArrayAdapter is read-only.',
'testIsHitDeferred' => 'PhpArrayAdapter is read-only.',
'testExpiresAt' => 'PhpArrayAdapter does not support expiration.',
'testExpiresAtWithNull' => 'PhpArrayAdapter does not support expiration.',
'testExpiresAfterWithNull' => 'PhpArrayAdapter does not support expiration.',
'testDeferredExpired' => 'PhpArrayAdapter does not support expiration.',
'testExpiration' => 'PhpArrayAdapter does not support expiration.',
'testGetItemInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
'testGetItemsInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
'testHasItemInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
'testDeleteItemInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
'testDeleteItemsInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
'testDefaultLifeTime' => 'PhpArrayAdapter does not allow configuring a default lifetime.',
'testPrune' => 'PhpArrayAdapter just proxies',
);
protected static $file;
public static function setupBeforeClass()
{
self::$file = sys_get_temp_dir().'/symfony-cache/php-array-adapter-test.php';
}
protected function tearDown()
{
if (file_exists(sys_get_temp_dir().'/symfony-cache')) {
FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache');
}
}
public function createCachePool()
{
return new PhpArrayAdapterWrapper(self::$file, new NullAdapter());
}
public function testStore()
{
$arrayWithRefs = array();
$arrayWithRefs[0] = 123;
$arrayWithRefs[1] = &$arrayWithRefs[0];
$object = (object) array(
'foo' => 'bar',
'foo2' => 'bar2',
);
$expected = array(
'null' => null,
'serializedString' => serialize($object),
'arrayWithRefs' => $arrayWithRefs,
'object' => $object,
'arrayWithObject' => array('bar' => $object),
);
$adapter = $this->createCachePool();
$adapter->warmUp($expected);
foreach ($expected as $key => $value) {
$this->assertSame(serialize($value), serialize($adapter->getItem($key)->get()), 'Warm up should create a PHP file that OPCache can load in memory');
}
}
public function testStoredFile()
{
$expected = array(
'integer' => 42,
'float' => 42.42,
'boolean' => true,
'array_simple' => array('foo', 'bar'),
'array_associative' => array('foo' => 'bar', 'foo2' => 'bar2'),
);
$adapter = $this->createCachePool();
$adapter->warmUp($expected);
$values = eval(substr(file_get_contents(self::$file), 6));
$this->assertSame($expected, $values, 'Warm up should create a PHP file that OPCache can load in memory');
}
}
class PhpArrayAdapterWrapper extends PhpArrayAdapter
{
public function save(CacheItemInterface $item)
{
\call_user_func(\Closure::bind(function () use ($item) {
$this->values[$item->getKey()] = $item->get();
$this->warmUp($this->values);
$this->values = eval(substr(file_get_contents($this->file), 6));
}, $this, PhpArrayAdapter::class));
return true;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Adapter\PhpArrayAdapter;
/**
* @group time-sensitive
*/
class PhpArrayAdapterWithFallbackTest extends AdapterTestCase
{
protected $skippedTests = array(
'testGetItemInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
'testGetItemsInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
'testHasItemInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
'testDeleteItemInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
'testDeleteItemsInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
'testPrune' => 'PhpArrayAdapter just proxies',
);
protected static $file;
public static function setupBeforeClass()
{
self::$file = sys_get_temp_dir().'/symfony-cache/php-array-adapter-test.php';
}
protected function tearDown()
{
if (file_exists(sys_get_temp_dir().'/symfony-cache')) {
FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache');
}
}
public function createCachePool($defaultLifetime = 0)
{
return new PhpArrayAdapter(self::$file, new FilesystemAdapter('php-array-fallback', $defaultLifetime));
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\Adapter\PhpFilesAdapter;
/**
* @group time-sensitive
*/
class PhpFilesAdapterTest extends AdapterTestCase
{
protected $skippedTests = array(
'testDefaultLifeTime' => 'PhpFilesAdapter does not allow configuring a default lifetime.',
);
public function createCachePool()
{
if (!PhpFilesAdapter::isSupported()) {
$this->markTestSkipped('OPcache extension is not enabled.');
}
return new PhpFilesAdapter('sf-cache');
}
public static function tearDownAfterClass()
{
FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache');
}
protected function isPruned(CacheItemPoolInterface $cache, $name)
{
$getFileMethod = (new \ReflectionObject($cache))->getMethod('getFile');
$getFileMethod->setAccessible(true);
return !file_exists($getFileMethod->invoke($cache, $name));
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use Predis\Connection\StreamConnection;
use Symfony\Component\Cache\Adapter\RedisAdapter;
class PredisAdapterTest extends AbstractRedisAdapterTest
{
public static function setupBeforeClass()
{
parent::setupBeforeClass();
self::$redis = new \Predis\Client(array('host' => getenv('REDIS_HOST')));
}
public function testCreateConnection()
{
$redisHost = getenv('REDIS_HOST');
$redis = RedisAdapter::createConnection('redis://'.$redisHost.'/1', array('class' => \Predis\Client::class, 'timeout' => 3));
$this->assertInstanceOf(\Predis\Client::class, $redis);
$connection = $redis->getConnection();
$this->assertInstanceOf(StreamConnection::class, $connection);
$params = array(
'scheme' => 'tcp',
'host' => $redisHost,
'path' => '',
'dbindex' => '1',
'port' => 6379,
'class' => 'Predis\Client',
'timeout' => 3,
'persistent' => 0,
'persistent_id' => null,
'read_timeout' => 0,
'retry_interval' => 0,
'lazy' => false,
'database' => '1',
'password' => null,
);
$this->assertSame($params, $connection->getParameters()->toArray());
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
class PredisClusterAdapterTest extends AbstractRedisAdapterTest
{
public static function setupBeforeClass()
{
parent::setupBeforeClass();
self::$redis = new \Predis\Client(array(array('host' => getenv('REDIS_HOST'))));
}
public static function tearDownAfterClass()
{
self::$redis = null;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use Psr\Cache\CacheItemInterface;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\Adapter\ProxyAdapter;
use Symfony\Component\Cache\CacheItem;
/**
* @group time-sensitive
*/
class ProxyAdapterTest extends AdapterTestCase
{
protected $skippedTests = array(
'testDeferredSaveWithoutCommit' => 'Assumes a shared cache which ArrayAdapter is not.',
'testSaveWithoutExpire' => 'Assumes a shared cache which ArrayAdapter is not.',
'testPrune' => 'ProxyAdapter just proxies',
);
public function createCachePool($defaultLifetime = 0)
{
return new ProxyAdapter(new ArrayAdapter(), '', $defaultLifetime);
}
/**
* @expectedException \Exception
* @expectedExceptionMessage OK bar
*/
public function testProxyfiedItem()
{
$item = new CacheItem();
$pool = new ProxyAdapter(new TestingArrayAdapter($item));
$proxyItem = $pool->getItem('foo');
$this->assertNotSame($item, $proxyItem);
$pool->save($proxyItem->set('bar'));
}
}
class TestingArrayAdapter extends ArrayAdapter
{
private $item;
public function __construct(CacheItemInterface $item)
{
$this->item = $item;
}
public function getItem($key)
{
return $this->item;
}
public function save(CacheItemInterface $item)
{
if ($item === $this->item) {
throw new \Exception('OK '.$item->get());
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use Symfony\Component\Cache\Adapter\AbstractAdapter;
use Symfony\Component\Cache\Adapter\RedisAdapter;
use Symfony\Component\Cache\Traits\RedisProxy;
class RedisAdapterTest extends AbstractRedisAdapterTest
{
public static function setupBeforeClass()
{
parent::setupBeforeClass();
self::$redis = AbstractAdapter::createConnection('redis://'.getenv('REDIS_HOST'), array('lazy' => true));
}
public function createCachePool($defaultLifetime = 0)
{
$adapter = parent::createCachePool($defaultLifetime);
$this->assertInstanceOf(RedisProxy::class, self::$redis);
return $adapter;
}
public function testCreateConnection()
{
$redisHost = getenv('REDIS_HOST');
$redis = RedisAdapter::createConnection('redis://'.$redisHost);
$this->assertInstanceOf(\Redis::class, $redis);
$this->assertTrue($redis->isConnected());
$this->assertSame(0, $redis->getDbNum());
$redis = RedisAdapter::createConnection('redis://'.$redisHost.'/2');
$this->assertSame(2, $redis->getDbNum());
$redis = RedisAdapter::createConnection('redis://'.$redisHost, array('timeout' => 3));
$this->assertEquals(3, $redis->getTimeout());
$redis = RedisAdapter::createConnection('redis://'.$redisHost.'?timeout=4');
$this->assertEquals(4, $redis->getTimeout());
$redis = RedisAdapter::createConnection('redis://'.$redisHost, array('read_timeout' => 5));
$this->assertEquals(5, $redis->getReadTimeout());
}
/**
* @dataProvider provideFailedCreateConnection
* @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException
* @expectedExceptionMessage Redis connection failed
*/
public function testFailedCreateConnection($dsn)
{
RedisAdapter::createConnection($dsn);
}
public function provideFailedCreateConnection()
{
return array(
array('redis://localhost:1234'),
array('redis://foo@localhost'),
array('redis://localhost/123'),
);
}
/**
* @dataProvider provideInvalidCreateConnection
* @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException
* @expectedExceptionMessage Invalid Redis DSN
*/
public function testInvalidCreateConnection($dsn)
{
RedisAdapter::createConnection($dsn);
}
public function provideInvalidCreateConnection()
{
return array(
array('foo://localhost'),
array('redis://'),
);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
class RedisArrayAdapterTest extends AbstractRedisAdapterTest
{
public static function setupBeforeClass()
{
parent::setupBeforeClass();
if (!class_exists('RedisArray')) {
self::markTestSkipped('The RedisArray class is required.');
}
self::$redis = new \RedisArray(array(getenv('REDIS_HOST')), array('lazy_connect' => true));
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
class RedisClusterAdapterTest extends AbstractRedisAdapterTest
{
public static function setupBeforeClass()
{
if (!class_exists('RedisCluster')) {
self::markTestSkipped('The RedisCluster class is required.');
}
if (!$hosts = getenv('REDIS_CLUSTER_HOSTS')) {
self::markTestSkipped('REDIS_CLUSTER_HOSTS env var is not defined.');
}
self::$redis = new \RedisCluster(null, explode(' ', $hosts));
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use Symfony\Component\Cache\Adapter\SimpleCacheAdapter;
use Symfony\Component\Cache\Simple\FilesystemCache;
/**
* @group time-sensitive
*/
class SimpleCacheAdapterTest extends AdapterTestCase
{
protected $skippedTests = array(
'testPrune' => 'SimpleCache just proxies',
);
public function createCachePool($defaultLifetime = 0)
{
return new SimpleCacheAdapter(new FilesystemCache(), '', $defaultLifetime);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use Symfony\Component\Cache\Adapter\AdapterInterface;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
/**
* @group time-sensitive
*/
class TagAwareAdapterTest extends AdapterTestCase
{
public function createCachePool($defaultLifetime = 0)
{
return new TagAwareAdapter(new FilesystemAdapter('', $defaultLifetime));
}
public static function tearDownAfterClass()
{
FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache');
}
/**
* @expectedException \Psr\Cache\InvalidArgumentException
*/
public function testInvalidTag()
{
$pool = $this->createCachePool();
$item = $pool->getItem('foo');
$item->tag(':');
}
public function testInvalidateTags()
{
$pool = $this->createCachePool();
$i0 = $pool->getItem('i0');
$i1 = $pool->getItem('i1');
$i2 = $pool->getItem('i2');
$i3 = $pool->getItem('i3');
$foo = $pool->getItem('foo');
$pool->save($i0->tag('bar'));
$pool->save($i1->tag('foo'));
$pool->save($i2->tag('foo')->tag('bar'));
$pool->save($i3->tag('foo')->tag('baz'));
$pool->save($foo);
$pool->invalidateTags(array('bar'));
$this->assertFalse($pool->getItem('i0')->isHit());
$this->assertTrue($pool->getItem('i1')->isHit());
$this->assertFalse($pool->getItem('i2')->isHit());
$this->assertTrue($pool->getItem('i3')->isHit());
$this->assertTrue($pool->getItem('foo')->isHit());
$pool->invalidateTags(array('foo'));
$this->assertFalse($pool->getItem('i1')->isHit());
$this->assertFalse($pool->getItem('i3')->isHit());
$this->assertTrue($pool->getItem('foo')->isHit());
$anotherPoolInstance = $this->createCachePool();
$this->assertFalse($anotherPoolInstance->getItem('i1')->isHit());
$this->assertFalse($anotherPoolInstance->getItem('i3')->isHit());
$this->assertTrue($anotherPoolInstance->getItem('foo')->isHit());
}
public function testInvalidateCommits()
{
$pool1 = $this->createCachePool();
$foo = $pool1->getItem('foo');
$foo->tag('tag');
$pool1->saveDeferred($foo->set('foo'));
$pool1->invalidateTags(array('tag'));
$pool2 = $this->createCachePool();
$foo = $pool2->getItem('foo');
$this->assertTrue($foo->isHit());
}
public function testTagsAreCleanedOnSave()
{
$pool = $this->createCachePool();
$i = $pool->getItem('k');
$pool->save($i->tag('foo'));
$i = $pool->getItem('k');
$pool->save($i->tag('bar'));
$pool->invalidateTags(array('foo'));
$this->assertTrue($pool->getItem('k')->isHit());
}
public function testTagsAreCleanedOnDelete()
{
$pool = $this->createCachePool();
$i = $pool->getItem('k');
$pool->save($i->tag('foo'));
$pool->deleteItem('k');
$pool->save($pool->getItem('k'));
$pool->invalidateTags(array('foo'));
$this->assertTrue($pool->getItem('k')->isHit());
}
public function testTagItemExpiry()
{
$pool = $this->createCachePool(10);
$item = $pool->getItem('foo');
$item->tag(array('baz'));
$item->expiresAfter(100);
$pool->save($item);
$pool->invalidateTags(array('baz'));
$this->assertFalse($pool->getItem('foo')->isHit());
sleep(20);
$this->assertFalse($pool->getItem('foo')->isHit());
}
public function testGetPreviousTags()
{
$pool = $this->createCachePool();
$i = $pool->getItem('k');
$pool->save($i->tag('foo'));
$i = $pool->getItem('k');
$this->assertSame(array('foo' => 'foo'), $i->getPreviousTags());
}
public function testPrune()
{
$cache = new TagAwareAdapter($this->getPruneableMock());
$this->assertTrue($cache->prune());
$cache = new TagAwareAdapter($this->getNonPruneableMock());
$this->assertFalse($cache->prune());
$cache = new TagAwareAdapter($this->getFailingPruneableMock());
$this->assertFalse($cache->prune());
}
/**
* @return \PHPUnit_Framework_MockObject_MockObject|PruneableCacheInterface
*/
private function getPruneableMock()
{
$pruneable = $this
->getMockBuilder(PruneableCacheInterface::class)
->getMock();
$pruneable
->expects($this->atLeastOnce())
->method('prune')
->will($this->returnValue(true));
return $pruneable;
}
/**
* @return \PHPUnit_Framework_MockObject_MockObject|PruneableCacheInterface
*/
private function getFailingPruneableMock()
{
$pruneable = $this
->getMockBuilder(PruneableCacheInterface::class)
->getMock();
$pruneable
->expects($this->atLeastOnce())
->method('prune')
->will($this->returnValue(false));
return $pruneable;
}
/**
* @return \PHPUnit_Framework_MockObject_MockObject|AdapterInterface
*/
private function getNonPruneableMock()
{
return $this
->getMockBuilder(AdapterInterface::class)
->getMock();
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Adapter\TraceableAdapter;
/**
* @group time-sensitive
*/
class TraceableAdapterTest extends AdapterTestCase
{
protected $skippedTests = array(
'testPrune' => 'TraceableAdapter just proxies',
);
public function createCachePool($defaultLifetime = 0)
{
return new TraceableAdapter(new FilesystemAdapter('', $defaultLifetime));
}
public function testGetItemMissTrace()
{
$pool = $this->createCachePool();
$pool->getItem('k');
$calls = $pool->getCalls();
$this->assertCount(1, $calls);
$call = $calls[0];
$this->assertSame('getItem', $call->name);
$this->assertSame(array('k' => false), $call->result);
$this->assertSame(0, $call->hits);
$this->assertSame(1, $call->misses);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
public function testGetItemHitTrace()
{
$pool = $this->createCachePool();
$item = $pool->getItem('k')->set('foo');
$pool->save($item);
$pool->getItem('k');
$calls = $pool->getCalls();
$this->assertCount(3, $calls);
$call = $calls[2];
$this->assertSame(1, $call->hits);
$this->assertSame(0, $call->misses);
}
public function testGetItemsMissTrace()
{
$pool = $this->createCachePool();
$arg = array('k0', 'k1');
$items = $pool->getItems($arg);
foreach ($items as $item) {
}
$calls = $pool->getCalls();
$this->assertCount(1, $calls);
$call = $calls[0];
$this->assertSame('getItems', $call->name);
$this->assertSame(array('k0' => false, 'k1' => false), $call->result);
$this->assertSame(2, $call->misses);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
public function testHasItemMissTrace()
{
$pool = $this->createCachePool();
$pool->hasItem('k');
$calls = $pool->getCalls();
$this->assertCount(1, $calls);
$call = $calls[0];
$this->assertSame('hasItem', $call->name);
$this->assertSame(array('k' => false), $call->result);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
public function testHasItemHitTrace()
{
$pool = $this->createCachePool();
$item = $pool->getItem('k')->set('foo');
$pool->save($item);
$pool->hasItem('k');
$calls = $pool->getCalls();
$this->assertCount(3, $calls);
$call = $calls[2];
$this->assertSame('hasItem', $call->name);
$this->assertSame(array('k' => true), $call->result);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
public function testDeleteItemTrace()
{
$pool = $this->createCachePool();
$pool->deleteItem('k');
$calls = $pool->getCalls();
$this->assertCount(1, $calls);
$call = $calls[0];
$this->assertSame('deleteItem', $call->name);
$this->assertSame(array('k' => true), $call->result);
$this->assertSame(0, $call->hits);
$this->assertSame(0, $call->misses);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
public function testDeleteItemsTrace()
{
$pool = $this->createCachePool();
$arg = array('k0', 'k1');
$pool->deleteItems($arg);
$calls = $pool->getCalls();
$this->assertCount(1, $calls);
$call = $calls[0];
$this->assertSame('deleteItems', $call->name);
$this->assertSame(array('keys' => $arg, 'result' => true), $call->result);
$this->assertSame(0, $call->hits);
$this->assertSame(0, $call->misses);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
public function testSaveTrace()
{
$pool = $this->createCachePool();
$item = $pool->getItem('k')->set('foo');
$pool->save($item);
$calls = $pool->getCalls();
$this->assertCount(2, $calls);
$call = $calls[1];
$this->assertSame('save', $call->name);
$this->assertSame(array('k' => true), $call->result);
$this->assertSame(0, $call->hits);
$this->assertSame(0, $call->misses);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
public function testSaveDeferredTrace()
{
$pool = $this->createCachePool();
$item = $pool->getItem('k')->set('foo');
$pool->saveDeferred($item);
$calls = $pool->getCalls();
$this->assertCount(2, $calls);
$call = $calls[1];
$this->assertSame('saveDeferred', $call->name);
$this->assertSame(array('k' => true), $call->result);
$this->assertSame(0, $call->hits);
$this->assertSame(0, $call->misses);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
public function testCommitTrace()
{
$pool = $this->createCachePool();
$pool->commit();
$calls = $pool->getCalls();
$this->assertCount(1, $calls);
$call = $calls[0];
$this->assertSame('commit', $call->name);
$this->assertTrue($call->result);
$this->assertSame(0, $call->hits);
$this->assertSame(0, $call->misses);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Adapter;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
use Symfony\Component\Cache\Adapter\TraceableTagAwareAdapter;
/**
* @group time-sensitive
*/
class TraceableTagAwareAdapterTest extends TraceableAdapterTest
{
public function testInvalidateTags()
{
$pool = new TraceableTagAwareAdapter(new TagAwareAdapter(new FilesystemAdapter()));
$pool->invalidateTags(array('foo'));
$calls = $pool->getCalls();
$this->assertCount(1, $calls);
$call = $calls[0];
$this->assertSame('invalidateTags', $call->name);
$this->assertSame(0, $call->hits);
$this->assertSame(0, $call->misses);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Cache\CacheItem;
class CacheItemTest extends TestCase
{
public function testValidKey()
{
$this->assertSame('foo', CacheItem::validateKey('foo'));
}
/**
* @dataProvider provideInvalidKey
* @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException
* @expectedExceptionMessage Cache key
*/
public function testInvalidKey($key)
{
CacheItem::validateKey($key);
}
public function provideInvalidKey()
{
return array(
array(''),
array('{'),
array('}'),
array('('),
array(')'),
array('/'),
array('\\'),
array('@'),
array(':'),
array(true),
array(null),
array(1),
array(1.1),
array(array(array())),
array(new \Exception('foo')),
);
}
public function testTag()
{
$item = new CacheItem();
$this->assertSame($item, $item->tag('foo'));
$this->assertSame($item, $item->tag(array('bar', 'baz')));
\call_user_func(\Closure::bind(function () use ($item) {
$this->assertSame(array('foo' => 'foo', 'bar' => 'bar', 'baz' => 'baz'), $item->tags);
}, $this, CacheItem::class));
}
/**
* @dataProvider provideInvalidKey
* @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException
* @expectedExceptionMessage Cache tag
*/
public function testInvalidTag($tag)
{
$item = new CacheItem();
$item->tag($tag);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests;
use Doctrine\Common\Cache\CacheProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\DoctrineProvider;
class DoctrineProviderTest extends TestCase
{
public function testProvider()
{
$pool = new ArrayAdapter();
$cache = new DoctrineProvider($pool);
$this->assertInstanceOf(CacheProvider::class, $cache);
$key = '{}()/\@:';
$this->assertTrue($cache->delete($key));
$this->assertFalse($cache->contains($key));
$this->assertTrue($cache->save($key, 'bar'));
$this->assertTrue($cache->contains($key));
$this->assertSame('bar', $cache->fetch($key));
$this->assertTrue($cache->delete($key));
$this->assertFalse($cache->fetch($key));
$this->assertTrue($cache->save($key, 'bar'));
$cache->flushAll();
$this->assertFalse($cache->fetch($key));
$this->assertFalse($cache->contains($key));
}
}
<?php
namespace Symfony\Component\Cache\Tests\Fixtures;
use Doctrine\Common\Cache\CacheProvider;
class ArrayCache extends CacheProvider
{
private $data = array();
protected function doFetch($id)
{
return $this->doContains($id) ? $this->data[$id][0] : false;
}
protected function doContains($id)
{
if (!isset($this->data[$id])) {
return false;
}
$expiry = $this->data[$id][1];
return !$expiry || time() < $expiry || !$this->doDelete($id);
}
protected function doSave($id, $data, $lifeTime = 0)
{
$this->data[$id] = array($data, $lifeTime ? time() + $lifeTime : false);
return true;
}
protected function doDelete($id)
{
unset($this->data[$id]);
return true;
}
protected function doFlush()
{
$this->data = array();
return true;
}
protected function doGetStats()
{
return null;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Fixtures;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
/**
* Adapter not implementing the {@see \Symfony\Component\Cache\Adapter\AdapterInterface}.
*
* @author Kévin Dunglas <[email protected]>
*/
class ExternalAdapter implements CacheItemPoolInterface
{
private $cache;
public function __construct()
{
$this->cache = new ArrayAdapter();
}
public function getItem($key)
{
return $this->cache->getItem($key);
}
public function getItems(array $keys = array())
{
return $this->cache->getItems($keys);
}
public function hasItem($key)
{
return $this->cache->hasItem($key);
}
public function clear()
{
return $this->cache->clear();
}
public function deleteItem($key)
{
return $this->cache->deleteItem($key);
}
public function deleteItems(array $keys)
{
return $this->cache->deleteItems($keys);
}
public function save(CacheItemInterface $item)
{
return $this->cache->save($item);
}
public function saveDeferred(CacheItemInterface $item)
{
return $this->cache->saveDeferred($item);
}
public function commit()
{
return $this->cache->commit();
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Simple;
use Symfony\Component\Cache\Simple\RedisCache;
abstract class AbstractRedisCacheTest extends CacheTestCase
{
protected $skippedTests = array(
'testSetTtl' => 'Testing expiration slows down the test suite',
'testSetMultipleTtl' => 'Testing expiration slows down the test suite',
'testDefaultLifeTime' => 'Testing expiration slows down the test suite',
);
protected static $redis;
public function createSimpleCache($defaultLifetime = 0)
{
return new RedisCache(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime);
}
public static function setupBeforeClass()
{
if (!\extension_loaded('redis')) {
self::markTestSkipped('Extension redis required.');
}
if (!@((new \Redis())->connect(getenv('REDIS_HOST')))) {
$e = error_get_last();
self::markTestSkipped($e['message']);
}
}
public static function tearDownAfterClass()
{
self::$redis = null;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Simple;
use Symfony\Component\Cache\Simple\ApcuCache;
class ApcuCacheTest extends CacheTestCase
{
protected $skippedTests = array(
'testSetTtl' => 'Testing expiration slows down the test suite',
'testSetMultipleTtl' => 'Testing expiration slows down the test suite',
'testDefaultLifeTime' => 'Testing expiration slows down the test suite',
);
public function createSimpleCache($defaultLifetime = 0)
{
if (!\function_exists('apcu_fetch') || !ini_get('apc.enabled') || ('cli' === \PHP_SAPI && !ini_get('apc.enable_cli'))) {
$this->markTestSkipped('APCu extension is required.');
}
if ('\\' === \DIRECTORY_SEPARATOR) {
$this->markTestSkipped('Fails transiently on Windows.');
}
return new ApcuCache(str_replace('\\', '.', __CLASS__), $defaultLifetime);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Simple;
use Symfony\Component\Cache\Simple\ArrayCache;
/**
* @group time-sensitive
*/
class ArrayCacheTest extends CacheTestCase
{
public function createSimpleCache($defaultLifetime = 0)
{
return new ArrayCache($defaultLifetime);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Simple;
use Cache\IntegrationTests\SimpleCacheTest;
use Psr\SimpleCache\CacheInterface;
use Symfony\Component\Cache\PruneableInterface;
abstract class CacheTestCase extends SimpleCacheTest
{
protected function setUp()
{
parent::setUp();
if (!array_key_exists('testPrune', $this->skippedTests) && !$this->createSimpleCache() instanceof PruneableInterface) {
$this->skippedTests['testPrune'] = 'Not a pruneable cache pool.';
}
}
public static function validKeys()
{
return array_merge(parent::validKeys(), array(array("a\0b")));
}
public function testDefaultLifeTime()
{
if (isset($this->skippedTests[__FUNCTION__])) {
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
}
$cache = $this->createSimpleCache(2);
$cache->clear();
$cache->set('key.dlt', 'value');
sleep(1);
$this->assertSame('value', $cache->get('key.dlt'));
sleep(2);
$this->assertNull($cache->get('key.dlt'));
$cache->clear();
}
public function testNotUnserializable()
{
if (isset($this->skippedTests[__FUNCTION__])) {
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
}
$cache = $this->createSimpleCache();
$cache->clear();
$cache->set('foo', new NotUnserializable());
$this->assertNull($cache->get('foo'));
$cache->setMultiple(array('foo' => new NotUnserializable()));
foreach ($cache->getMultiple(array('foo')) as $value) {
}
$this->assertNull($value);
$cache->clear();
}
public function testPrune()
{
if (isset($this->skippedTests[__FUNCTION__])) {
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
}
if (!method_exists($this, 'isPruned')) {
$this->fail('Test classes for pruneable caches must implement `isPruned($cache, $name)` method.');
}
/** @var PruneableInterface|CacheInterface $cache */
$cache = $this->createSimpleCache();
$cache->clear();
$cache->set('foo', 'foo-val', new \DateInterval('PT05S'));
$cache->set('bar', 'bar-val', new \DateInterval('PT10S'));
$cache->set('baz', 'baz-val', new \DateInterval('PT15S'));
$cache->set('qux', 'qux-val', new \DateInterval('PT20S'));
sleep(30);
$cache->prune();
$this->assertTrue($this->isPruned($cache, 'foo'));
$this->assertTrue($this->isPruned($cache, 'bar'));
$this->assertTrue($this->isPruned($cache, 'baz'));
$this->assertTrue($this->isPruned($cache, 'qux'));
$cache->set('foo', 'foo-val');
$cache->set('bar', 'bar-val', new \DateInterval('PT20S'));
$cache->set('baz', 'baz-val', new \DateInterval('PT40S'));
$cache->set('qux', 'qux-val', new \DateInterval('PT80S'));
$cache->prune();
$this->assertFalse($this->isPruned($cache, 'foo'));
$this->assertFalse($this->isPruned($cache, 'bar'));
$this->assertFalse($this->isPruned($cache, 'baz'));
$this->assertFalse($this->isPruned($cache, 'qux'));
sleep(30);
$cache->prune();
$this->assertFalse($this->isPruned($cache, 'foo'));
$this->assertTrue($this->isPruned($cache, 'bar'));
$this->assertFalse($this->isPruned($cache, 'baz'));
$this->assertFalse($this->isPruned($cache, 'qux'));
sleep(30);
$cache->prune();
$this->assertFalse($this->isPruned($cache, 'foo'));
$this->assertTrue($this->isPruned($cache, 'baz'));
$this->assertFalse($this->isPruned($cache, 'qux'));
sleep(30);
$cache->prune();
$this->assertFalse($this->isPruned($cache, 'foo'));
$this->assertTrue($this->isPruned($cache, 'qux'));
$cache->clear();
}
}
class NotUnserializable implements \Serializable
{
public function serialize()
{
return serialize(123);
}
public function unserialize($ser)
{
throw new \Exception(__CLASS__);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Simple;
use Psr\SimpleCache\CacheInterface;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\Simple\ArrayCache;
use Symfony\Component\Cache\Simple\ChainCache;
use Symfony\Component\Cache\Simple\FilesystemCache;
/**
* @group time-sensitive
*/
class ChainCacheTest extends CacheTestCase
{
public function createSimpleCache($defaultLifetime = 0)
{
return new ChainCache(array(new ArrayCache($defaultLifetime), new FilesystemCache('', $defaultLifetime)), $defaultLifetime);
}
/**
* @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException
* @expectedExceptionMessage At least one cache must be specified.
*/
public function testEmptyCachesException()
{
new ChainCache(array());
}
/**
* @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException
* @expectedExceptionMessage The class "stdClass" does not implement
*/
public function testInvalidCacheException()
{
new ChainCache(array(new \stdClass()));
}
public function testPrune()
{
if (isset($this->skippedTests[__FUNCTION__])) {
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
}
$cache = new ChainCache(array(
$this->getPruneableMock(),
$this->getNonPruneableMock(),
$this->getPruneableMock(),
));
$this->assertTrue($cache->prune());
$cache = new ChainCache(array(
$this->getPruneableMock(),
$this->getFailingPruneableMock(),
$this->getPruneableMock(),
));
$this->assertFalse($cache->prune());
}
/**
* @return \PHPUnit_Framework_MockObject_MockObject|PruneableCacheInterface
*/
private function getPruneableMock()
{
$pruneable = $this
->getMockBuilder(PruneableCacheInterface::class)
->getMock();
$pruneable
->expects($this->atLeastOnce())
->method('prune')
->will($this->returnValue(true));
return $pruneable;
}
/**
* @return \PHPUnit_Framework_MockObject_MockObject|PruneableCacheInterface
*/
private function getFailingPruneableMock()
{
$pruneable = $this
->getMockBuilder(PruneableCacheInterface::class)
->getMock();
$pruneable
->expects($this->atLeastOnce())
->method('prune')
->will($this->returnValue(false));
return $pruneable;
}
/**
* @return \PHPUnit_Framework_MockObject_MockObject|CacheInterface
*/
private function getNonPruneableMock()
{
return $this
->getMockBuilder(CacheInterface::class)
->getMock();
}
}
interface PruneableCacheInterface extends PruneableInterface, CacheInterface
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Simple;
use Symfony\Component\Cache\Simple\DoctrineCache;
use Symfony\Component\Cache\Tests\Fixtures\ArrayCache;
/**
* @group time-sensitive
*/
class DoctrineCacheTest extends CacheTestCase
{
protected $skippedTests = array(
'testObjectDoesNotChangeInCache' => 'ArrayCache does not use serialize/unserialize',
'testNotUnserializable' => 'ArrayCache does not use serialize/unserialize',
);
public function createSimpleCache($defaultLifetime = 0)
{
return new DoctrineCache(new ArrayCache($defaultLifetime), '', $defaultLifetime);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Simple;
use Psr\SimpleCache\CacheInterface;
use Symfony\Component\Cache\Simple\FilesystemCache;
/**
* @group time-sensitive
*/
class FilesystemCacheTest extends CacheTestCase
{
public function createSimpleCache($defaultLifetime = 0)
{
return new FilesystemCache('', $defaultLifetime);
}
protected function isPruned(CacheInterface $cache, $name)
{
$getFileMethod = (new \ReflectionObject($cache))->getMethod('getFile');
$getFileMethod->setAccessible(true);
return !file_exists($getFileMethod->invoke($cache, $name));
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Simple;
use Symfony\Component\Cache\Adapter\AbstractAdapter;
use Symfony\Component\Cache\Simple\MemcachedCache;
class MemcachedCacheTest extends CacheTestCase
{
protected $skippedTests = array(
'testSetTtl' => 'Testing expiration slows down the test suite',
'testSetMultipleTtl' => 'Testing expiration slows down the test suite',
'testDefaultLifeTime' => 'Testing expiration slows down the test suite',
);
protected static $client;
public static function setupBeforeClass()
{
if (!MemcachedCache::isSupported()) {
self::markTestSkipped('Extension memcached >=2.2.0 required.');
}
self::$client = AbstractAdapter::createConnection('memcached://'.getenv('MEMCACHED_HOST'));
self::$client->get('foo');
$code = self::$client->getResultCode();
if (\Memcached::RES_SUCCESS !== $code && \Memcached::RES_NOTFOUND !== $code) {
self::markTestSkipped('Memcached error: '.strtolower(self::$client->getResultMessage()));
}
}
public function createSimpleCache($defaultLifetime = 0)
{
$client = $defaultLifetime ? AbstractAdapter::createConnection('memcached://'.getenv('MEMCACHED_HOST'), array('binary_protocol' => false)) : self::$client;
return new MemcachedCache($client, str_replace('\\', '.', __CLASS__), $defaultLifetime);
}
public function testCreatePersistentConnectionShouldNotDupServerList()
{
$instance = MemcachedCache::createConnection('memcached://'.getenv('MEMCACHED_HOST'), array('persistent_id' => 'persistent'));
$this->assertCount(1, $instance->getServerList());
$instance = MemcachedCache::createConnection('memcached://'.getenv('MEMCACHED_HOST'), array('persistent_id' => 'persistent'));
$this->assertCount(1, $instance->getServerList());
}
public function testOptions()
{
$client = MemcachedCache::createConnection(array(), array(
'libketama_compatible' => false,
'distribution' => 'modula',
'compression' => true,
'serializer' => 'php',
'hash' => 'md5',
));
$this->assertSame(\Memcached::SERIALIZER_PHP, $client->getOption(\Memcached::OPT_SERIALIZER));
$this->assertSame(\Memcached::HASH_MD5, $client->getOption(\Memcached::OPT_HASH));
$this->assertTrue($client->getOption(\Memcached::OPT_COMPRESSION));
$this->assertSame(0, $client->getOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE));
$this->assertSame(\Memcached::DISTRIBUTION_MODULA, $client->getOption(\Memcached::OPT_DISTRIBUTION));
}
/**
* @dataProvider provideBadOptions
* @expectedException \ErrorException
* @expectedExceptionMessage constant(): Couldn't find constant Memcached::
*/
public function testBadOptions($name, $value)
{
MemcachedCache::createConnection(array(), array($name => $value));
}
public function provideBadOptions()
{
return array(
array('foo', 'bar'),
array('hash', 'zyx'),
array('serializer', 'zyx'),
array('distribution', 'zyx'),
);
}
public function testDefaultOptions()
{
$this->assertTrue(MemcachedCache::isSupported());
$client = MemcachedCache::createConnection(array());
$this->assertTrue($client->getOption(\Memcached::OPT_COMPRESSION));
$this->assertSame(1, $client->getOption(\Memcached::OPT_BINARY_PROTOCOL));
$this->assertSame(1, $client->getOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE));
}
/**
* @expectedException \Symfony\Component\Cache\Exception\CacheException
* @expectedExceptionMessage MemcachedAdapter: "serializer" option must be "php" or "igbinary".
*/
public function testOptionSerializer()
{
if (!\Memcached::HAVE_JSON) {
$this->markTestSkipped('Memcached::HAVE_JSON required');
}
new MemcachedCache(MemcachedCache::createConnection(array(), array('serializer' => 'json')));
}
/**
* @dataProvider provideServersSetting
*/
public function testServersSetting($dsn, $host, $port)
{
$client1 = MemcachedCache::createConnection($dsn);
$client2 = MemcachedCache::createConnection(array($dsn));
$client3 = MemcachedCache::createConnection(array(array($host, $port)));
$expect = array(
'host' => $host,
'port' => $port,
);
$f = function ($s) { return array('host' => $s['host'], 'port' => $s['port']); };
$this->assertSame(array($expect), array_map($f, $client1->getServerList()));
$this->assertSame(array($expect), array_map($f, $client2->getServerList()));
$this->assertSame(array($expect), array_map($f, $client3->getServerList()));
}
public function provideServersSetting()
{
yield array(
'memcached://127.0.0.1/50',
'127.0.0.1',
11211,
);
yield array(
'memcached://localhost:11222?weight=25',
'localhost',
11222,
);
if (ini_get('memcached.use_sasl')) {
yield array(
'memcached://user:[email protected]?weight=50',
'127.0.0.1',
11211,
);
}
yield array(
'memcached:///var/run/memcached.sock?weight=25',
'/var/run/memcached.sock',
0,
);
yield array(
'memcached:///var/local/run/memcached.socket?weight=25',
'/var/local/run/memcached.socket',
0,
);
if (ini_get('memcached.use_sasl')) {
yield array(
'memcached://user:password@/var/local/run/memcached.socket?weight=25',
'/var/local/run/memcached.socket',
0,
);
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Simple;
use Symfony\Component\Cache\Adapter\AbstractAdapter;
use Symfony\Component\Cache\Simple\MemcachedCache;
class MemcachedCacheTextModeTest extends MemcachedCacheTest
{
public function createSimpleCache($defaultLifetime = 0)
{
$client = AbstractAdapter::createConnection('memcached://'.getenv('MEMCACHED_HOST'), array('binary_protocol' => false));
return new MemcachedCache($client, str_replace('\\', '.', __CLASS__), $defaultLifetime);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Simple;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Cache\Simple\NullCache;
/**
* @group time-sensitive
*/
class NullCacheTest extends TestCase
{
public function createCachePool()
{
return new NullCache();
}
public function testGetItem()
{
$cache = $this->createCachePool();
$this->assertNull($cache->get('key'));
}
public function testHas()
{
$this->assertFalse($this->createCachePool()->has('key'));
}
public function testGetMultiple()
{
$cache = $this->createCachePool();
$keys = array('foo', 'bar', 'baz', 'biz');
$default = new \stdClass();
$items = $cache->getMultiple($keys, $default);
$count = 0;
foreach ($items as $key => $item) {
$this->assertContains($key, $keys, 'Cache key can not change.');
$this->assertSame($default, $item);
// Remove $key for $keys
foreach ($keys as $k => $v) {
if ($v === $key) {
unset($keys[$k]);
}
}
++$count;
}
$this->assertSame(4, $count);
}
public function testClear()
{
$this->assertTrue($this->createCachePool()->clear());
}
public function testDelete()
{
$this->assertTrue($this->createCachePool()->delete('key'));
}
public function testDeleteMultiple()
{
$this->assertTrue($this->createCachePool()->deleteMultiple(array('key', 'foo', 'bar')));
}
public function testSet()
{
$cache = $this->createCachePool();
$this->assertFalse($cache->set('key', 'val'));
$this->assertNull($cache->get('key'));
}
public function testSetMultiple()
{
$cache = $this->createCachePool();
$this->assertFalse($cache->setMultiple(array('key' => 'val')));
$this->assertNull($cache->get('key'));
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Simple;
use Symfony\Component\Cache\Simple\PdoCache;
use Symfony\Component\Cache\Tests\Traits\PdoPruneableTrait;
/**
* @group time-sensitive
*/
class PdoCacheTest extends CacheTestCase
{
use PdoPruneableTrait;
protected static $dbFile;
public static function setupBeforeClass()
{
if (!\extension_loaded('pdo_sqlite')) {
self::markTestSkipped('Extension pdo_sqlite required.');
}
self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
$pool = new PdoCache('sqlite:'.self::$dbFile);
$pool->createTable();
}
public static function tearDownAfterClass()
{
@unlink(self::$dbFile);
}
public function createSimpleCache($defaultLifetime = 0)
{
return new PdoCache('sqlite:'.self::$dbFile, 'ns', $defaultLifetime);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Simple;
use Doctrine\DBAL\DriverManager;
use Symfony\Component\Cache\Simple\PdoCache;
use Symfony\Component\Cache\Tests\Traits\PdoPruneableTrait;
/**
* @group time-sensitive
*/
class PdoDbalCacheTest extends CacheTestCase
{
use PdoPruneableTrait;
protected static $dbFile;
public static function setupBeforeClass()
{
if (!\extension_loaded('pdo_sqlite')) {
self::markTestSkipped('Extension pdo_sqlite required.');
}
self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
$pool = new PdoCache(DriverManager::getConnection(array('driver' => 'pdo_sqlite', 'path' => self::$dbFile)));
$pool->createTable();
}
public static function tearDownAfterClass()
{
@unlink(self::$dbFile);
}
public function createSimpleCache($defaultLifetime = 0)
{
return new PdoCache(DriverManager::getConnection(array('driver' => 'pdo_sqlite', 'path' => self::$dbFile)), '', $defaultLifetime);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Simple;
use Symfony\Component\Cache\Simple\NullCache;
use Symfony\Component\Cache\Simple\PhpArrayCache;
use Symfony\Component\Cache\Tests\Adapter\FilesystemAdapterTest;
/**
* @group time-sensitive
*/
class PhpArrayCacheTest extends CacheTestCase
{
protected $skippedTests = array(
'testBasicUsageWithLongKey' => 'PhpArrayCache does no writes',
'testDelete' => 'PhpArrayCache does no writes',
'testDeleteMultiple' => 'PhpArrayCache does no writes',
'testDeleteMultipleGenerator' => 'PhpArrayCache does no writes',
'testSetTtl' => 'PhpArrayCache does no expiration',
'testSetMultipleTtl' => 'PhpArrayCache does no expiration',
'testSetExpiredTtl' => 'PhpArrayCache does no expiration',
'testSetMultipleExpiredTtl' => 'PhpArrayCache does no expiration',
'testGetInvalidKeys' => 'PhpArrayCache does no validation',
'testGetMultipleInvalidKeys' => 'PhpArrayCache does no validation',
'testSetInvalidKeys' => 'PhpArrayCache does no validation',
'testDeleteInvalidKeys' => 'PhpArrayCache does no validation',
'testDeleteMultipleInvalidKeys' => 'PhpArrayCache does no validation',
'testSetInvalidTtl' => 'PhpArrayCache does no validation',
'testSetMultipleInvalidKeys' => 'PhpArrayCache does no validation',
'testSetMultipleInvalidTtl' => 'PhpArrayCache does no validation',
'testHasInvalidKeys' => 'PhpArrayCache does no validation',
'testSetValidData' => 'PhpArrayCache does no validation',
'testDefaultLifeTime' => 'PhpArrayCache does not allow configuring a default lifetime.',
'testPrune' => 'PhpArrayCache just proxies',
);
protected static $file;
public static function setupBeforeClass()
{
self::$file = sys_get_temp_dir().'/symfony-cache/php-array-adapter-test.php';
}
protected function tearDown()
{
if (file_exists(sys_get_temp_dir().'/symfony-cache')) {
FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache');
}
}
public function createSimpleCache()
{
return new PhpArrayCacheWrapper(self::$file, new NullCache());
}
public function testStore()
{
$arrayWithRefs = array();
$arrayWithRefs[0] = 123;
$arrayWithRefs[1] = &$arrayWithRefs[0];
$object = (object) array(
'foo' => 'bar',
'foo2' => 'bar2',
);
$expected = array(
'null' => null,
'serializedString' => serialize($object),
'arrayWithRefs' => $arrayWithRefs,
'object' => $object,
'arrayWithObject' => array('bar' => $object),
);
$cache = new PhpArrayCache(self::$file, new NullCache());
$cache->warmUp($expected);
foreach ($expected as $key => $value) {
$this->assertSame(serialize($value), serialize($cache->get($key)), 'Warm up should create a PHP file that OPCache can load in memory');
}
}
public function testStoredFile()
{
$expected = array(
'integer' => 42,
'float' => 42.42,
'boolean' => true,
'array_simple' => array('foo', 'bar'),
'array_associative' => array('foo' => 'bar', 'foo2' => 'bar2'),
);
$cache = new PhpArrayCache(self::$file, new NullCache());
$cache->warmUp($expected);
$values = eval(substr(file_get_contents(self::$file), 6));
$this->assertSame($expected, $values, 'Warm up should create a PHP file that OPCache can load in memory');
}
}
class PhpArrayCacheWrapper extends PhpArrayCache
{
public function set($key, $value, $ttl = null)
{
\call_user_func(\Closure::bind(function () use ($key, $value) {
$this->values[$key] = $value;
$this->warmUp($this->values);
$this->values = eval(substr(file_get_contents($this->file), 6));
}, $this, PhpArrayCache::class));
return true;
}
public function setMultiple($values, $ttl = null)
{
if (!\is_array($values) && !$values instanceof \Traversable) {
return parent::setMultiple($values, $ttl);
}
\call_user_func(\Closure::bind(function () use ($values) {
foreach ($values as $key => $value) {
$this->values[$key] = $value;
}
$this->warmUp($this->values);
$this->values = eval(substr(file_get_contents($this->file), 6));
}, $this, PhpArrayCache::class));
return true;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Simple;
use Symfony\Component\Cache\Simple\FilesystemCache;
use Symfony\Component\Cache\Simple\PhpArrayCache;
use Symfony\Component\Cache\Tests\Adapter\FilesystemAdapterTest;
/**
* @group time-sensitive
*/
class PhpArrayCacheWithFallbackTest extends CacheTestCase
{
protected $skippedTests = array(
'testGetInvalidKeys' => 'PhpArrayCache does no validation',
'testGetMultipleInvalidKeys' => 'PhpArrayCache does no validation',
'testDeleteInvalidKeys' => 'PhpArrayCache does no validation',
'testDeleteMultipleInvalidKeys' => 'PhpArrayCache does no validation',
//'testSetValidData' => 'PhpArrayCache does no validation',
'testSetInvalidKeys' => 'PhpArrayCache does no validation',
'testSetInvalidTtl' => 'PhpArrayCache does no validation',
'testSetMultipleInvalidKeys' => 'PhpArrayCache does no validation',
'testSetMultipleInvalidTtl' => 'PhpArrayCache does no validation',
'testHasInvalidKeys' => 'PhpArrayCache does no validation',
'testPrune' => 'PhpArrayCache just proxies',
);
protected static $file;
public static function setupBeforeClass()
{
self::$file = sys_get_temp_dir().'/symfony-cache/php-array-adapter-test.php';
}
protected function tearDown()
{
if (file_exists(sys_get_temp_dir().'/symfony-cache')) {
FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache');
}
}
public function createSimpleCache($defaultLifetime = 0)
{
return new PhpArrayCache(self::$file, new FilesystemCache('php-array-fallback', $defaultLifetime));
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Simple;
use Psr\SimpleCache\CacheInterface;
use Symfony\Component\Cache\Simple\PhpFilesCache;
/**
* @group time-sensitive
*/
class PhpFilesCacheTest extends CacheTestCase
{
protected $skippedTests = array(
'testDefaultLifeTime' => 'PhpFilesCache does not allow configuring a default lifetime.',
);
public function createSimpleCache()
{
if (!PhpFilesCache::isSupported()) {
$this->markTestSkipped('OPcache extension is not enabled.');
}
return new PhpFilesCache('sf-cache');
}
protected function isPruned(CacheInterface $cache, $name)
{
$getFileMethod = (new \ReflectionObject($cache))->getMethod('getFile');
$getFileMethod->setAccessible(true);
return !file_exists($getFileMethod->invoke($cache, $name));
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Simple;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Simple\Psr6Cache;
/**
* @group time-sensitive
*/
class Psr6CacheTest extends CacheTestCase
{
protected $skippedTests = array(
'testPrune' => 'Psr6Cache just proxies',
);
public function createSimpleCache($defaultLifetime = 0)
{
return new Psr6Cache(new FilesystemAdapter('', $defaultLifetime));
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Simple;
class RedisArrayCacheTest extends AbstractRedisCacheTest
{
public static function setupBeforeClass()
{
parent::setupBeforeClass();
if (!class_exists('RedisArray')) {
self::markTestSkipped('The RedisArray class is required.');
}
self::$redis = new \RedisArray(array(getenv('REDIS_HOST')), array('lazy_connect' => true));
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Simple;
use Symfony\Component\Cache\Simple\RedisCache;
class RedisCacheTest extends AbstractRedisCacheTest
{
public static function setupBeforeClass()
{
parent::setupBeforeClass();
self::$redis = RedisCache::createConnection('redis://'.getenv('REDIS_HOST'));
}
public function testCreateConnection()
{
$redisHost = getenv('REDIS_HOST');
$redis = RedisCache::createConnection('redis://'.$redisHost);
$this->assertInstanceOf(\Redis::class, $redis);
$this->assertTrue($redis->isConnected());
$this->assertSame(0, $redis->getDbNum());
$redis = RedisCache::createConnection('redis://'.$redisHost.'/2');
$this->assertSame(2, $redis->getDbNum());
$redis = RedisCache::createConnection('redis://'.$redisHost, array('timeout' => 3));
$this->assertEquals(3, $redis->getTimeout());
$redis = RedisCache::createConnection('redis://'.$redisHost.'?timeout=4');
$this->assertEquals(4, $redis->getTimeout());
$redis = RedisCache::createConnection('redis://'.$redisHost, array('read_timeout' => 5));
$this->assertEquals(5, $redis->getReadTimeout());
}
/**
* @dataProvider provideFailedCreateConnection
* @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException
* @expectedExceptionMessage Redis connection failed
*/
public function testFailedCreateConnection($dsn)
{
RedisCache::createConnection($dsn);
}
public function provideFailedCreateConnection()
{
return array(
array('redis://localhost:1234'),
array('redis://foo@localhost'),
array('redis://localhost/123'),
);
}
/**
* @dataProvider provideInvalidCreateConnection
* @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException
* @expectedExceptionMessage Invalid Redis DSN
*/
public function testInvalidCreateConnection($dsn)
{
RedisCache::createConnection($dsn);
}
public function provideInvalidCreateConnection()
{
return array(
array('foo://localhost'),
array('redis://'),
);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Simple;
class RedisClusterCacheTest extends AbstractRedisCacheTest
{
public static function setupBeforeClass()
{
if (!class_exists('RedisCluster')) {
self::markTestSkipped('The RedisCluster class is required.');
}
if (!$hosts = getenv('REDIS_CLUSTER_HOSTS')) {
self::markTestSkipped('REDIS_CLUSTER_HOSTS env var is not defined.');
}
self::$redis = new \RedisCluster(null, explode(' ', $hosts));
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Simple;
use Symfony\Component\Cache\Simple\FilesystemCache;
use Symfony\Component\Cache\Simple\TraceableCache;
/**
* @group time-sensitive
*/
class TraceableCacheTest extends CacheTestCase
{
protected $skippedTests = array(
'testPrune' => 'TraceableCache just proxies',
);
public function createSimpleCache($defaultLifetime = 0)
{
return new TraceableCache(new FilesystemCache('', $defaultLifetime));
}
public function testGetMissTrace()
{
$pool = $this->createSimpleCache();
$pool->get('k');
$calls = $pool->getCalls();
$this->assertCount(1, $calls);
$call = $calls[0];
$this->assertSame('get', $call->name);
$this->assertSame(array('k' => false), $call->result);
$this->assertSame(0, $call->hits);
$this->assertSame(1, $call->misses);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
public function testGetHitTrace()
{
$pool = $this->createSimpleCache();
$pool->set('k', 'foo');
$pool->get('k');
$calls = $pool->getCalls();
$this->assertCount(2, $calls);
$call = $calls[1];
$this->assertSame(1, $call->hits);
$this->assertSame(0, $call->misses);
}
public function testGetMultipleMissTrace()
{
$pool = $this->createSimpleCache();
$pool->set('k1', 123);
$values = $pool->getMultiple(array('k0', 'k1'));
foreach ($values as $value) {
}
$calls = $pool->getCalls();
$this->assertCount(2, $calls);
$call = $calls[1];
$this->assertSame('getMultiple', $call->name);
$this->assertSame(array('k1' => true, 'k0' => false), $call->result);
$this->assertSame(1, $call->misses);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
public function testHasMissTrace()
{
$pool = $this->createSimpleCache();
$pool->has('k');
$calls = $pool->getCalls();
$this->assertCount(1, $calls);
$call = $calls[0];
$this->assertSame('has', $call->name);
$this->assertSame(array('k' => false), $call->result);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
public function testHasHitTrace()
{
$pool = $this->createSimpleCache();
$pool->set('k', 'foo');
$pool->has('k');
$calls = $pool->getCalls();
$this->assertCount(2, $calls);
$call = $calls[1];
$this->assertSame('has', $call->name);
$this->assertSame(array('k' => true), $call->result);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
public function testDeleteTrace()
{
$pool = $this->createSimpleCache();
$pool->delete('k');
$calls = $pool->getCalls();
$this->assertCount(1, $calls);
$call = $calls[0];
$this->assertSame('delete', $call->name);
$this->assertSame(array('k' => true), $call->result);
$this->assertSame(0, $call->hits);
$this->assertSame(0, $call->misses);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
public function testDeleteMultipleTrace()
{
$pool = $this->createSimpleCache();
$arg = array('k0', 'k1');
$pool->deleteMultiple($arg);
$calls = $pool->getCalls();
$this->assertCount(1, $calls);
$call = $calls[0];
$this->assertSame('deleteMultiple', $call->name);
$this->assertSame(array('keys' => $arg, 'result' => true), $call->result);
$this->assertSame(0, $call->hits);
$this->assertSame(0, $call->misses);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
public function testTraceSetTrace()
{
$pool = $this->createSimpleCache();
$pool->set('k', 'foo');
$calls = $pool->getCalls();
$this->assertCount(1, $calls);
$call = $calls[0];
$this->assertSame('set', $call->name);
$this->assertSame(array('k' => true), $call->result);
$this->assertSame(0, $call->hits);
$this->assertSame(0, $call->misses);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
public function testSetMultipleTrace()
{
$pool = $this->createSimpleCache();
$pool->setMultiple(array('k' => 'foo'));
$calls = $pool->getCalls();
$this->assertCount(1, $calls);
$call = $calls[0];
$this->assertSame('setMultiple', $call->name);
$this->assertSame(array('keys' => array('k'), 'result' => true), $call->result);
$this->assertSame(0, $call->hits);
$this->assertSame(0, $call->misses);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Tests\Traits;
trait PdoPruneableTrait
{
protected function isPruned($cache, $name)
{
$o = new \ReflectionObject($cache);
if (!$o->hasMethod('getConnection')) {
self::fail('Cache does not have "getConnection()" method.');
}
$getPdoConn = $o->getMethod('getConnection');
$getPdoConn->setAccessible(true);
/** @var \Doctrine\DBAL\Statement $select */
$select = $getPdoConn->invoke($cache)->prepare('SELECT 1 FROM cache_items WHERE item_id LIKE :id');
$select->bindValue(':id', sprintf('%%%s', $name));
$select->execute();
return 0 === \count($select->fetchAll(\PDO::FETCH_COLUMN));
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Traits;
use Psr\Log\LoggerAwareTrait;
use Symfony\Component\Cache\CacheItem;
/**
* @author Nicolas Grekas <[email protected]>
*
* @internal
*/
trait AbstractTrait
{
use LoggerAwareTrait;
private $namespace;
private $namespaceVersion = '';
private $versioningIsEnabled = false;
private $deferred = array();
/**
* @var int|null The maximum length to enforce for identifiers or null when no limit applies
*/
protected $maxIdLength;
/**
* Fetches several cache items.
*
* @param array $ids The cache identifiers to fetch
*
* @return array|\Traversable The corresponding values found in the cache
*/
abstract protected function doFetch(array $ids);
/**
* Confirms if the cache contains specified cache item.
*
* @param string $id The identifier for which to check existence
*
* @return bool True if item exists in the cache, false otherwise
*/
abstract protected function doHave($id);
/**
* Deletes all items in the pool.
*
* @param string The prefix used for all identifiers managed by this pool
*
* @return bool True if the pool was successfully cleared, false otherwise
*/
abstract protected function doClear($namespace);
/**
* Removes multiple items from the pool.
*
* @param array $ids An array of identifiers that should be removed from the pool
*
* @return bool True if the items were successfully removed, false otherwise
*/
abstract protected function doDelete(array $ids);
/**
* Persists several cache items immediately.
*
* @param array $values The values to cache, indexed by their cache identifier
* @param int $lifetime The lifetime of the cached values, 0 for persisting until manual cleaning
*
* @return array|bool The identifiers that failed to be cached or a boolean stating if caching succeeded or not
*/
abstract protected function doSave(array $values, $lifetime);
/**
* {@inheritdoc}
*/
public function hasItem($key)
{
$id = $this->getId($key);
if (isset($this->deferred[$key])) {
$this->commit();
}
try {
return $this->doHave($id);
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to check if key "{key}" is cached', array('key' => $key, 'exception' => $e));
return false;
}
}
/**
* {@inheritdoc}
*/
public function clear()
{
$this->deferred = array();
if ($cleared = $this->versioningIsEnabled) {
$namespaceVersion = substr_replace(base64_encode(pack('V', mt_rand())), ':', 5);
try {
$cleared = $this->doSave(array('@'.$this->namespace => $namespaceVersion), 0);
} catch (\Exception $e) {
$cleared = false;
}
if ($cleared = true === $cleared || array() === $cleared) {
$this->namespaceVersion = $namespaceVersion;
}
}
try {
return $this->doClear($this->namespace) || $cleared;
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to clear the cache', array('exception' => $e));
return false;
}
}
/**
* {@inheritdoc}
*/
public function deleteItem($key)
{
return $this->deleteItems(array($key));
}
/**
* {@inheritdoc}
*/
public function deleteItems(array $keys)
{
$ids = array();
foreach ($keys as $key) {
$ids[$key] = $this->getId($key);
unset($this->deferred[$key]);
}
try {
if ($this->doDelete($ids)) {
return true;
}
} catch (\Exception $e) {
}
$ok = true;
// When bulk-delete failed, retry each item individually
foreach ($ids as $key => $id) {
try {
$e = null;
if ($this->doDelete(array($id))) {
continue;
}
} catch (\Exception $e) {
}
CacheItem::log($this->logger, 'Failed to delete key "{key}"', array('key' => $key, 'exception' => $e));
$ok = false;
}
return $ok;
}
/**
* Enables/disables versioning of items.
*
* When versioning is enabled, clearing the cache is atomic and doesn't require listing existing keys to proceed,
* but old keys may need garbage collection and extra round-trips to the back-end are required.
*
* Calling this method also clears the memoized namespace version and thus forces a resynchonization of it.
*
* @param bool $enable
*
* @return bool the previous state of versioning
*/
public function enableVersioning($enable = true)
{
$wasEnabled = $this->versioningIsEnabled;
$this->versioningIsEnabled = (bool) $enable;
$this->namespaceVersion = '';
return $wasEnabled;
}
/**
* {@inheritdoc}
*/
public function reset()
{
if ($this->deferred) {
$this->commit();
}
$this->namespaceVersion = '';
}
/**
* Like the native unserialize() function but throws an exception if anything goes wrong.
*
* @param string $value
*
* @return mixed
*
* @throws \Exception
*/
protected static function unserialize($value)
{
if ('b:0;' === $value) {
return false;
}
$unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');
try {
if (false !== $value = unserialize($value)) {
return $value;
}
throw new \DomainException('Failed to unserialize cached value');
} catch (\Error $e) {
throw new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine());
} finally {
ini_set('unserialize_callback_func', $unserializeCallbackHandler);
}
}
private function getId($key)
{
CacheItem::validateKey($key);
if ($this->versioningIsEnabled && '' === $this->namespaceVersion) {
$this->namespaceVersion = '1:';
try {
foreach ($this->doFetch(array('@'.$this->namespace)) as $v) {
$this->namespaceVersion = $v;
}
if ('1:' === $this->namespaceVersion) {
$this->namespaceVersion = substr_replace(base64_encode(pack('V', time())), ':', 5);
$this->doSave(array('@'.$this->namespace => $this->namespaceVersion), 0);
}
} catch (\Exception $e) {
}
}
if (null === $this->maxIdLength) {
return $this->namespace.$this->namespaceVersion.$key;
}
if (\strlen($id = $this->namespace.$this->namespaceVersion.$key) > $this->maxIdLength) {
$id = $this->namespace.$this->namespaceVersion.substr_replace(base64_encode(hash('sha256', $key, true)), ':', -(\strlen($this->namespaceVersion) + 22));
}
return $id;
}
/**
* @internal
*/
public static function handleUnserializeCallback($class)
{
throw new \DomainException('Class not found: '.$class);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Traits;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\CacheException;
/**
* @author Nicolas Grekas <[email protected]>
*
* @internal
*/
trait ApcuTrait
{
public static function isSupported()
{
return \function_exists('apcu_fetch') && ini_get('apc.enabled');
}
private function init($namespace, $defaultLifetime, $version)
{
if (!static::isSupported()) {
throw new CacheException('APCu is not enabled');
}
if ('cli' === \PHP_SAPI) {
ini_set('apc.use_request_time', 0);
}
parent::__construct($namespace, $defaultLifetime);
if (null !== $version) {
CacheItem::validateKey($version);
if (!apcu_exists($version.'@'.$namespace)) {
$this->doClear($namespace);
apcu_add($version.'@'.$namespace, null);
}
}
}
/**
* {@inheritdoc}
*/
protected function doFetch(array $ids)
{
try {
foreach (apcu_fetch($ids, $ok) ?: array() as $k => $v) {
if (null !== $v || $ok) {
yield $k => $v;
}
}
} catch (\Error $e) {
throw new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine());
}
}
/**
* {@inheritdoc}
*/
protected function doHave($id)
{
return apcu_exists($id);
}
/**
* {@inheritdoc}
*/
protected function doClear($namespace)
{
return isset($namespace[0]) && class_exists('APCuIterator', false) && ('cli' !== \PHP_SAPI || ini_get('apc.enable_cli'))
? apcu_delete(new \APCuIterator(sprintf('/^%s/', preg_quote($namespace, '/')), APC_ITER_KEY))
: apcu_clear_cache();
}
/**
* {@inheritdoc}
*/
protected function doDelete(array $ids)
{
foreach ($ids as $id) {
apcu_delete($id);
}
return true;
}
/**
* {@inheritdoc}
*/
protected function doSave(array $values, $lifetime)
{
try {
if (false === $failures = apcu_store($values, null, $lifetime)) {
$failures = $values;
}
return array_keys($failures);
} catch (\Throwable $e) {
if (1 === \count($values)) {
// Workaround https://github.com/krakjoe/apcu/issues/170
apcu_delete(key($values));
}
throw $e;
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Traits;
use Psr\Log\LoggerAwareTrait;
use Symfony\Component\Cache\CacheItem;
/**
* @author Nicolas Grekas <[email protected]>
*
* @internal
*/
trait ArrayTrait
{
use LoggerAwareTrait;
private $storeSerialized;
private $values = array();
private $expiries = array();
/**
* Returns all cached values, with cache miss as null.
*
* @return array
*/
public function getValues()
{
return $this->values;
}
/**
* {@inheritdoc}
*/
public function hasItem($key)
{
CacheItem::validateKey($key);
return isset($this->expiries[$key]) && ($this->expiries[$key] > time() || !$this->deleteItem($key));
}
/**
* {@inheritdoc}
*/
public function clear()
{
$this->values = $this->expiries = array();
return true;
}
/**
* {@inheritdoc}
*/
public function deleteItem($key)
{
CacheItem::validateKey($key);
unset($this->values[$key], $this->expiries[$key]);
return true;
}
/**
* {@inheritdoc}
*/
public function reset()
{
$this->clear();
}
private function generateItems(array $keys, $now, $f)
{
foreach ($keys as $i => $key) {
try {
if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] > $now || !$this->deleteItem($key))) {
$this->values[$key] = $value = null;
} elseif (!$this->storeSerialized) {
$value = $this->values[$key];
} elseif ('b:0;' === $value = $this->values[$key]) {
$value = false;
} elseif (false === $value = unserialize($value)) {
$this->values[$key] = $value = null;
$isHit = false;
}
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to unserialize key "{key}"', array('key' => $key, 'exception' => $e));
$this->values[$key] = $value = null;
$isHit = false;
}
unset($keys[$i]);
yield $key => $f($key, $value, $isHit);
}
foreach ($keys as $key) {
yield $key => $f($key, null, false);
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Traits;
/**
* @author Nicolas Grekas <[email protected]>
*
* @internal
*/
trait DoctrineTrait
{
private $provider;
/**
* {@inheritdoc}
*/
public function reset()
{
parent::reset();
$this->provider->setNamespace($this->provider->getNamespace());
}
/**
* {@inheritdoc}
*/
protected function doFetch(array $ids)
{
$unserializeCallbackHandler = ini_set('unserialize_callback_func', parent::class.'::handleUnserializeCallback');
try {
return $this->provider->fetchMultiple($ids);
} catch (\Error $e) {
$trace = $e->getTrace();
if (isset($trace[0]['function']) && !isset($trace[0]['class'])) {
switch ($trace[0]['function']) {
case 'unserialize':
case 'apcu_fetch':
case 'apc_fetch':
throw new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine());
}
}
throw $e;
} finally {
ini_set('unserialize_callback_func', $unserializeCallbackHandler);
}
}
/**
* {@inheritdoc}
*/
protected function doHave($id)
{
return $this->provider->contains($id);
}
/**
* {@inheritdoc}
*/
protected function doClear($namespace)
{
$namespace = $this->provider->getNamespace();
return isset($namespace[0])
? $this->provider->deleteAll()
: $this->provider->flushAll();
}
/**
* {@inheritdoc}
*/
protected function doDelete(array $ids)
{
$ok = true;
foreach ($ids as $id) {
$ok = $this->provider->delete($id) && $ok;
}
return $ok;
}
/**
* {@inheritdoc}
*/
protected function doSave(array $values, $lifetime)
{
return $this->provider->saveMultiple($values, $lifetime);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Traits;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
/**
* @author Nicolas Grekas <[email protected]>
*
* @internal
*/
trait FilesystemCommonTrait
{
private $directory;
private $tmp;
private function init($namespace, $directory)
{
if (!isset($directory[0])) {
$directory = sys_get_temp_dir().'/symfony-cache';
} else {
$directory = realpath($directory) ?: $directory;
}
if (isset($namespace[0])) {
if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) {
throw new InvalidArgumentException(sprintf('Namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0]));
}
$directory .= \DIRECTORY_SEPARATOR.$namespace;
}
if (!file_exists($directory)) {
@mkdir($directory, 0777, true);
}
$directory .= \DIRECTORY_SEPARATOR;
// On Windows the whole path is limited to 258 chars
if ('\\' === \DIRECTORY_SEPARATOR && \strlen($directory) > 234) {
throw new InvalidArgumentException(sprintf('Cache directory too long (%s)', $directory));
}
$this->directory = $directory;
}
/**
* {@inheritdoc}
*/
protected function doClear($namespace)
{
$ok = true;
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS)) as $file) {
$ok = ($file->isDir() || @unlink($file) || !file_exists($file)) && $ok;
}
return $ok;
}
/**
* {@inheritdoc}
*/
protected function doDelete(array $ids)
{
$ok = true;
foreach ($ids as $id) {
$file = $this->getFile($id);
$ok = (!file_exists($file) || @unlink($file) || !file_exists($file)) && $ok;
}
return $ok;
}
private function write($file, $data, $expiresAt = null)
{
set_error_handler(__CLASS__.'::throwError');
try {
if (null === $this->tmp) {
$this->tmp = $this->directory.uniqid('', true);
}
file_put_contents($this->tmp, $data);
if (null !== $expiresAt) {
touch($this->tmp, $expiresAt);
}
return rename($this->tmp, $file);
} finally {
restore_error_handler();
}
}
private function getFile($id, $mkdir = false)
{
$hash = str_replace('/', '-', base64_encode(hash('sha256', static::class.$id, true)));
$dir = $this->directory.strtoupper($hash[0].\DIRECTORY_SEPARATOR.$hash[1].\DIRECTORY_SEPARATOR);
if ($mkdir && !file_exists($dir)) {
@mkdir($dir, 0777, true);
}
return $dir.substr($hash, 2, 20);
}
/**
* @internal
*/
public static function throwError($type, $message, $file, $line)
{
throw new \ErrorException($message, 0, $type, $file, $line);
}
public function __destruct()
{
if (method_exists(parent::class, '__destruct')) {
parent::__destruct();
}
if (null !== $this->tmp && file_exists($this->tmp)) {
unlink($this->tmp);
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Traits;
use Symfony\Component\Cache\Exception\CacheException;
/**
* @author Nicolas Grekas <[email protected]>
* @author Rob Frawley 2nd <[email protected]>
*
* @internal
*/
trait FilesystemTrait
{
use FilesystemCommonTrait;
/**
* @return bool
*/
public function prune()
{
$time = time();
$pruned = true;
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
if (!$h = @fopen($file, 'rb')) {
continue;
}
if (($expiresAt = (int) fgets($h)) && $time >= $expiresAt) {
fclose($h);
$pruned = @unlink($file) && !file_exists($file) && $pruned;
} else {
fclose($h);
}
}
return $pruned;
}
/**
* {@inheritdoc}
*/
protected function doFetch(array $ids)
{
$values = array();
$now = time();
foreach ($ids as $id) {
$file = $this->getFile($id);
if (!file_exists($file) || !$h = @fopen($file, 'rb')) {
continue;
}
if (($expiresAt = (int) fgets($h)) && $now >= $expiresAt) {
fclose($h);
@unlink($file);
} else {
$i = rawurldecode(rtrim(fgets($h)));
$value = stream_get_contents($h);
fclose($h);
if ($i === $id) {
$values[$id] = parent::unserialize($value);
}
}
}
return $values;
}
/**
* {@inheritdoc}
*/
protected function doHave($id)
{
$file = $this->getFile($id);
return file_exists($file) && (@filemtime($file) > time() || $this->doFetch(array($id)));
}
/**
* {@inheritdoc}
*/
protected function doSave(array $values, $lifetime)
{
$ok = true;
$expiresAt = $lifetime ? (time() + $lifetime) : 0;
foreach ($values as $id => $value) {
$ok = $this->write($this->getFile($id, true), $expiresAt."\n".rawurlencode($id)."\n".serialize($value), $expiresAt) && $ok;
}
if (!$ok && !is_writable($this->directory)) {
throw new CacheException(sprintf('Cache directory is not writable (%s)', $this->directory));
}
return $ok;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Traits;
use Symfony\Component\Cache\Exception\CacheException;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
/**
* @author Rob Frawley 2nd <[email protected]>
* @author Nicolas Grekas <[email protected]>
*
* @internal
*/
trait MemcachedTrait
{
private static $defaultClientOptions = array(
'persistent_id' => null,
'username' => null,
'password' => null,
'serializer' => 'php',
);
private $client;
private $lazyClient;
public static function isSupported()
{
return \extension_loaded('memcached') && version_compare(phpversion('memcached'), '2.2.0', '>=');
}
private function init(\Memcached $client, $namespace, $defaultLifetime)
{
if (!static::isSupported()) {
throw new CacheException('Memcached >= 2.2.0 is required');
}
if ('Memcached' === \get_class($client)) {
$opt = $client->getOption(\Memcached::OPT_SERIALIZER);
if (\Memcached::SERIALIZER_PHP !== $opt && \Memcached::SERIALIZER_IGBINARY !== $opt) {
throw new CacheException('MemcachedAdapter: "serializer" option must be "php" or "igbinary".');
}
$this->maxIdLength -= \strlen($client->getOption(\Memcached::OPT_PREFIX_KEY));
$this->client = $client;
} else {
$this->lazyClient = $client;
}
parent::__construct($namespace, $defaultLifetime);
$this->enableVersioning();
}
/**
* Creates a Memcached instance.
*
* By default, the binary protocol, no block, and libketama compatible options are enabled.
*
* Examples for servers:
* - 'memcached://user:pass@localhost?weight=33'
* - array(array('localhost', 11211, 33))
*
* @param array[]|string|string[] An array of servers, a DSN, or an array of DSNs
* @param array An array of options
*
* @return \Memcached
*
* @throws \ErrorException When invalid options or servers are provided
*/
public static function createConnection($servers, array $options = array())
{
if (\is_string($servers)) {
$servers = array($servers);
} elseif (!\is_array($servers)) {
throw new InvalidArgumentException(sprintf('MemcachedAdapter::createClient() expects array or string as first argument, %s given.', \gettype($servers)));
}
if (!static::isSupported()) {
throw new CacheException('Memcached >= 2.2.0 is required');
}
set_error_handler(function ($type, $msg, $file, $line) { throw new \ErrorException($msg, 0, $type, $file, $line); });
try {
$options += static::$defaultClientOptions;
$client = new \Memcached($options['persistent_id']);
$username = $options['username'];
$password = $options['password'];
// parse any DSN in $servers
foreach ($servers as $i => $dsn) {
if (\is_array($dsn)) {
continue;
}
if (0 !== strpos($dsn, 'memcached://')) {
throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: %s does not start with "memcached://"', $dsn));
}
$params = preg_replace_callback('#^memcached://(?:([^@]*+)@)?#', function ($m) use (&$username, &$password) {
if (!empty($m[1])) {
list($username, $password) = explode(':', $m[1], 2) + array(1 => null);
}
return 'file://';
}, $dsn);
if (false === $params = parse_url($params)) {
throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: %s', $dsn));
}
if (!isset($params['host']) && !isset($params['path'])) {
throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: %s', $dsn));
}
if (isset($params['path']) && preg_match('#/(\d+)$#', $params['path'], $m)) {
$params['weight'] = $m[1];
$params['path'] = substr($params['path'], 0, -\strlen($m[0]));
}
$params += array(
'host' => isset($params['host']) ? $params['host'] : $params['path'],
'port' => isset($params['host']) ? 11211 : null,
'weight' => 0,
);
if (isset($params['query'])) {
parse_str($params['query'], $query);
$params += $query;
$options = $query + $options;
}
$servers[$i] = array($params['host'], $params['port'], $params['weight']);
}
// set client's options
unset($options['persistent_id'], $options['username'], $options['password'], $options['weight'], $options['lazy']);
$options = array_change_key_case($options, CASE_UPPER);
$client->setOption(\Memcached::OPT_BINARY_PROTOCOL, true);
$client->setOption(\Memcached::OPT_NO_BLOCK, true);
$client->setOption(\Memcached::OPT_TCP_NODELAY, true);
if (!array_key_exists('LIBKETAMA_COMPATIBLE', $options) && !array_key_exists(\Memcached::OPT_LIBKETAMA_COMPATIBLE, $options)) {
$client->setOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE, true);
}
foreach ($options as $name => $value) {
if (\is_int($name)) {
continue;
}
if ('HASH' === $name || 'SERIALIZER' === $name || 'DISTRIBUTION' === $name) {
$value = \constant('Memcached::'.$name.'_'.strtoupper($value));
}
$opt = \constant('Memcached::OPT_'.$name);
unset($options[$name]);
$options[$opt] = $value;
}
$client->setOptions($options);
// set client's servers, taking care of persistent connections
if (!$client->isPristine()) {
$oldServers = array();
foreach ($client->getServerList() as $server) {
$oldServers[] = array($server['host'], $server['port']);
}
$newServers = array();
foreach ($servers as $server) {
if (1 < \count($server)) {
$server = array_values($server);
unset($server[2]);
$server[1] = (int) $server[1];
}
$newServers[] = $server;
}
if ($oldServers !== $newServers) {
$client->resetServerList();
$client->addServers($servers);
}
} else {
$client->addServers($servers);
}
if (null !== $username || null !== $password) {
if (!method_exists($client, 'setSaslAuthData')) {
trigger_error('Missing SASL support: the memcached extension must be compiled with --enable-memcached-sasl.');
}
$client->setSaslAuthData($username, $password);
}
return $client;
} finally {
restore_error_handler();
}
}
/**
* {@inheritdoc}
*/
protected function doSave(array $values, $lifetime)
{
if ($lifetime && $lifetime > 30 * 86400) {
$lifetime += time();
}
$encodedValues = array();
foreach ($values as $key => $value) {
$encodedValues[rawurlencode($key)] = $value;
}
return $this->checkResultCode($this->getClient()->setMulti($encodedValues, $lifetime));
}
/**
* {@inheritdoc}
*/
protected function doFetch(array $ids)
{
$unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');
try {
$encodedIds = array_map('rawurlencode', $ids);
$encodedResult = $this->checkResultCode($this->getClient()->getMulti($encodedIds));
$result = array();
foreach ($encodedResult as $key => $value) {
$result[rawurldecode($key)] = $value;
}
return $result;
} catch (\Error $e) {
throw new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine());
} finally {
ini_set('unserialize_callback_func', $unserializeCallbackHandler);
}
}
/**
* {@inheritdoc}
*/
protected function doHave($id)
{
return false !== $this->getClient()->get(rawurlencode($id)) || $this->checkResultCode(\Memcached::RES_SUCCESS === $this->client->getResultCode());
}
/**
* {@inheritdoc}
*/
protected function doDelete(array $ids)
{
$ok = true;
$encodedIds = array_map('rawurlencode', $ids);
foreach ($this->checkResultCode($this->getClient()->deleteMulti($encodedIds)) as $result) {
if (\Memcached::RES_SUCCESS !== $result && \Memcached::RES_NOTFOUND !== $result) {
$ok = false;
}
}
return $ok;
}
/**
* {@inheritdoc}
*/
protected function doClear($namespace)
{
return false;
}
private function checkResultCode($result)
{
$code = $this->client->getResultCode();
if (\Memcached::RES_SUCCESS === $code || \Memcached::RES_NOTFOUND === $code) {
return $result;
}
throw new CacheException(sprintf('MemcachedAdapter client error: %s.', strtolower($this->client->getResultMessage())));
}
/**
* @return \Memcached
*/
private function getClient()
{
if ($this->client) {
return $this->client;
}
$opt = $this->lazyClient->getOption(\Memcached::OPT_SERIALIZER);
if (\Memcached::SERIALIZER_PHP !== $opt && \Memcached::SERIALIZER_IGBINARY !== $opt) {
throw new CacheException('MemcachedAdapter: "serializer" option must be "php" or "igbinary".');
}
if ('' !== $prefix = (string) $this->lazyClient->getOption(\Memcached::OPT_PREFIX_KEY)) {
throw new CacheException(sprintf('MemcachedAdapter: "prefix_key" option must be empty when using proxified connections, "%s" given.', $prefix));
}
return $this->client = $this->lazyClient;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Traits;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
use Doctrine\DBAL\Schema\Schema;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
/**
* @internal
*/
trait PdoTrait
{
private $conn;
private $dsn;
private $driver;
private $serverVersion;
private $table = 'cache_items';
private $idCol = 'item_id';
private $dataCol = 'item_data';
private $lifetimeCol = 'item_lifetime';
private $timeCol = 'item_time';
private $username = '';
private $password = '';
private $connectionOptions = array();
private $namespace;
private function init($connOrDsn, $namespace, $defaultLifetime, array $options)
{
if (isset($namespace[0]) && preg_match('#[^-+.A-Za-z0-9]#', $namespace, $match)) {
throw new InvalidArgumentException(sprintf('Namespace contains "%s" but only characters in [-+.A-Za-z0-9] are allowed.', $match[0]));
}
if ($connOrDsn instanceof \PDO) {
if (\PDO::ERRMODE_EXCEPTION !== $connOrDsn->getAttribute(\PDO::ATTR_ERRMODE)) {
throw new InvalidArgumentException(sprintf('"%s" requires PDO error mode attribute be set to throw Exceptions (i.e. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION))', __CLASS__));
}
$this->conn = $connOrDsn;
} elseif ($connOrDsn instanceof Connection) {
$this->conn = $connOrDsn;
} elseif (\is_string($connOrDsn)) {
$this->dsn = $connOrDsn;
} else {
throw new InvalidArgumentException(sprintf('"%s" requires PDO or Doctrine\DBAL\Connection instance or DSN string as first argument, "%s" given.', __CLASS__, \is_object($connOrDsn) ? \get_class($connOrDsn) : \gettype($connOrDsn)));
}
$this->table = isset($options['db_table']) ? $options['db_table'] : $this->table;
$this->idCol = isset($options['db_id_col']) ? $options['db_id_col'] : $this->idCol;
$this->dataCol = isset($options['db_data_col']) ? $options['db_data_col'] : $this->dataCol;
$this->lifetimeCol = isset($options['db_lifetime_col']) ? $options['db_lifetime_col'] : $this->lifetimeCol;
$this->timeCol = isset($options['db_time_col']) ? $options['db_time_col'] : $this->timeCol;
$this->username = isset($options['db_username']) ? $options['db_username'] : $this->username;
$this->password = isset($options['db_password']) ? $options['db_password'] : $this->password;
$this->connectionOptions = isset($options['db_connection_options']) ? $options['db_connection_options'] : $this->connectionOptions;
$this->namespace = $namespace;
parent::__construct($namespace, $defaultLifetime);
}
/**
* Creates the table to store cache items which can be called once for setup.
*
* Cache ID are saved in a column of maximum length 255. Cache data is
* saved in a BLOB.
*
* @throws \PDOException When the table already exists
* @throws DBALException When the table already exists
* @throws \DomainException When an unsupported PDO driver is used
*/
public function createTable()
{
// connect if we are not yet
$conn = $this->getConnection();
if ($conn instanceof Connection) {
$types = array(
'mysql' => 'binary',
'sqlite' => 'text',
'pgsql' => 'string',
'oci' => 'string',
'sqlsrv' => 'string',
);
if (!isset($types[$this->driver])) {
throw new \DomainException(sprintf('Creating the cache table is currently not implemented for PDO driver "%s".', $this->driver));
}
$schema = new Schema();
$table = $schema->createTable($this->table);
$table->addColumn($this->idCol, $types[$this->driver], array('length' => 255));
$table->addColumn($this->dataCol, 'blob', array('length' => 16777215));
$table->addColumn($this->lifetimeCol, 'integer', array('unsigned' => true, 'notnull' => false));
$table->addColumn($this->timeCol, 'integer', array('unsigned' => true));
$table->setPrimaryKey(array($this->idCol));
foreach ($schema->toSql($conn->getDatabasePlatform()) as $sql) {
$conn->exec($sql);
}
return;
}
switch ($this->driver) {
case 'mysql':
// We use varbinary for the ID column because it prevents unwanted conversions:
// - character set conversions between server and client
// - trailing space removal
// - case-insensitivity
// - language processing like é == e
$sql = "CREATE TABLE $this->table ($this->idCol VARBINARY(255) NOT NULL PRIMARY KEY, $this->dataCol MEDIUMBLOB NOT NULL, $this->lifetimeCol INTEGER UNSIGNED, $this->timeCol INTEGER UNSIGNED NOT NULL) COLLATE utf8_bin, ENGINE = InnoDB";
break;
case 'sqlite':
$sql = "CREATE TABLE $this->table ($this->idCol TEXT NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER, $this->timeCol INTEGER NOT NULL)";
break;
case 'pgsql':
$sql = "CREATE TABLE $this->table ($this->idCol VARCHAR(255) NOT NULL PRIMARY KEY, $this->dataCol BYTEA NOT NULL, $this->lifetimeCol INTEGER, $this->timeCol INTEGER NOT NULL)";
break;
case 'oci':
$sql = "CREATE TABLE $this->table ($this->idCol VARCHAR2(255) NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER, $this->timeCol INTEGER NOT NULL)";
break;
case 'sqlsrv':
$sql = "CREATE TABLE $this->table ($this->idCol VARCHAR(255) NOT NULL PRIMARY KEY, $this->dataCol VARBINARY(MAX) NOT NULL, $this->lifetimeCol INTEGER, $this->timeCol INTEGER NOT NULL)";
break;
default:
throw new \DomainException(sprintf('Creating the cache table is currently not implemented for PDO driver "%s".', $this->driver));
}
$conn->exec($sql);
}
/**
* {@inheritdoc}
*/
public function prune()
{
$deleteSql = "DELETE FROM $this->table WHERE $this->lifetimeCol + $this->timeCol <= :time";
if ('' !== $this->namespace) {
$deleteSql .= " AND $this->idCol LIKE :namespace";
}
$delete = $this->getConnection()->prepare($deleteSql);
$delete->bindValue(':time', time(), \PDO::PARAM_INT);
if ('' !== $this->namespace) {
$delete->bindValue(':namespace', sprintf('%s%%', $this->namespace), \PDO::PARAM_STR);
}
return $delete->execute();
}
/**
* {@inheritdoc}
*/
protected function doFetch(array $ids)
{
$now = time();
$expired = array();
$sql = str_pad('', (\count($ids) << 1) - 1, '?,');
$sql = "SELECT $this->idCol, CASE WHEN $this->lifetimeCol IS NULL OR $this->lifetimeCol + $this->timeCol > ? THEN $this->dataCol ELSE NULL END FROM $this->table WHERE $this->idCol IN ($sql)";
$stmt = $this->getConnection()->prepare($sql);
$stmt->bindValue($i = 1, $now, \PDO::PARAM_INT);
foreach ($ids as $id) {
$stmt->bindValue(++$i, $id);
}
$stmt->execute();
while ($row = $stmt->fetch(\PDO::FETCH_NUM)) {
if (null === $row[1]) {
$expired[] = $row[0];
} else {
yield $row[0] => parent::unserialize(\is_resource($row[1]) ? stream_get_contents($row[1]) : $row[1]);
}
}
if ($expired) {
$sql = str_pad('', (\count($expired) << 1) - 1, '?,');
$sql = "DELETE FROM $this->table WHERE $this->lifetimeCol + $this->timeCol <= ? AND $this->idCol IN ($sql)";
$stmt = $this->getConnection()->prepare($sql);
$stmt->bindValue($i = 1, $now, \PDO::PARAM_INT);
foreach ($expired as $id) {
$stmt->bindValue(++$i, $id);
}
$stmt->execute();
}
}
/**
* {@inheritdoc}
*/
protected function doHave($id)
{
$sql = "SELECT 1 FROM $this->table WHERE $this->idCol = :id AND ($this->lifetimeCol IS NULL OR $this->lifetimeCol + $this->timeCol > :time)";
$stmt = $this->getConnection()->prepare($sql);
$stmt->bindValue(':id', $id);
$stmt->bindValue(':time', time(), \PDO::PARAM_INT);
$stmt->execute();
return (bool) $stmt->fetchColumn();
}
/**
* {@inheritdoc}
*/
protected function doClear($namespace)
{
$conn = $this->getConnection();
if ('' === $namespace) {
if ('sqlite' === $this->driver) {
$sql = "DELETE FROM $this->table";
} else {
$sql = "TRUNCATE TABLE $this->table";
}
} else {
$sql = "DELETE FROM $this->table WHERE $this->idCol LIKE '$namespace%'";
}
$conn->exec($sql);
return true;
}
/**
* {@inheritdoc}
*/
protected function doDelete(array $ids)
{
$sql = str_pad('', (\count($ids) << 1) - 1, '?,');
$sql = "DELETE FROM $this->table WHERE $this->idCol IN ($sql)";
$stmt = $this->getConnection()->prepare($sql);
$stmt->execute(array_values($ids));
return true;
}
/**
* {@inheritdoc}
*/
protected function doSave(array $values, $lifetime)
{
$serialized = array();
$failed = array();
foreach ($values as $id => $value) {
try {
$serialized[$id] = serialize($value);
} catch (\Exception $e) {
$failed[] = $id;
}
}
if (!$serialized) {
return $failed;
}
$conn = $this->getConnection();
$driver = $this->driver;
$insertSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time)";
switch (true) {
case 'mysql' === $driver:
$sql = $insertSql." ON DUPLICATE KEY UPDATE $this->dataCol = VALUES($this->dataCol), $this->lifetimeCol = VALUES($this->lifetimeCol), $this->timeCol = VALUES($this->timeCol)";
break;
case 'oci' === $driver:
// DUAL is Oracle specific dummy table
$sql = "MERGE INTO $this->table USING DUAL ON ($this->idCol = ?) ".
"WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (?, ?, ?, ?) ".
"WHEN MATCHED THEN UPDATE SET $this->dataCol = ?, $this->lifetimeCol = ?, $this->timeCol = ?";
break;
case 'sqlsrv' === $driver && version_compare($this->getServerVersion(), '10', '>='):
// MERGE is only available since SQL Server 2008 and must be terminated by semicolon
// It also requires HOLDLOCK according to http://weblogs.sqlteam.com/dang/archive/2009/01/31/UPSERT-Race-Condition-With-MERGE.aspx
$sql = "MERGE INTO $this->table WITH (HOLDLOCK) USING (SELECT 1 AS dummy) AS src ON ($this->idCol = ?) ".
"WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (?, ?, ?, ?) ".
"WHEN MATCHED THEN UPDATE SET $this->dataCol = ?, $this->lifetimeCol = ?, $this->timeCol = ?;";
break;
case 'sqlite' === $driver:
$sql = 'INSERT OR REPLACE'.substr($insertSql, 6);
break;
case 'pgsql' === $driver && version_compare($this->getServerVersion(), '9.5', '>='):
$sql = $insertSql." ON CONFLICT ($this->idCol) DO UPDATE SET ($this->dataCol, $this->lifetimeCol, $this->timeCol) = (EXCLUDED.$this->dataCol, EXCLUDED.$this->lifetimeCol, EXCLUDED.$this->timeCol)";
break;
default:
$driver = null;
$sql = "UPDATE $this->table SET $this->dataCol = :data, $this->lifetimeCol = :lifetime, $this->timeCol = :time WHERE $this->idCol = :id";
break;
}
$now = time();
$lifetime = $lifetime ?: null;
$stmt = $conn->prepare($sql);
if ('sqlsrv' === $driver || 'oci' === $driver) {
$stmt->bindParam(1, $id);
$stmt->bindParam(2, $id);
$stmt->bindParam(3, $data, \PDO::PARAM_LOB);
$stmt->bindValue(4, $lifetime, \PDO::PARAM_INT);
$stmt->bindValue(5, $now, \PDO::PARAM_INT);
$stmt->bindParam(6, $data, \PDO::PARAM_LOB);
$stmt->bindValue(7, $lifetime, \PDO::PARAM_INT);
$stmt->bindValue(8, $now, \PDO::PARAM_INT);
} else {
$stmt->bindParam(':id', $id);
$stmt->bindParam(':data', $data, \PDO::PARAM_LOB);
$stmt->bindValue(':lifetime', $lifetime, \PDO::PARAM_INT);
$stmt->bindValue(':time', $now, \PDO::PARAM_INT);
}
if (null === $driver) {
$insertStmt = $conn->prepare($insertSql);
$insertStmt->bindParam(':id', $id);
$insertStmt->bindParam(':data', $data, \PDO::PARAM_LOB);
$insertStmt->bindValue(':lifetime', $lifetime, \PDO::PARAM_INT);
$insertStmt->bindValue(':time', $now, \PDO::PARAM_INT);
}
foreach ($serialized as $id => $data) {
$stmt->execute();
if (null === $driver && !$stmt->rowCount()) {
try {
$insertStmt->execute();
} catch (DBALException $e) {
} catch (\PDOException $e) {
// A concurrent write won, let it be
}
}
}
return $failed;
}
/**
* @return \PDO|Connection
*/
private function getConnection()
{
if (null === $this->conn) {
$this->conn = new \PDO($this->dsn, $this->username, $this->password, $this->connectionOptions);
$this->conn->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
}
if (null === $this->driver) {
if ($this->conn instanceof \PDO) {
$this->driver = $this->conn->getAttribute(\PDO::ATTR_DRIVER_NAME);
} else {
switch ($this->driver = $this->conn->getDriver()->getName()) {
case 'mysqli':
case 'pdo_mysql':
case 'drizzle_pdo_mysql':
$this->driver = 'mysql';
break;
case 'pdo_sqlite':
$this->driver = 'sqlite';
break;
case 'pdo_pgsql':
$this->driver = 'pgsql';
break;
case 'oci8':
case 'pdo_oracle':
$this->driver = 'oci';
break;
case 'pdo_sqlsrv':
$this->driver = 'sqlsrv';
break;
}
}
}
return $this->conn;
}
/**
* @return string
*/
private function getServerVersion()
{
if (null === $this->serverVersion) {
$conn = $this->conn instanceof \PDO ? $this->conn : $this->conn->getWrappedConnection();
if ($conn instanceof \PDO) {
$this->serverVersion = $conn->getAttribute(\PDO::ATTR_SERVER_VERSION);
} elseif ($conn instanceof ServerInfoAwareConnection) {
$this->serverVersion = $conn->getServerVersion();
} else {
$this->serverVersion = '0';
}
}
return $this->serverVersion;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Traits;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
/**
* @author Titouan Galopin <[email protected]>
* @author Nicolas Grekas <[email protected]>
*
* @internal
*/
trait PhpArrayTrait
{
use ProxyTrait;
private $file;
private $values;
private $zendDetectUnicode;
/**
* Store an array of cached values.
*
* @param array $values The cached values
*/
public function warmUp(array $values)
{
if (file_exists($this->file)) {
if (!is_file($this->file)) {
throw new InvalidArgumentException(sprintf('Cache path exists and is not a file: %s.', $this->file));
}
if (!is_writable($this->file)) {
throw new InvalidArgumentException(sprintf('Cache file is not writable: %s.', $this->file));
}
} else {
$directory = \dirname($this->file);
if (!is_dir($directory) && !@mkdir($directory, 0777, true)) {
throw new InvalidArgumentException(sprintf('Cache directory does not exist and cannot be created: %s.', $directory));
}
if (!is_writable($directory)) {
throw new InvalidArgumentException(sprintf('Cache directory is not writable: %s.', $directory));
}
}
$dump = <<<'EOF'
<?php
// This file has been auto-generated by the Symfony Cache Component.
return array(
EOF;
foreach ($values as $key => $value) {
CacheItem::validateKey(\is_int($key) ? (string) $key : $key);
if (null === $value || \is_object($value)) {
try {
$value = serialize($value);
} catch (\Exception $e) {
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, \get_class($value)), 0, $e);
}
} elseif (\is_array($value)) {
try {
$serialized = serialize($value);
$unserialized = unserialize($serialized);
} catch (\Exception $e) {
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable array value.', $key), 0, $e);
}
// Store arrays serialized if they contain any objects or references
if ($unserialized !== $value || (false !== strpos($serialized, ';R:') && preg_match('/;R:[1-9]/', $serialized))) {
$value = $serialized;
}
} elseif (\is_string($value)) {
// Serialize strings if they could be confused with serialized objects or arrays
if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) {
$value = serialize($value);
}
} elseif (!\is_scalar($value)) {
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, \gettype($value)));
}
$dump .= var_export($key, true).' => '.var_export($value, true).",\n";
}
$dump .= "\n);\n";
$dump = str_replace("' . \"\\0\" . '", "\0", $dump);
$tmpFile = uniqid($this->file, true);
file_put_contents($tmpFile, $dump);
@chmod($tmpFile, 0666 & ~umask());
unset($serialized, $unserialized, $value, $dump);
@rename($tmpFile, $this->file);
$this->initialize();
}
/**
* {@inheritdoc}
*/
public function clear()
{
$this->values = array();
$cleared = @unlink($this->file) || !file_exists($this->file);
return $this->pool->clear() && $cleared;
}
/**
* Load the cache file.
*/
private function initialize()
{
if ($this->zendDetectUnicode) {
$zmb = ini_set('zend.detect_unicode', 0);
}
try {
$this->values = file_exists($this->file) ? (include $this->file ?: array()) : array();
} finally {
if ($this->zendDetectUnicode) {
ini_set('zend.detect_unicode', $zmb);
}
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Traits;
use Symfony\Component\Cache\Exception\CacheException;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
/**
* @author Piotr Stankowski <[email protected]>
* @author Nicolas Grekas <[email protected]>
* @author Rob Frawley 2nd <[email protected]>
*
* @internal
*/
trait PhpFilesTrait
{
use FilesystemCommonTrait;
private $includeHandler;
private $zendDetectUnicode;
public static function isSupported()
{
return \function_exists('opcache_invalidate') && ini_get('opcache.enable');
}
/**
* @return bool
*/
public function prune()
{
$time = time();
$pruned = true;
$allowCompile = 'cli' !== \PHP_SAPI || ini_get('opcache.enable_cli');
set_error_handler($this->includeHandler);
try {
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
list($expiresAt) = include $file;
if ($time >= $expiresAt) {
$pruned = @unlink($file) && !file_exists($file) && $pruned;
if ($allowCompile) {
@opcache_invalidate($file, true);
}
}
}
} finally {
restore_error_handler();
}
return $pruned;
}
/**
* {@inheritdoc}
*/
protected function doFetch(array $ids)
{
$values = array();
$now = time();
if ($this->zendDetectUnicode) {
$zmb = ini_set('zend.detect_unicode', 0);
}
set_error_handler($this->includeHandler);
try {
foreach ($ids as $id) {
try {
$file = $this->getFile($id);
list($expiresAt, $values[$id]) = include $file;
if ($now >= $expiresAt) {
unset($values[$id]);
}
} catch (\Exception $e) {
continue;
}
}
} finally {
restore_error_handler();
if ($this->zendDetectUnicode) {
ini_set('zend.detect_unicode', $zmb);
}
}
foreach ($values as $id => $value) {
if ('N;' === $value) {
$values[$id] = null;
} elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
$values[$id] = parent::unserialize($value);
}
}
return $values;
}
/**
* {@inheritdoc}
*/
protected function doHave($id)
{
return (bool) $this->doFetch(array($id));
}
/**
* {@inheritdoc}
*/
protected function doSave(array $values, $lifetime)
{
$ok = true;
$data = array($lifetime ? time() + $lifetime : PHP_INT_MAX, '');
$allowCompile = 'cli' !== \PHP_SAPI || ini_get('opcache.enable_cli');
foreach ($values as $key => $value) {
if (null === $value || \is_object($value)) {
$value = serialize($value);
} elseif (\is_array($value)) {
$serialized = serialize($value);
$unserialized = parent::unserialize($serialized);
// Store arrays serialized if they contain any objects or references
if ($unserialized !== $value || (false !== strpos($serialized, ';R:') && preg_match('/;R:[1-9]/', $serialized))) {
$value = $serialized;
}
} elseif (\is_string($value)) {
// Serialize strings if they could be confused with serialized objects or arrays
if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) {
$value = serialize($value);
}
} elseif (!\is_scalar($value)) {
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, \gettype($value)));
}
$data[1] = $value;
$file = $this->getFile($key, true);
$ok = $this->write($file, '<?php return '.var_export($data, true).';') && $ok;
if ($allowCompile) {
@opcache_invalidate($file, true);
}
}
if (!$ok && !is_writable($this->directory)) {
throw new CacheException(sprintf('Cache directory is not writable (%s)', $this->directory));
}
return $ok;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Traits;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\ResettableInterface;
/**
* @author Nicolas Grekas <[email protected]>
*
* @internal
*/
trait ProxyTrait
{
private $pool;
/**
* {@inheritdoc}
*/
public function prune()
{
return $this->pool instanceof PruneableInterface && $this->pool->prune();
}
/**
* {@inheritdoc}
*/
public function reset()
{
if ($this->pool instanceof ResettableInterface) {
$this->pool->reset();
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Traits;
/**
* @author Nicolas Grekas <[email protected]>
*
* @internal
*/
class RedisProxy
{
private $redis;
private $initializer;
private $ready = false;
public function __construct(\Redis $redis, \Closure $initializer)
{
$this->redis = $redis;
$this->initializer = $initializer;
}
public function __call($method, array $args)
{
$this->ready ?: $this->ready = $this->initializer->__invoke($this->redis);
return \call_user_func_array(array($this->redis, $method), $args);
}
public function hscan($strKey, &$iIterator, $strPattern = null, $iCount = null)
{
$this->ready ?: $this->ready = $this->initializer->__invoke($this->redis);
return $this->redis->hscan($strKey, $iIterator, $strPattern, $iCount);
}
public function scan(&$iIterator, $strPattern = null, $iCount = null)
{
$this->ready ?: $this->ready = $this->initializer->__invoke($this->redis);
return $this->redis->scan($iIterator, $strPattern, $iCount);
}
public function sscan($strKey, &$iIterator, $strPattern = null, $iCount = null)
{
$this->ready ?: $this->ready = $this->initializer->__invoke($this->redis);
return $this->redis->sscan($strKey, $iIterator, $strPattern, $iCount);
}
public function zscan($strKey, &$iIterator, $strPattern = null, $iCount = null)
{
$this->ready ?: $this->ready = $this->initializer->__invoke($this->redis);
return $this->redis->zscan($strKey, $iIterator, $strPattern, $iCount);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Cache\Traits;
use Predis\Connection\Aggregate\ClusterInterface;
use Predis\Connection\Aggregate\PredisCluster;
use Predis\Connection\Aggregate\RedisCluster;
use Predis\Connection\Factory;
use Predis\Response\Status;
use Symfony\Component\Cache\Exception\CacheException;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
/**
* @author Aurimas Niekis <[email protected]>
* @author Nicolas Grekas <[email protected]>
*
* @internal
*/
trait RedisTrait
{
private static $defaultConnectionOptions = array(
'class' => null,
'persistent' => 0,
'persistent_id' => null,
'timeout' => 30,
'read_timeout' => 0,
'retry_interval' => 0,
'lazy' => false,
);
private $redis;
/**
* @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient
*/
private function init($redisClient, $namespace = '', $defaultLifetime = 0)
{
parent::__construct($namespace, $defaultLifetime);
if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) {
throw new InvalidArgumentException(sprintf('RedisAdapter namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0]));
}
if ($redisClient instanceof \RedisCluster) {
$this->enableVersioning();
} elseif (!$redisClient instanceof \Redis && !$redisClient instanceof \RedisArray && !$redisClient instanceof \Predis\Client && !$redisClient instanceof RedisProxy) {
throw new InvalidArgumentException(sprintf('%s() expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\Client, %s given', __METHOD__, \is_object($redisClient) ? \get_class($redisClient) : \gettype($redisClient)));
}
$this->redis = $redisClient;
}
/**
* Creates a Redis connection using a DSN configuration.
*
* Example DSN:
* - redis://localhost
* - redis://example.com:1234
* - redis://[email protected]/13
* - redis:///var/run/redis.sock
* - redis://secret@/var/run/redis.sock/13
*
* @param string $dsn
* @param array $options See self::$defaultConnectionOptions
*
* @throws InvalidArgumentException when the DSN is invalid
*
* @return \Redis|\Predis\Client According to the "class" option
*/
public static function createConnection($dsn, array $options = array())
{
if (0 !== strpos($dsn, 'redis://')) {
throw new InvalidArgumentException(sprintf('Invalid Redis DSN: %s does not start with "redis://"', $dsn));
}
$params = preg_replace_callback('#^redis://(?:(?:[^:@]*+:)?([^@]*+)@)?#', function ($m) use (&$auth) {
if (isset($m[1])) {
$auth = $m[1];
}
return 'file://';
}, $dsn);
if (false === $params = parse_url($params)) {
throw new InvalidArgumentException(sprintf('Invalid Redis DSN: %s', $dsn));
}
if (!isset($params['host']) && !isset($params['path'])) {
throw new InvalidArgumentException(sprintf('Invalid Redis DSN: %s', $dsn));
}
if (isset($params['path']) && preg_match('#/(\d+)$#', $params['path'], $m)) {
$params['dbindex'] = $m[1];
$params['path'] = substr($params['path'], 0, -\strlen($m[0]));
}
if (isset($params['host'])) {
$scheme = 'tcp';
} else {
$scheme = 'unix';
}
$params += array(
'host' => isset($params['host']) ? $params['host'] : $params['path'],
'port' => isset($params['host']) ? 6379 : null,
'dbindex' => 0,
);
if (isset($params['query'])) {
parse_str($params['query'], $query);
$params += $query;
}
$params += $options + self::$defaultConnectionOptions;
if (null === $params['class'] && !\extension_loaded('redis') && !class_exists(\Predis\Client::class)) {
throw new CacheException(sprintf('Cannot find the "redis" extension, and "predis/predis" is not installed: %s', $dsn));
}
$class = null === $params['class'] ? (\extension_loaded('redis') ? \Redis::class : \Predis\Client::class) : $params['class'];
if (is_a($class, \Redis::class, true)) {
$connect = $params['persistent'] || $params['persistent_id'] ? 'pconnect' : 'connect';
$redis = new $class();
$initializer = function ($redis) use ($connect, $params, $dsn, $auth) {
try {
@$redis->{$connect}($params['host'], $params['port'], $params['timeout'], $params['persistent_id'], $params['retry_interval']);
} catch (\RedisException $e) {
throw new InvalidArgumentException(sprintf('Redis connection failed (%s): %s', $e->getMessage(), $dsn));
}
set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
$isConnected = $redis->isConnected();
restore_error_handler();
if (!$isConnected) {
$error = preg_match('/^Redis::p?connect\(\): (.*)/', $error, $error) ? sprintf(' (%s)', $error[1]) : '';
throw new InvalidArgumentException(sprintf('Redis connection failed%s: %s', $error, $dsn));
}
if ((null !== $auth && !$redis->auth($auth))
|| ($params['dbindex'] && !$redis->select($params['dbindex']))
|| ($params['read_timeout'] && !$redis->setOption(\Redis::OPT_READ_TIMEOUT, $params['read_timeout']))
) {
$e = preg_replace('/^ERR /', '', $redis->getLastError());
throw new InvalidArgumentException(sprintf('Redis connection failed (%s): %s', $e, $dsn));
}
return true;
};
if ($params['lazy']) {
$redis = new RedisProxy($redis, $initializer);
} else {
$initializer($redis);
}
} elseif (is_a($class, \Predis\Client::class, true)) {
$params['scheme'] = $scheme;
$params['database'] = $params['dbindex'] ?: null;
$params['password'] = $auth;
$redis = new $class((new Factory())->create($params));
} elseif (class_exists($class, false)) {
throw new InvalidArgumentException(sprintf('"%s" is not a subclass of "Redis" or "Predis\Client"', $class));
} else {
throw new InvalidArgumentException(sprintf('Class "%s" does not exist', $class));
}
return $redis;
}
/**
* {@inheritdoc}
*/
protected function doFetch(array $ids)
{
if ($ids) {
$values = $this->pipeline(function () use ($ids) {
foreach ($ids as $id) {
yield 'get' => array($id);
}
});
foreach ($values as $id => $v) {
if ($v) {
yield $id => parent::unserialize($v);
}
}
}
}
/**
* {@inheritdoc}
*/
protected function doHave($id)
{
return (bool) $this->redis->exists($id);
}
/**
* {@inheritdoc}
*/
protected function doClear($namespace)
{
// When using a native Redis cluster, clearing the cache is done by versioning in AbstractTrait::clear().
// This means old keys are not really removed until they expire and may need garbage collection.
$cleared = true;
$hosts = array($this->redis);
$evalArgs = array(array($namespace), 0);
if ($this->redis instanceof \Predis\Client) {
$evalArgs = array(0, $namespace);
$connection = $this->redis->getConnection();
if ($connection instanceof PredisCluster) {
$hosts = array();
foreach ($connection as $c) {
$hosts[] = new \Predis\Client($c);
}
} elseif ($connection instanceof RedisCluster) {
return false;
}
} elseif ($this->redis instanceof \RedisArray) {
$hosts = array();
foreach ($this->redis->_hosts() as $host) {
$hosts[] = $this->redis->_instance($host);
}
} elseif ($this->redis instanceof \RedisCluster) {
return false;
}
foreach ($hosts as $host) {
if (!isset($namespace[0])) {
$cleared = $host->flushDb() && $cleared;
continue;
}
$info = $host->info('Server');
$info = isset($info['Server']) ? $info['Server'] : $info;
if (!version_compare($info['redis_version'], '2.8', '>=')) {
// As documented in Redis documentation (http://redis.io/commands/keys) using KEYS
// can hang your server when it is executed against large databases (millions of items).
// Whenever you hit this scale, you should really consider upgrading to Redis 2.8 or above.
$cleared = $host->eval("local keys=redis.call('KEYS',ARGV[1]..'*') for i=1,#keys,5000 do redis.call('DEL',unpack(keys,i,math.min(i+4999,#keys))) end return 1", $evalArgs[0], $evalArgs[1]) && $cleared;
continue;
}
$cursor = null;
do {
$keys = $host instanceof \Predis\Client ? $host->scan($cursor, 'MATCH', $namespace.'*', 'COUNT', 1000) : $host->scan($cursor, $namespace.'*', 1000);
if (isset($keys[1]) && \is_array($keys[1])) {
$cursor = $keys[0];
$keys = $keys[1];
}
if ($keys) {
$host->del($keys);
}
} while ($cursor = (int) $cursor);
}
return $cleared;
}
/**
* {@inheritdoc}
*/
protected function doDelete(array $ids)
{
if ($ids) {
$this->redis->del($ids);
}
return true;
}
/**
* {@inheritdoc}
*/
protected function doSave(array $values, $lifetime)
{
$serialized = array();
$failed = array();
foreach ($values as $id => $value) {
try {
$serialized[$id] = serialize($value);
} catch (\Exception $e) {
$failed[] = $id;
}
}
if (!$serialized) {
return $failed;
}
$results = $this->pipeline(function () use ($serialized, $lifetime) {
foreach ($serialized as $id => $value) {
if (0 >= $lifetime) {
yield 'set' => array($id, $value);
} else {
yield 'setEx' => array($id, $lifetime, $value);
}
}
});
foreach ($results as $id => $result) {
if (true !== $result && (!$result instanceof Status || $result !== Status::get('OK'))) {
$failed[] = $id;
}
}
return $failed;
}
private function pipeline(\Closure $generator)
{
$ids = array();
if ($this->redis instanceof \Predis\Client && !$this->redis->getConnection() instanceof ClusterInterface) {
$results = $this->redis->pipeline(function ($redis) use ($generator, &$ids) {
foreach ($generator() as $command => $args) {
\call_user_func_array(array($redis, $command), $args);
$ids[] = $args[0];
}
});
} elseif ($this->redis instanceof \RedisArray) {
$connections = $results = $ids = array();
foreach ($generator() as $command => $args) {
if (!isset($connections[$h = $this->redis->_target($args[0])])) {
$connections[$h] = array($this->redis->_instance($h), -1);
$connections[$h][0]->multi(\Redis::PIPELINE);
}
\call_user_func_array(array($connections[$h][0], $command), $args);
$results[] = array($h, ++$connections[$h][1]);
$ids[] = $args[0];
}
foreach ($connections as $h => $c) {
$connections[$h] = $c[0]->exec();
}
foreach ($results as $k => list($h, $c)) {
$results[$k] = $connections[$h][$c];
}
} elseif ($this->redis instanceof \RedisCluster || ($this->redis instanceof \Predis\Client && $this->redis->getConnection() instanceof ClusterInterface)) {
// phpredis & predis don't support pipelining with RedisCluster
// see https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#pipelining
// see https://github.com/nrk/predis/issues/267#issuecomment-123781423
$results = array();
foreach ($generator() as $command => $args) {
$results[] = \call_user_func_array(array($this->redis, $command), $args);
$ids[] = $args[0];
}
} else {
$this->redis->multi(\Redis::PIPELINE);
foreach ($generator() as $command => $args) {
\call_user_func_array(array($this->redis, $command), $args);
$ids[] = $args[0];
}
$results = $this->redis->exec();
}
foreach ($ids as $k => $id) {
yield $id => $results[$k];
}
}
}

CHANGELOG

4.1.0

  • added setPathSeparator method to NodeBuilder class
  • added third $pathSeparator constructor argument to BaseNode
  • the Processor class has been made final

4.0.0

  • removed ConfigCachePass

3.4.0

  • added setDeprecated() method to indicate a deprecated node
  • added XmlUtils::parse() method to parse an XML string
  • deprecated ConfigCachePass

3.3.0

  • added ReflectionClassResource class
  • added second $exists constructor argument to ClassExistenceResource
  • made ClassExistenceResource work with interfaces and traits
  • added ConfigCachePass (originally in FrameworkBundle)
  • added castToArray() helper to turn any config value into an array

3.0.0

  • removed ReferenceDumper class
  • removed the ResourceInterface::isFresh() method
  • removed BCResourceInterfaceChecker class
  • removed ResourceInterface::getResource() method

2.8.0

The edge case of defining just one value for nodes of type Enum is now allowed:

$rootNode
    ->children()
        ->enumNode('variable')
            ->values(array('value'))
        ->end()
    ->end()
;

Before: InvalidArgumentException (variable must contain at least two distinct elements). After: the code will work as expected and it will restrict the values of the variable option to just value.

  • deprecated the ResourceInterface::isFresh() method. If you implement custom resource types and they can be validated that way, make them implement the new SelfCheckingResourceInterface.
  • deprecated the getResource() method in ResourceInterface. You can still call this method on concrete classes implementing the interface, but it does not make sense at the interface level as you need to know about the particular type of resource at hand to understand the semantics of the returned value.

2.7.0

  • added ConfigCacheInterface, ConfigCacheFactoryInterface and a basic ConfigCacheFactory implementation to delegate creation of ConfigCache instances

2.2.0

  • added ArrayNodeDefinition::canBeEnabled() and ArrayNodeDefinition::canBeDisabled() to ease configuration when some sections are respectively disabled / enabled by default.
  • added a normalizeKeys() method for array nodes (to avoid key normalization)
  • added numerical type handling for config definitions
  • added convenience methods for optional configuration sections to ArrayNodeDefinition
  • added a utils class for XML manipulations

2.1.0

  • added a way to add documentation on configuration
  • implemented Serializable on resources
  • LoaderResolverInterface is now used instead of LoaderResolver for type hinting
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config;
use Symfony\Component\Config\Resource\SelfCheckingResourceChecker;
/**
* ConfigCache caches arbitrary content in files on disk.
*
* When in debug mode, those metadata resources that implement
* \Symfony\Component\Config\Resource\SelfCheckingResourceInterface will
* be used to check cache freshness.
*
* @author Fabien Potencier <[email protected]>
* @author Matthias Pigulla <[email protected]>
*/
class ConfigCache extends ResourceCheckerConfigCache
{
private $debug;
/**
* @param string $file The absolute cache path
* @param bool $debug Whether debugging is enabled or not
*/
public function __construct(string $file, bool $debug)
{
$this->debug = $debug;
$checkers = array();
if (true === $this->debug) {
$checkers = array(new SelfCheckingResourceChecker());
}
parent::__construct($file, $checkers);
}
/**
* Checks if the cache is still fresh.
*
* This implementation always returns true when debug is off and the
* cache file exists.
*
* @return bool true if the cache is fresh, false otherwise
*/
public function isFresh()
{
if (!$this->debug && is_file($this->getPath())) {
return true;
}
return parent::isFresh();
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config;
/**
* Basic implementation of ConfigCacheFactoryInterface that
* creates an instance of the default ConfigCache.
*
* This factory and/or cache <em>do not</em> support cache validation
* by means of ResourceChecker instances (that is, service-based).
*
* @author Matthias Pigulla <[email protected]>
*/
class ConfigCacheFactory implements ConfigCacheFactoryInterface
{
private $debug;
/**
* @param bool $debug The debug flag to pass to ConfigCache
*/
public function __construct(bool $debug)
{
$this->debug = $debug;
}
/**
* {@inheritdoc}
*/
public function cache($file, $callback)
{
if (!\is_callable($callback)) {
throw new \InvalidArgumentException(sprintf('Invalid type for callback argument. Expected callable, but got "%s".', \gettype($callback)));
}
$cache = new ConfigCache($file, $this->debug);
if (!$cache->isFresh()) {
\call_user_func($callback, $cache);
}
return $cache;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config;
/**
* Interface for a ConfigCache factory. This factory creates
* an instance of ConfigCacheInterface and initializes the
* cache if necessary.
*
* @author Matthias Pigulla <[email protected]>
*/
interface ConfigCacheFactoryInterface
{
/**
* Creates a cache instance and (re-)initializes it if necessary.
*
* @param string $file The absolute cache file path
* @param callable $callable The callable to be executed when the cache needs to be filled (i. e. is not fresh). The cache will be passed as the only parameter to this callback
*
* @return ConfigCacheInterface $configCache The cache instance
*/
public function cache($file, $callable);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config;
use Symfony\Component\Config\Resource\ResourceInterface;
/**
* Interface for ConfigCache.
*
* @author Matthias Pigulla <[email protected]>
*/
interface ConfigCacheInterface
{
/**
* Gets the cache file path.
*
* @return string The cache file path
*/
public function getPath();
/**
* Checks if the cache is still fresh.
*
* This check should take the metadata passed to the write() method into consideration.
*
* @return bool Whether the cache is still fresh
*/
public function isFresh();
/**
* Writes the given content into the cache file. Metadata will be stored
* independently and can be used to check cache freshness at a later time.
*
* @param string $content The content to write into the cache
* @param ResourceInterface[]|null $metadata An array of ResourceInterface instances
*
* @throws \RuntimeException When the cache file cannot be written
*/
public function write($content, array $metadata = null);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
use Symfony\Component\Config\Definition\Exception\UnsetKeyException;
/**
* Represents an Array node in the config tree.
*
* @author Johannes M. Schmitt <[email protected]>
*/
class ArrayNode extends BaseNode implements PrototypeNodeInterface
{
protected $xmlRemappings = array();
protected $children = array();
protected $allowFalse = false;
protected $allowNewKeys = true;
protected $addIfNotSet = false;
protected $performDeepMerging = true;
protected $ignoreExtraKeys = false;
protected $removeExtraKeys = true;
protected $normalizeKeys = true;
public function setNormalizeKeys($normalizeKeys)
{
$this->normalizeKeys = (bool) $normalizeKeys;
}
/**
* Normalizes keys between the different configuration formats.
*
* Namely, you mostly have foo_bar in YAML while you have foo-bar in XML.
* After running this method, all keys are normalized to foo_bar.
*
* If you have a mixed key like foo-bar_moo, it will not be altered.
* The key will also not be altered if the target key already exists.
*
* @param mixed $value
*
* @return array The value with normalized keys
*/
protected function preNormalize($value)
{
if (!$this->normalizeKeys || !\is_array($value)) {
return $value;
}
$normalized = array();
foreach ($value as $k => $v) {
if (false !== strpos($k, '-') && false === strpos($k, '_') && !array_key_exists($normalizedKey = str_replace('-', '_', $k), $value)) {
$normalized[$normalizedKey] = $v;
} else {
$normalized[$k] = $v;
}
}
return $normalized;
}
/**
* Retrieves the children of this node.
*
* @return array The children
*/
public function getChildren()
{
return $this->children;
}
/**
* Sets the xml remappings that should be performed.
*
* @param array $remappings An array of the form array(array(string, string))
*/
public function setXmlRemappings(array $remappings)
{
$this->xmlRemappings = $remappings;
}
/**
* Gets the xml remappings that should be performed.
*
* @return array $remappings an array of the form array(array(string, string))
*/
public function getXmlRemappings()
{
return $this->xmlRemappings;
}
/**
* Sets whether to add default values for this array if it has not been
* defined in any of the configuration files.
*
* @param bool $boolean
*/
public function setAddIfNotSet($boolean)
{
$this->addIfNotSet = (bool) $boolean;
}
/**
* Sets whether false is allowed as value indicating that the array should be unset.
*
* @param bool $allow
*/
public function setAllowFalse($allow)
{
$this->allowFalse = (bool) $allow;
}
/**
* Sets whether new keys can be defined in subsequent configurations.
*
* @param bool $allow
*/
public function setAllowNewKeys($allow)
{
$this->allowNewKeys = (bool) $allow;
}
/**
* Sets if deep merging should occur.
*
* @param bool $boolean
*/
public function setPerformDeepMerging($boolean)
{
$this->performDeepMerging = (bool) $boolean;
}
/**
* Whether extra keys should just be ignore without an exception.
*
* @param bool $boolean To allow extra keys
* @param bool $remove To remove extra keys
*/
public function setIgnoreExtraKeys($boolean, $remove = true)
{
$this->ignoreExtraKeys = (bool) $boolean;
$this->removeExtraKeys = $this->ignoreExtraKeys && $remove;
}
/**
* {@inheritdoc}
*/
public function setName($name)
{
$this->name = $name;
}
/**
* {@inheritdoc}
*/
public function hasDefaultValue()
{
return $this->addIfNotSet;
}
/**
* {@inheritdoc}
*/
public function getDefaultValue()
{
if (!$this->hasDefaultValue()) {
throw new \RuntimeException(sprintf('The node at path "%s" has no default value.', $this->getPath()));
}
$defaults = array();
foreach ($this->children as $name => $child) {
if ($child->hasDefaultValue()) {
$defaults[$name] = $child->getDefaultValue();
}
}
return $defaults;
}
/**
* Adds a child node.
*
* @throws \InvalidArgumentException when the child node has no name
* @throws \InvalidArgumentException when the child node's name is not unique
*/
public function addChild(NodeInterface $node)
{
$name = $node->getName();
if (!\strlen($name)) {
throw new \InvalidArgumentException('Child nodes must be named.');
}
if (isset($this->children[$name])) {
throw new \InvalidArgumentException(sprintf('A child node named "%s" already exists.', $name));
}
$this->children[$name] = $node;
}
/**
* Finalizes the value of this node.
*
* @param mixed $value
*
* @return mixed The finalised value
*
* @throws UnsetKeyException
* @throws InvalidConfigurationException if the node doesn't have enough children
*/
protected function finalizeValue($value)
{
if (false === $value) {
throw new UnsetKeyException(sprintf('Unsetting key for path "%s", value: %s', $this->getPath(), json_encode($value)));
}
foreach ($this->children as $name => $child) {
if (!array_key_exists($name, $value)) {
if ($child->isRequired()) {
$ex = new InvalidConfigurationException(sprintf('The child node "%s" at path "%s" must be configured.', $name, $this->getPath()));
$ex->setPath($this->getPath());
throw $ex;
}
if ($child->hasDefaultValue()) {
$value[$name] = $child->getDefaultValue();
}
continue;
}
if ($child->isDeprecated()) {
@trigger_error($child->getDeprecationMessage($name, $this->getPath()), E_USER_DEPRECATED);
}
try {
$value[$name] = $child->finalize($value[$name]);
} catch (UnsetKeyException $e) {
unset($value[$name]);
}
}
return $value;
}
/**
* Validates the type of the value.
*
* @param mixed $value
*
* @throws InvalidTypeException
*/
protected function validateType($value)
{
if (!\is_array($value) && (!$this->allowFalse || false !== $value)) {
$ex = new InvalidTypeException(sprintf('Invalid type for path "%s". Expected array, but got %s', $this->getPath(), \gettype($value)));
if ($hint = $this->getInfo()) {
$ex->addHint($hint);
}
$ex->setPath($this->getPath());
throw $ex;
}
}
/**
* Normalizes the value.
*
* @param mixed $value The value to normalize
*
* @return mixed The normalized value
*
* @throws InvalidConfigurationException
*/
protected function normalizeValue($value)
{
if (false === $value) {
return $value;
}
$value = $this->remapXml($value);
$normalized = array();
foreach ($value as $name => $val) {
if (isset($this->children[$name])) {
$normalized[$name] = $this->children[$name]->normalize($val);
unset($value[$name]);
} elseif (!$this->removeExtraKeys) {
$normalized[$name] = $val;
}
}
// if extra fields are present, throw exception
if (\count($value) && !$this->ignoreExtraKeys) {
$ex = new InvalidConfigurationException(sprintf('Unrecognized option%s "%s" under "%s"', 1 === \count($value) ? '' : 's', implode(', ', array_keys($value)), $this->getPath()));
$ex->setPath($this->getPath());
throw $ex;
}
return $normalized;
}
/**
* Remaps multiple singular values to a single plural value.
*
* @param array $value The source values
*
* @return array The remapped values
*/
protected function remapXml($value)
{
foreach ($this->xmlRemappings as list($singular, $plural)) {
if (!isset($value[$singular])) {
continue;
}
$value[$plural] = Processor::normalizeConfig($value, $singular, $plural);
unset($value[$singular]);
}
return $value;
}
/**
* Merges values together.
*
* @param mixed $leftSide The left side to merge
* @param mixed $rightSide The right side to merge
*
* @return mixed The merged values
*
* @throws InvalidConfigurationException
* @throws \RuntimeException
*/
protected function mergeValues($leftSide, $rightSide)
{
if (false === $rightSide) {
// if this is still false after the last config has been merged the
// finalization pass will take care of removing this key entirely
return false;
}
if (false === $leftSide || !$this->performDeepMerging) {
return $rightSide;
}
foreach ($rightSide as $k => $v) {
// no conflict
if (!array_key_exists($k, $leftSide)) {
if (!$this->allowNewKeys) {
$ex = new InvalidConfigurationException(sprintf('You are not allowed to define new elements for path "%s". Please define all elements for this path in one config file. If you are trying to overwrite an element, make sure you redefine it with the same name.', $this->getPath()));
$ex->setPath($this->getPath());
throw $ex;
}
$leftSide[$k] = $v;
continue;
}
if (!isset($this->children[$k])) {
throw new \RuntimeException('merge() expects a normalized config array.');
}
$leftSide[$k] = $this->children[$k]->merge($leftSide[$k], $v);
}
return $leftSide;
}
/**
* {@inheritdoc}
*/
protected function allowPlaceholders(): bool
{
return false;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
use Symfony\Component\Config\Definition\Exception\Exception;
use Symfony\Component\Config\Definition\Exception\ForbiddenOverwriteException;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
use Symfony\Component\Config\Definition\Exception\UnsetKeyException;
/**
* The base node class.
*
* @author Johannes M. Schmitt <[email protected]>
*/
abstract class BaseNode implements NodeInterface
{
const DEFAULT_PATH_SEPARATOR = '.';
private static $placeholderUniquePrefix;
private static $placeholders = array();
protected $name;
protected $parent;
protected $normalizationClosures = array();
protected $finalValidationClosures = array();
protected $allowOverwrite = true;
protected $required = false;
protected $deprecationMessage = null;
protected $equivalentValues = array();
protected $attributes = array();
protected $pathSeparator;
private $handlingPlaceholder;
/**
* @throws \InvalidArgumentException if the name contains a period
*/
public function __construct(?string $name, NodeInterface $parent = null, string $pathSeparator = self::DEFAULT_PATH_SEPARATOR)
{
if (false !== strpos($name = (string) $name, $pathSeparator)) {
throw new \InvalidArgumentException('The name must not contain "'.$pathSeparator.'".');
}
$this->name = $name;
$this->parent = $parent;
$this->pathSeparator = $pathSeparator;
}
/**
* Register possible (dummy) values for a dynamic placeholder value.
*
* Matching configuration values will be processed with a provided value, one by one. After a provided value is
* successfully processed the configuration value is returned as is, thus preserving the placeholder.
*
* @internal
*/
public static function setPlaceholder(string $placeholder, array $values): void
{
if (!$values) {
throw new \InvalidArgumentException('At least one value must be provided.');
}
self::$placeholders[$placeholder] = $values;
}
/**
* Sets a common prefix for dynamic placeholder values.
*
* Matching configuration values will be skipped from being processed and are returned as is, thus preserving the
* placeholder. An exact match provided by {@see setPlaceholder()} might take precedence.
*
* @internal
*/
public static function setPlaceholderUniquePrefix(string $prefix): void
{
self::$placeholderUniquePrefix = $prefix;
}
/**
* Resets all current placeholders available.
*
* @internal
*/
public static function resetPlaceholders(): void
{
self::$placeholderUniquePrefix = null;
self::$placeholders = array();
}
public function setAttribute($key, $value)
{
$this->attributes[$key] = $value;
}
public function getAttribute($key, $default = null)
{
return isset($this->attributes[$key]) ? $this->attributes[$key] : $default;
}
public function hasAttribute($key)
{
return isset($this->attributes[$key]);
}
public function getAttributes()
{
return $this->attributes;
}
public function setAttributes(array $attributes)
{
$this->attributes = $attributes;
}
public function removeAttribute($key)
{
unset($this->attributes[$key]);
}
/**
* Sets an info message.
*
* @param string $info
*/
public function setInfo($info)
{
$this->setAttribute('info', $info);
}
/**
* Returns info message.
*
* @return string The info text
*/
public function getInfo()
{
return $this->getAttribute('info');
}
/**
* Sets the example configuration for this node.
*
* @param string|array $example
*/
public function setExample($example)
{
$this->setAttribute('example', $example);
}
/**
* Retrieves the example configuration for this node.
*
* @return string|array The example
*/
public function getExample()
{
return $this->getAttribute('example');
}
/**
* Adds an equivalent value.
*
* @param mixed $originalValue
* @param mixed $equivalentValue
*/
public function addEquivalentValue($originalValue, $equivalentValue)
{
$this->equivalentValues[] = array($originalValue, $equivalentValue);
}
/**
* Set this node as required.
*
* @param bool $boolean Required node
*/
public function setRequired($boolean)
{
$this->required = (bool) $boolean;
}
/**
* Sets this node as deprecated.
*
* You can use %node% and %path% placeholders in your message to display,
* respectively, the node name and its complete path.
*
* @param string|null $message Deprecated message
*/
public function setDeprecated($message)
{
$this->deprecationMessage = $message;
}
/**
* Sets if this node can be overridden.
*
* @param bool $allow
*/
public function setAllowOverwrite($allow)
{
$this->allowOverwrite = (bool) $allow;
}
/**
* Sets the closures used for normalization.
*
* @param \Closure[] $closures An array of Closures used for normalization
*/
public function setNormalizationClosures(array $closures)
{
$this->normalizationClosures = $closures;
}
/**
* Sets the closures used for final validation.
*
* @param \Closure[] $closures An array of Closures used for final validation
*/
public function setFinalValidationClosures(array $closures)
{
$this->finalValidationClosures = $closures;
}
/**
* {@inheritdoc}
*/
public function isRequired()
{
return $this->required;
}
/**
* Checks if this node is deprecated.
*
* @return bool
*/
public function isDeprecated()
{
return null !== $this->deprecationMessage;
}
/**
* Returns the deprecated message.
*
* @param string $node the configuration node name
* @param string $path the path of the node
*
* @return string
*/
public function getDeprecationMessage($node, $path)
{
return strtr($this->deprecationMessage, array('%node%' => $node, '%path%' => $path));
}
/**
* {@inheritdoc}
*/
public function getName()
{
return $this->name;
}
/**
* {@inheritdoc}
*/
public function getPath()
{
if (null !== $this->parent) {
return $this->parent->getPath().$this->pathSeparator.$this->name;
}
return $this->name;
}
/**
* {@inheritdoc}
*/
final public function merge($leftSide, $rightSide)
{
if (!$this->allowOverwrite) {
throw new ForbiddenOverwriteException(sprintf('Configuration path "%s" cannot be overwritten. You have to define all options for this path, and any of its sub-paths in one configuration section.', $this->getPath()));
}
if ($leftSide !== $leftPlaceholders = self::resolvePlaceholderValue($leftSide)) {
foreach ($leftPlaceholders as $leftPlaceholder) {
$this->handlingPlaceholder = $leftSide;
try {
$this->merge($leftPlaceholder, $rightSide);
} finally {
$this->handlingPlaceholder = null;
}
}
return $rightSide;
}
if ($rightSide !== $rightPlaceholders = self::resolvePlaceholderValue($rightSide)) {
foreach ($rightPlaceholders as $rightPlaceholder) {
$this->handlingPlaceholder = $rightSide;
try {
$this->merge($leftSide, $rightPlaceholder);
} finally {
$this->handlingPlaceholder = null;
}
}
return $rightSide;
}
$this->doValidateType($leftSide);
$this->doValidateType($rightSide);
return $this->mergeValues($leftSide, $rightSide);
}
/**
* {@inheritdoc}
*/
final public function normalize($value)
{
$value = $this->preNormalize($value);
// run custom normalization closures
foreach ($this->normalizationClosures as $closure) {
$value = $closure($value);
}
// resolve placeholder value
if ($value !== $placeholders = self::resolvePlaceholderValue($value)) {
foreach ($placeholders as $placeholder) {
$this->handlingPlaceholder = $value;
try {
$this->normalize($placeholder);
} finally {
$this->handlingPlaceholder = null;
}
}
return $value;
}
// replace value with their equivalent
foreach ($this->equivalentValues as $data) {
if ($data[0] === $value) {
$value = $data[1];
}
}
// validate type
$this->doValidateType($value);
// normalize value
return $this->normalizeValue($value);
}
/**
* Normalizes the value before any other normalization is applied.
*
* @param $value
*
* @return $value The normalized array value
*/
protected function preNormalize($value)
{
return $value;
}
/**
* Returns parent node for this node.
*
* @return NodeInterface|null
*/
public function getParent()
{
return $this->parent;
}
/**
* {@inheritdoc}
*/
final public function finalize($value)
{
if ($value !== $placeholders = self::resolvePlaceholderValue($value)) {
foreach ($placeholders as $placeholder) {
$this->handlingPlaceholder = $value;
try {
$this->finalize($placeholder);
} finally {
$this->handlingPlaceholder = null;
}
}
return $value;
}
$this->doValidateType($value);
$value = $this->finalizeValue($value);
// Perform validation on the final value if a closure has been set.
// The closure is also allowed to return another value.
foreach ($this->finalValidationClosures as $closure) {
try {
$value = $closure($value);
} catch (Exception $e) {
if ($e instanceof UnsetKeyException && null !== $this->handlingPlaceholder) {
continue;
}
throw $e;
} catch (\Exception $e) {
throw new InvalidConfigurationException(sprintf('Invalid configuration for path "%s": %s', $this->getPath(), $e->getMessage()), $e->getCode(), $e);
}
}
return $value;
}
/**
* Validates the type of a Node.
*
* @param mixed $value The value to validate
*
* @throws InvalidTypeException when the value is invalid
*/
abstract protected function validateType($value);
/**
* Normalizes the value.
*
* @param mixed $value The value to normalize
*
* @return mixed The normalized value
*/
abstract protected function normalizeValue($value);
/**
* Merges two values together.
*
* @param mixed $leftSide
* @param mixed $rightSide
*
* @return mixed The merged value
*/
abstract protected function mergeValues($leftSide, $rightSide);
/**
* Finalizes a value.
*
* @param mixed $value The value to finalize
*
* @return mixed The finalized value
*/
abstract protected function finalizeValue($value);
/**
* Tests if placeholder values are allowed for this node.
*/
protected function allowPlaceholders(): bool
{
return true;
}
/**
* Tests if a placeholder is being handled currently.
*/
protected function isHandlingPlaceholder(): bool
{
return null !== $this->handlingPlaceholder;
}
/**
* Gets allowed dynamic types for this node.
*/
protected function getValidPlaceholderTypes(): array
{
return array();
}
private static function resolvePlaceholderValue($value)
{
if (\is_string($value)) {
if (isset(self::$placeholders[$value])) {
return self::$placeholders[$value];
}
if (self::$placeholderUniquePrefix && 0 === strpos($value, self::$placeholderUniquePrefix)) {
return array();
}
}
return $value;
}
private function doValidateType($value): void
{
if (null !== $this->handlingPlaceholder && !$this->allowPlaceholders()) {
$e = new InvalidTypeException(sprintf('A dynamic value is not compatible with a "%s" node type at path "%s".', \get_class($this), $this->getPath()));
$e->setPath($this->getPath());
throw $e;
}
if (null === $this->handlingPlaceholder || null === $value) {
$this->validateType($value);
return;
}
$knownTypes = array_keys(self::$placeholders[$this->handlingPlaceholder]);
$validTypes = $this->getValidPlaceholderTypes();
if ($validTypes && array_diff($knownTypes, $validTypes)) {
$e = new InvalidTypeException(sprintf(
'Invalid type for path "%s". Expected %s, but got %s.',
$this->getPath(),
1 === \count($validTypes) ? '"'.reset($validTypes).'"' : 'one of "'.implode('", "', $validTypes).'"',
1 === \count($knownTypes) ? '"'.reset($knownTypes).'"' : 'one of "'.implode('", "', $knownTypes).'"'
));
if ($hint = $this->getInfo()) {
$e->addHint($hint);
}
$e->setPath($this->getPath());
throw $e;
}
$this->validateType($value);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
/**
* This node represents a Boolean value in the config tree.
*
* @author Johannes M. Schmitt <[email protected]>
*/
class BooleanNode extends ScalarNode
{
/**
* {@inheritdoc}
*/
protected function validateType($value)
{
if (!\is_bool($value)) {
$ex = new InvalidTypeException(sprintf('Invalid type for path "%s". Expected boolean, but got %s.', $this->getPath(), \gettype($value)));
if ($hint = $this->getInfo()) {
$ex->addHint($hint);
}
$ex->setPath($this->getPath());
throw $ex;
}
}
/**
* {@inheritdoc}
*/
protected function isValueEmpty($value)
{
// a boolean value cannot be empty
return false;
}
/**
* {@inheritdoc}
*/
protected function getValidPlaceholderTypes(): array
{
return array('bool');
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
use Symfony\Component\Config\Definition\ArrayNode;
use Symfony\Component\Config\Definition\Exception\InvalidDefinitionException;
use Symfony\Component\Config\Definition\PrototypedArrayNode;
/**
* This class provides a fluent interface for defining an array node.
*
* @author Johannes M. Schmitt <[email protected]>
*/
class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinitionInterface
{
protected $performDeepMerging = true;
protected $ignoreExtraKeys = false;
protected $removeExtraKeys = true;
protected $children = array();
protected $prototype;
protected $atLeastOne = false;
protected $allowNewKeys = true;
protected $key;
protected $removeKeyItem;
protected $addDefaults = false;
protected $addDefaultChildren = false;
protected $nodeBuilder;
protected $normalizeKeys = true;
/**
* {@inheritdoc}
*/
public function __construct(?string $name, NodeParentInterface $parent = null)
{
parent::__construct($name, $parent);
$this->nullEquivalent = array();
$this->trueEquivalent = array();
}
/**
* {@inheritdoc}
*/
public function setBuilder(NodeBuilder $builder)
{
$this->nodeBuilder = $builder;
}
/**
* {@inheritdoc}
*/
public function children()
{
return $this->getNodeBuilder();
}
/**
* Sets a prototype for child nodes.
*
* @param string $type The type of node
*
* @return NodeDefinition
*/
public function prototype($type)
{
return $this->prototype = $this->getNodeBuilder()->node(null, $type)->setParent($this);
}
/**
* @return VariableNodeDefinition
*/
public function variablePrototype()
{
return $this->prototype('variable');
}
/**
* @return ScalarNodeDefinition
*/
public function scalarPrototype()
{
return $this->prototype('scalar');
}
/**
* @return BooleanNodeDefinition
*/
public function booleanPrototype()
{
return $this->prototype('boolean');
}
/**
* @return IntegerNodeDefinition
*/
public function integerPrototype()
{
return $this->prototype('integer');
}
/**
* @return FloatNodeDefinition
*/
public function floatPrototype()
{
return $this->prototype('float');
}
/**
* @return ArrayNodeDefinition
*/
public function arrayPrototype()
{
return $this->prototype('array');
}
/**
* @return EnumNodeDefinition
*/
public function enumPrototype()
{
return $this->prototype('enum');
}
/**
* Adds the default value if the node is not set in the configuration.
*
* This method is applicable to concrete nodes only (not to prototype nodes).
* If this function has been called and the node is not set during the finalization
* phase, it's default value will be derived from its children default values.
*
* @return $this
*/
public function addDefaultsIfNotSet()
{
$this->addDefaults = true;
return $this;
}
/**
* Adds children with a default value when none are defined.
*
* This method is applicable to prototype nodes only.
*
* @param int|string|array|null $children The number of children|The child name|The children names to be added
*
* @return $this
*/
public function addDefaultChildrenIfNoneSet($children = null)
{
$this->addDefaultChildren = $children;
return $this;
}
/**
* Requires the node to have at least one element.
*
* This method is applicable to prototype nodes only.
*
* @return $this
*/
public function requiresAtLeastOneElement()
{
$this->atLeastOne = true;
return $this;
}
/**
* Disallows adding news keys in a subsequent configuration.
*
* If used all keys have to be defined in the same configuration file.
*
* @return $this
*/
public function disallowNewKeysInSubsequentConfigs()
{
$this->allowNewKeys = false;
return $this;
}
/**
* Sets a normalization rule for XML configurations.
*
* @param string $singular The key to remap
* @param string $plural The plural of the key for irregular plurals
*
* @return $this
*/
public function fixXmlConfig($singular, $plural = null)
{
$this->normalization()->remap($singular, $plural);
return $this;
}
/**
* Sets the attribute which value is to be used as key.
*
* This is useful when you have an indexed array that should be an
* associative array. You can select an item from within the array
* to be the key of the particular item. For example, if "id" is the
* "key", then:
*
* array(
* array('id' => 'my_name', 'foo' => 'bar'),
* );
*
* becomes
*
* array(
* 'my_name' => array('foo' => 'bar'),
* );
*
* If you'd like "'id' => 'my_name'" to still be present in the resulting
* array, then you can set the second argument of this method to false.
*
* This method is applicable to prototype nodes only.
*
* @param string $name The name of the key
* @param bool $removeKeyItem Whether or not the key item should be removed
*
* @return $this
*/
public function useAttributeAsKey($name, $removeKeyItem = true)
{
$this->key = $name;
$this->removeKeyItem = $removeKeyItem;
return $this;
}
/**
* Sets whether the node can be unset.
*
* @param bool $allow
*
* @return $this
*/
public function canBeUnset($allow = true)
{
$this->merge()->allowUnset($allow);
return $this;
}
/**
* Adds an "enabled" boolean to enable the current section.
*
* By default, the section is disabled. If any configuration is specified then
* the node will be automatically enabled:
*
* enableableArrayNode: {enabled: true, ...} # The config is enabled & default values get overridden
* enableableArrayNode: ~ # The config is enabled & use the default values
* enableableArrayNode: true # The config is enabled & use the default values
* enableableArrayNode: {other: value, ...} # The config is enabled & default values get overridden
* enableableArrayNode: {enabled: false, ...} # The config is disabled
* enableableArrayNode: false # The config is disabled
*
* @return $this
*/
public function canBeEnabled()
{
$this
->addDefaultsIfNotSet()
->treatFalseLike(array('enabled' => false))
->treatTrueLike(array('enabled' => true))
->treatNullLike(array('enabled' => true))
->beforeNormalization()
->ifArray()
->then(function ($v) {
$v['enabled'] = isset($v['enabled']) ? $v['enabled'] : true;
return $v;
})
->end()
->children()
->booleanNode('enabled')
->defaultFalse()
;
return $this;
}
/**
* Adds an "enabled" boolean to enable the current section.
*
* By default, the section is enabled.
*
* @return $this
*/
public function canBeDisabled()
{
$this
->addDefaultsIfNotSet()
->treatFalseLike(array('enabled' => false))
->treatTrueLike(array('enabled' => true))
->treatNullLike(array('enabled' => true))
->children()
->booleanNode('enabled')
->defaultTrue()
;
return $this;
}
/**
* Disables the deep merging of the node.
*
* @return $this
*/
public function performNoDeepMerging()
{
$this->performDeepMerging = false;
return $this;
}
/**
* Allows extra config keys to be specified under an array without
* throwing an exception.
*
* Those config values are simply ignored and removed from the
* resulting array. This should be used only in special cases where
* you want to send an entire configuration array through a special
* tree that processes only part of the array.
*
* @param bool $remove Whether to remove the extra keys
*
* @return $this
*/
public function ignoreExtraKeys($remove = true)
{
$this->ignoreExtraKeys = true;
$this->removeExtraKeys = $remove;
return $this;
}
/**
* Sets key normalization.
*
* @param bool $bool Whether to enable key normalization
*
* @return $this
*/
public function normalizeKeys($bool)
{
$this->normalizeKeys = (bool) $bool;
return $this;
}
/**
* {@inheritdoc}
*/
public function append(NodeDefinition $node)
{
$this->children[$node->name] = $node->setParent($this);
return $this;
}
/**
* Returns a node builder to be used to add children and prototype.
*
* @return NodeBuilder The node builder
*/
protected function getNodeBuilder()
{
if (null === $this->nodeBuilder) {
$this->nodeBuilder = new NodeBuilder();
}
return $this->nodeBuilder->setParent($this);
}
/**
* {@inheritdoc}
*/
protected function createNode()
{
if (null === $this->prototype) {
$node = new ArrayNode($this->name, $this->parent, $this->pathSeparator);
$this->validateConcreteNode($node);
$node->setAddIfNotSet($this->addDefaults);
foreach ($this->children as $child) {
$child->parent = $node;
$node->addChild($child->getNode());
}
} else {
$node = new PrototypedArrayNode($this->name, $this->parent, $this->pathSeparator);
$this->validatePrototypeNode($node);
if (null !== $this->key) {
$node->setKeyAttribute($this->key, $this->removeKeyItem);
}
if (true === $this->atLeastOne || false === $this->allowEmptyValue) {
$node->setMinNumberOfElements(1);
}
if ($this->default) {
$node->setDefaultValue($this->defaultValue);
}
if (false !== $this->addDefaultChildren) {
$node->setAddChildrenIfNoneSet($this->addDefaultChildren);
if ($this->prototype instanceof static && null === $this->prototype->prototype) {
$this->prototype->addDefaultsIfNotSet();
}
}
$this->prototype->parent = $node;
$node->setPrototype($this->prototype->getNode());
}
$node->setAllowNewKeys($this->allowNewKeys);
$node->addEquivalentValue(null, $this->nullEquivalent);
$node->addEquivalentValue(true, $this->trueEquivalent);
$node->addEquivalentValue(false, $this->falseEquivalent);
$node->setPerformDeepMerging($this->performDeepMerging);
$node->setRequired($this->required);
$node->setDeprecated($this->deprecationMessage);
$node->setIgnoreExtraKeys($this->ignoreExtraKeys, $this->removeExtraKeys);
$node->setNormalizeKeys($this->normalizeKeys);
if (null !== $this->normalization) {
$node->setNormalizationClosures($this->normalization->before);
$node->setXmlRemappings($this->normalization->remappings);
}
if (null !== $this->merge) {
$node->setAllowOverwrite($this->merge->allowOverwrite);
$node->setAllowFalse($this->merge->allowFalse);
}
if (null !== $this->validation) {
$node->setFinalValidationClosures($this->validation->rules);
}
return $node;
}
/**
* Validate the configuration of a concrete node.
*
* @throws InvalidDefinitionException
*/
protected function validateConcreteNode(ArrayNode $node)
{
$path = $node->getPath();
if (null !== $this->key) {
throw new InvalidDefinitionException(sprintf('->useAttributeAsKey() is not applicable to concrete nodes at path "%s"', $path));
}
if (false === $this->allowEmptyValue) {
throw new InvalidDefinitionException(sprintf('->cannotBeEmpty() is not applicable to concrete nodes at path "%s"', $path));
}
if (true === $this->atLeastOne) {
throw new InvalidDefinitionException(sprintf('->requiresAtLeastOneElement() is not applicable to concrete nodes at path "%s"', $path));
}
if ($this->default) {
throw new InvalidDefinitionException(sprintf('->defaultValue() is not applicable to concrete nodes at path "%s"', $path));
}
if (false !== $this->addDefaultChildren) {
throw new InvalidDefinitionException(sprintf('->addDefaultChildrenIfNoneSet() is not applicable to concrete nodes at path "%s"', $path));
}
}
/**
* Validate the configuration of a prototype node.
*
* @throws InvalidDefinitionException
*/
protected function validatePrototypeNode(PrototypedArrayNode $node)
{
$path = $node->getPath();
if ($this->addDefaults) {
throw new InvalidDefinitionException(sprintf('->addDefaultsIfNotSet() is not applicable to prototype nodes at path "%s"', $path));
}
if (false !== $this->addDefaultChildren) {
if ($this->default) {
throw new InvalidDefinitionException(sprintf('A default value and default children might not be used together at path "%s"', $path));
}
if (null !== $this->key && (null === $this->addDefaultChildren || \is_int($this->addDefaultChildren) && $this->addDefaultChildren > 0)) {
throw new InvalidDefinitionException(sprintf('->addDefaultChildrenIfNoneSet() should set default children names as ->useAttributeAsKey() is used at path "%s"', $path));
}
if (null === $this->key && (\is_string($this->addDefaultChildren) || \is_array($this->addDefaultChildren))) {
throw new InvalidDefinitionException(sprintf('->addDefaultChildrenIfNoneSet() might not set default children names as ->useAttributeAsKey() is not used at path "%s"', $path));
}
}
}
/**
* @return NodeDefinition[]
*/
public function getChildNodeDefinitions()
{
return $this->children;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
use Symfony\Component\Config\Definition\BooleanNode;
use Symfony\Component\Config\Definition\Exception\InvalidDefinitionException;
/**
* This class provides a fluent interface for defining a node.
*
* @author Johannes M. Schmitt <[email protected]>
*/
class BooleanNodeDefinition extends ScalarNodeDefinition
{
/**
* {@inheritdoc}
*/
public function __construct(?string $name, NodeParentInterface $parent = null)
{
parent::__construct($name, $parent);
$this->nullEquivalent = true;
}
/**
* Instantiate a Node.
*
* @return BooleanNode The node
*/
protected function instantiateNode()
{
return new BooleanNode($this->name, $this->parent, $this->pathSeparator);
}
/**
* {@inheritdoc}
*
* @throws InvalidDefinitionException
*/
public function cannotBeEmpty()
{
throw new InvalidDefinitionException('->cannotBeEmpty() is not applicable to BooleanNodeDefinition.');
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
/**
* An interface that can be implemented by nodes which build other nodes.
*
* @author Roland Franssen <[email protected]>
*/
interface BuilderAwareInterface
{
/**
* Sets a custom children builder.
*/
public function setBuilder(NodeBuilder $builder);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
use Symfony\Component\Config\Definition\EnumNode;
/**
* Enum Node Definition.
*
* @author Johannes M. Schmitt <[email protected]>
*/
class EnumNodeDefinition extends ScalarNodeDefinition
{
private $values;
/**
* @return $this
*/
public function values(array $values)
{
$values = array_unique($values);
if (empty($values)) {
throw new \InvalidArgumentException('->values() must be called with at least one value.');
}
$this->values = $values;
return $this;
}
/**
* Instantiate a Node.
*
* @return EnumNode The node
*
* @throws \RuntimeException
*/
protected function instantiateNode()
{
if (null === $this->values) {
throw new \RuntimeException('You must call ->values() on enum nodes.');
}
return new EnumNode($this->name, $this->parent, $this->values, $this->pathSeparator);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
use Symfony\Component\Config\Definition\Exception\UnsetKeyException;
/**
* This class builds an if expression.
*
* @author Johannes M. Schmitt <[email protected]>
* @author Christophe Coevoet <[email protected]>
*/
class ExprBuilder
{
protected $node;
public $ifPart;
public $thenPart;
public function __construct(NodeDefinition $node)
{
$this->node = $node;
}
/**
* Marks the expression as being always used.
*
* @return $this
*/
public function always(\Closure $then = null)
{
$this->ifPart = function ($v) { return true; };
if (null !== $then) {
$this->thenPart = $then;
}
return $this;
}
/**
* Sets a closure to use as tests.
*
* The default one tests if the value is true.
*
* @return $this
*/
public function ifTrue(\Closure $closure = null)
{
if (null === $closure) {
$closure = function ($v) { return true === $v; };
}
$this->ifPart = $closure;
return $this;
}
/**
* Tests if the value is a string.
*
* @return $this
*/
public function ifString()
{
$this->ifPart = function ($v) { return \is_string($v); };
return $this;
}
/**
* Tests if the value is null.
*
* @return $this
*/
public function ifNull()
{
$this->ifPart = function ($v) { return null === $v; };
return $this;
}
/**
* Tests if the value is empty.
*
* @return ExprBuilder
*/
public function ifEmpty()
{
$this->ifPart = function ($v) { return empty($v); };
return $this;
}
/**
* Tests if the value is an array.
*
* @return $this
*/
public function ifArray()
{
$this->ifPart = function ($v) { return \is_array($v); };
return $this;
}
/**
* Tests if the value is in an array.
*
* @return $this
*/
public function ifInArray(array $array)
{
$this->ifPart = function ($v) use ($array) { return \in_array($v, $array, true); };
return $this;
}
/**
* Tests if the value is not in an array.
*
* @return $this
*/
public function ifNotInArray(array $array)
{
$this->ifPart = function ($v) use ($array) { return !\in_array($v, $array, true); };
return $this;
}
/**
* Transforms variables of any type into an array.
*
* @return $this
*/
public function castToArray()
{
$this->ifPart = function ($v) { return !\is_array($v); };
$this->thenPart = function ($v) { return array($v); };
return $this;
}
/**
* Sets the closure to run if the test pass.
*
* @return $this
*/
public function then(\Closure $closure)
{
$this->thenPart = $closure;
return $this;
}
/**
* Sets a closure returning an empty array.
*
* @return $this
*/
public function thenEmptyArray()
{
$this->thenPart = function ($v) { return array(); };
return $this;
}
/**
* Sets a closure marking the value as invalid at validation time.
*
* if you want to add the value of the node in your message just use a %s placeholder.
*
* @param string $message
*
* @return $this
*
* @throws \InvalidArgumentException
*/
public function thenInvalid($message)
{
$this->thenPart = function ($v) use ($message) { throw new \InvalidArgumentException(sprintf($message, json_encode($v))); };
return $this;
}
/**
* Sets a closure unsetting this key of the array at validation time.
*
* @return $this
*
* @throws UnsetKeyException
*/
public function thenUnset()
{
$this->thenPart = function ($v) { throw new UnsetKeyException('Unsetting key'); };
return $this;
}
/**
* Returns the related node.
*
* @return NodeDefinition|ArrayNodeDefinition|VariableNodeDefinition
*
* @throws \RuntimeException
*/
public function end()
{
if (null === $this->ifPart) {
throw new \RuntimeException('You must specify an if part.');
}
if (null === $this->thenPart) {
throw new \RuntimeException('You must specify a then part.');
}
return $this->node;
}
/**
* Builds the expressions.
*
* @param ExprBuilder[] $expressions An array of ExprBuilder instances to build
*
* @return array
*/
public static function buildExpressions(array $expressions)
{
foreach ($expressions as $k => $expr) {
if ($expr instanceof self) {
$if = $expr->ifPart;
$then = $expr->thenPart;
$expressions[$k] = function ($v) use ($if, $then) {
return $if($v) ? $then($v) : $v;
};
}
}
return $expressions;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
use Symfony\Component\Config\Definition\FloatNode;
/**
* This class provides a fluent interface for defining a float node.
*
* @author Jeanmonod David <[email protected]>
*/
class FloatNodeDefinition extends NumericNodeDefinition
{
/**
* Instantiates a Node.
*
* @return FloatNode The node
*/
protected function instantiateNode()
{
return new FloatNode($this->name, $this->parent, $this->min, $this->max, $this->pathSeparator);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
use Symfony\Component\Config\Definition\IntegerNode;
/**
* This class provides a fluent interface for defining an integer node.
*
* @author Jeanmonod David <[email protected]>
*/
class IntegerNodeDefinition extends NumericNodeDefinition
{
/**
* Instantiates a Node.
*
* @return IntegerNode The node
*/
protected function instantiateNode()
{
return new IntegerNode($this->name, $this->parent, $this->min, $this->max, $this->pathSeparator);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
/**
* This class builds merge conditions.
*
* @author Johannes M. Schmitt <[email protected]>
*/
class MergeBuilder
{
protected $node;
public $allowFalse = false;
public $allowOverwrite = true;
public function __construct(NodeDefinition $node)
{
$this->node = $node;
}
/**
* Sets whether the node can be unset.
*
* @param bool $allow
*
* @return $this
*/
public function allowUnset($allow = true)
{
$this->allowFalse = $allow;
return $this;
}
/**
* Sets whether the node can be overwritten.
*
* @param bool $deny Whether the overwriting is forbidden or not
*
* @return $this
*/
public function denyOverwrite($deny = true)
{
$this->allowOverwrite = !$deny;
return $this;
}
/**
* Returns the related node.
*
* @return NodeDefinition|ArrayNodeDefinition|VariableNodeDefinition
*/
public function end()
{
return $this->node;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
/**
* This class provides a fluent interface for building a node.
*
* @author Johannes M. Schmitt <[email protected]>
*/
class NodeBuilder implements NodeParentInterface
{
protected $parent;
protected $nodeMapping;
public function __construct()
{
$this->nodeMapping = array(
'variable' => __NAMESPACE__.'\\VariableNodeDefinition',
'scalar' => __NAMESPACE__.'\\ScalarNodeDefinition',
'boolean' => __NAMESPACE__.'\\BooleanNodeDefinition',
'integer' => __NAMESPACE__.'\\IntegerNodeDefinition',
'float' => __NAMESPACE__.'\\FloatNodeDefinition',
'array' => __NAMESPACE__.'\\ArrayNodeDefinition',
'enum' => __NAMESPACE__.'\\EnumNodeDefinition',
);
}
/**
* Set the parent node.
*
* @return $this
*/
public function setParent(ParentNodeDefinitionInterface $parent = null)
{
$this->parent = $parent;
return $this;
}
/**
* Creates a child array node.
*
* @param string $name The name of the node
*
* @return ArrayNodeDefinition The child node
*/
public function arrayNode($name)
{
return $this->node($name, 'array');
}
/**
* Creates a child scalar node.
*
* @param string $name The name of the node
*
* @return ScalarNodeDefinition The child node
*/
public function scalarNode($name)
{
return $this->node($name, 'scalar');
}
/**
* Creates a child Boolean node.
*
* @param string $name The name of the node
*
* @return BooleanNodeDefinition The child node
*/
public function booleanNode($name)
{
return $this->node($name, 'boolean');
}
/**
* Creates a child integer node.
*
* @param string $name The name of the node
*
* @return IntegerNodeDefinition The child node
*/
public function integerNode($name)
{
return $this->node($name, 'integer');
}
/**
* Creates a child float node.
*
* @param string $name The name of the node
*
* @return FloatNodeDefinition The child node
*/
public function floatNode($name)
{
return $this->node($name, 'float');
}
/**
* Creates a child EnumNode.
*
* @param string $name
*
* @return EnumNodeDefinition
*/
public function enumNode($name)
{
return $this->node($name, 'enum');
}
/**
* Creates a child variable node.
*
* @param string $name The name of the node
*
* @return VariableNodeDefinition The builder of the child node
*/
public function variableNode($name)
{
return $this->node($name, 'variable');
}
/**
* Returns the parent node.
*
* @return ParentNodeDefinitionInterface|NodeDefinition The parent node
*/
public function end()
{
return $this->parent;
}
/**
* Creates a child node.
*
* @param string|null $name The name of the node
* @param string $type The type of the node
*
* @return NodeDefinition The child node
*
* @throws \RuntimeException When the node type is not registered
* @throws \RuntimeException When the node class is not found
*/
public function node($name, $type)
{
$class = $this->getNodeClass($type);
$node = new $class($name);
$this->append($node);
return $node;
}
/**
* Appends a node definition.
*
* Usage:
*
* $node = new ArrayNodeDefinition('name')
* ->children()
* ->scalarNode('foo')->end()
* ->scalarNode('baz')->end()
* ->append($this->getBarNodeDefinition())
* ->end()
* ;
*
* @return $this
*/
public function append(NodeDefinition $node)
{
if ($node instanceof BuilderAwareInterface) {
$builder = clone $this;
$builder->setParent(null);
$node->setBuilder($builder);
}
if (null !== $this->parent) {
$this->parent->append($node);
// Make this builder the node parent to allow for a fluid interface
$node->setParent($this);
}
return $this;
}
/**
* Adds or overrides a node Type.
*
* @param string $type The name of the type
* @param string $class The fully qualified name the node definition class
*
* @return $this
*/
public function setNodeClass($type, $class)
{
$this->nodeMapping[strtolower($type)] = $class;
return $this;
}
/**
* Returns the class name of the node definition.
*
* @param string $type The node type
*
* @return string The node definition class name
*
* @throws \RuntimeException When the node type is not registered
* @throws \RuntimeException When the node class is not found
*/
protected function getNodeClass($type)
{
$type = strtolower($type);
if (!isset($this->nodeMapping[$type])) {
throw new \RuntimeException(sprintf('The node type "%s" is not registered.', $type));
}
$class = $this->nodeMapping[$type];
if (!class_exists($class)) {
throw new \RuntimeException(sprintf('The node class "%s" does not exist.', $class));
}
return $class;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
use Symfony\Component\Config\Definition\BaseNode;
use Symfony\Component\Config\Definition\Exception\InvalidDefinitionException;
use Symfony\Component\Config\Definition\NodeInterface;
/**
* This class provides a fluent interface for defining a node.
*
* @author Johannes M. Schmitt <[email protected]>
*/
abstract class NodeDefinition implements NodeParentInterface
{
protected $name;
protected $normalization;
protected $validation;
protected $defaultValue;
protected $default = false;
protected $required = false;
protected $deprecationMessage = null;
protected $merge;
protected $allowEmptyValue = true;
protected $nullEquivalent;
protected $trueEquivalent = true;
protected $falseEquivalent = false;
protected $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR;
protected $parent;
protected $attributes = array();
public function __construct(?string $name, NodeParentInterface $parent = null)
{
$this->parent = $parent;
$this->name = $name;
}
/**
* Sets the parent node.
*
* @return $this
*/
public function setParent(NodeParentInterface $parent)
{
$this->parent = $parent;
return $this;
}
/**
* Sets info message.
*
* @param string $info The info text
*
* @return $this
*/
public function info($info)
{
return $this->attribute('info', $info);
}
/**
* Sets example configuration.
*
* @param string|array $example
*
* @return $this
*/
public function example($example)
{
return $this->attribute('example', $example);
}
/**
* Sets an attribute on the node.
*
* @param string $key
* @param mixed $value
*
* @return $this
*/
public function attribute($key, $value)
{
$this->attributes[$key] = $value;
return $this;
}
/**
* Returns the parent node.
*
* @return NodeParentInterface|NodeBuilder|NodeDefinition|ArrayNodeDefinition|VariableNodeDefinition|null The builder of the parent node
*/
public function end()
{
return $this->parent;
}
/**
* Creates the node.
*
* @param bool $forceRootNode Whether to force this node as the root node
*
* @return NodeInterface
*/
public function getNode($forceRootNode = false)
{
if ($forceRootNode) {
$this->parent = null;
}
if (null !== $this->normalization) {
$this->normalization->before = ExprBuilder::buildExpressions($this->normalization->before);
}
if (null !== $this->validation) {
$this->validation->rules = ExprBuilder::buildExpressions($this->validation->rules);
}
$node = $this->createNode();
$node->setAttributes($this->attributes);
return $node;
}
/**
* Sets the default value.
*
* @param mixed $value The default value
*
* @return $this
*/
public function defaultValue($value)
{
$this->default = true;
$this->defaultValue = $value;
return $this;
}
/**
* Sets the node as required.
*
* @return $this
*/
public function isRequired()
{
$this->required = true;
return $this;
}
/**
* Sets the node as deprecated.
*
* You can use %node% and %path% placeholders in your message to display,
* respectively, the node name and its complete path.
*
* @param string $message Deprecation message
*
* @return $this
*/
public function setDeprecated($message = 'The child node "%node%" at path "%path%" is deprecated.')
{
$this->deprecationMessage = $message;
return $this;
}
/**
* Sets the equivalent value used when the node contains null.
*
* @param mixed $value
*
* @return $this
*/
public function treatNullLike($value)
{
$this->nullEquivalent = $value;
return $this;
}
/**
* Sets the equivalent value used when the node contains true.
*
* @param mixed $value
*
* @return $this
*/
public function treatTrueLike($value)
{
$this->trueEquivalent = $value;
return $this;
}
/**
* Sets the equivalent value used when the node contains false.
*
* @param mixed $value
*
* @return $this
*/
public function treatFalseLike($value)
{
$this->falseEquivalent = $value;
return $this;
}
/**
* Sets null as the default value.
*
* @return $this
*/
public function defaultNull()
{
return $this->defaultValue(null);
}
/**
* Sets true as the default value.
*
* @return $this
*/
public function defaultTrue()
{
return $this->defaultValue(true);
}
/**
* Sets false as the default value.
*
* @return $this
*/
public function defaultFalse()
{
return $this->defaultValue(false);
}
/**
* Sets an expression to run before the normalization.
*
* @return ExprBuilder
*/
public function beforeNormalization()
{
return $this->normalization()->before();
}
/**
* Denies the node value being empty.
*
* @return $this
*/
public function cannotBeEmpty()
{
$this->allowEmptyValue = false;
return $this;
}
/**
* Sets an expression to run for the validation.
*
* The expression receives the value of the node and must return it. It can
* modify it.
* An exception should be thrown when the node is not valid.
*
* @return ExprBuilder
*/
public function validate()
{
return $this->validation()->rule();
}
/**
* Sets whether the node can be overwritten.
*
* @param bool $deny Whether the overwriting is forbidden or not
*
* @return $this
*/
public function cannotBeOverwritten($deny = true)
{
$this->merge()->denyOverwrite($deny);
return $this;
}
/**
* Gets the builder for validation rules.
*
* @return ValidationBuilder
*/
protected function validation()
{
if (null === $this->validation) {
$this->validation = new ValidationBuilder($this);
}
return $this->validation;
}
/**
* Gets the builder for merging rules.
*
* @return MergeBuilder
*/
protected function merge()
{
if (null === $this->merge) {
$this->merge = new MergeBuilder($this);
}
return $this->merge;
}
/**
* Gets the builder for normalization rules.
*
* @return NormalizationBuilder
*/
protected function normalization()
{
if (null === $this->normalization) {
$this->normalization = new NormalizationBuilder($this);
}
return $this->normalization;
}
/**
* Instantiate and configure the node according to this definition.
*
* @return NodeInterface $node The node instance
*
* @throws InvalidDefinitionException When the definition is invalid
*/
abstract protected function createNode();
/**
* Set PathSeparator to use.
*
* @param string $separator
*
* @return $this
*/
public function setPathSeparator(string $separator)
{
if ($this instanceof ParentNodeDefinitionInterface) {
if (method_exists($this, 'getChildNodeDefinitions')) {
foreach ($this->getChildNodeDefinitions() as $child) {
$child->setPathSeparator($separator);
}
} else {
@trigger_error('Passing a ParentNodeDefinitionInterface without getChildNodeDefinitions() is deprecated since Symfony 4.1.', E_USER_DEPRECATED);
}
}
$this->pathSeparator = $separator;
return $this;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
/**
* An interface that must be implemented by all node parents.
*
* @author Victor Berchet <[email protected]>
*/
interface NodeParentInterface
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
/**
* This class builds normalization conditions.
*
* @author Johannes M. Schmitt <[email protected]>
*/
class NormalizationBuilder
{
protected $node;
public $before = array();
public $remappings = array();
public function __construct(NodeDefinition $node)
{
$this->node = $node;
}
/**
* Registers a key to remap to its plural form.
*
* @param string $key The key to remap
* @param string $plural The plural of the key in case of irregular plural
*
* @return $this
*/
public function remap($key, $plural = null)
{
$this->remappings[] = array($key, null === $plural ? $key.'s' : $plural);
return $this;
}
/**
* Registers a closure to run before the normalization or an expression builder to build it if null is provided.
*
* @return ExprBuilder|$this
*/
public function before(\Closure $closure = null)
{
if (null !== $closure) {
$this->before[] = $closure;
return $this;
}
return $this->before[] = new ExprBuilder($this->node);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
use Symfony\Component\Config\Definition\Exception\InvalidDefinitionException;
/**
* Abstract class that contains common code of integer and float node definitions.
*
* @author David Jeanmonod <[email protected]>
*/
abstract class NumericNodeDefinition extends ScalarNodeDefinition
{
protected $min;
protected $max;
/**
* Ensures that the value is smaller than the given reference.
*
* @param mixed $max
*
* @return $this
*
* @throws \InvalidArgumentException when the constraint is inconsistent
*/
public function max($max)
{
if (isset($this->min) && $this->min > $max) {
throw new \InvalidArgumentException(sprintf('You cannot define a max(%s) as you already have a min(%s)', $max, $this->min));
}
$this->max = $max;
return $this;
}
/**
* Ensures that the value is bigger than the given reference.
*
* @param mixed $min
*
* @return $this
*
* @throws \InvalidArgumentException when the constraint is inconsistent
*/
public function min($min)
{
if (isset($this->max) && $this->max < $min) {
throw new \InvalidArgumentException(sprintf('You cannot define a min(%s) as you already have a max(%s)', $min, $this->max));
}
$this->min = $min;
return $this;
}
/**
* {@inheritdoc}
*
* @throws InvalidDefinitionException
*/
public function cannotBeEmpty()
{
throw new InvalidDefinitionException('->cannotBeEmpty() is not applicable to NumericNodeDefinition.');
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
/**
* An interface that must be implemented by nodes which can have children.
*
* @author Victor Berchet <[email protected]>
*
* @method NodeDefinition[] getChildNodeDefinitions() should be implemented since 4.1
*/
interface ParentNodeDefinitionInterface extends BuilderAwareInterface
{
/**
* Returns a builder to add children nodes.
*
* @return NodeBuilder
*/
public function children();
/**
* Appends a node definition.
*
* Usage:
*
* $node = $parentNode
* ->children()
* ->scalarNode('foo')->end()
* ->scalarNode('baz')->end()
* ->append($this->getBarNodeDefinition())
* ->end()
* ;
*
* @return $this
*/
public function append(NodeDefinition $node);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
use Symfony\Component\Config\Definition\ScalarNode;
/**
* This class provides a fluent interface for defining a node.
*
* @author Johannes M. Schmitt <[email protected]>
*/
class ScalarNodeDefinition extends VariableNodeDefinition
{
/**
* Instantiate a Node.
*
* @return ScalarNode The node
*/
protected function instantiateNode()
{
return new ScalarNode($this->name, $this->parent, $this->pathSeparator);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
use Symfony\Component\Config\Definition\Exception\TreeWithoutRootNodeException;
use Symfony\Component\Config\Definition\NodeInterface;
/**
* This is the entry class for building a config tree.
*
* @author Johannes M. Schmitt <[email protected]>
*/
class TreeBuilder implements NodeParentInterface
{
protected $tree;
protected $root;
/**
* Creates the root node.
*
* @param string $name The name of the root node
* @param string $type The type of the root node
* @param NodeBuilder $builder A custom node builder instance
*
* @return ArrayNodeDefinition|NodeDefinition The root node (as an ArrayNodeDefinition when the type is 'array')
*
* @throws \RuntimeException When the node type is not supported
*/
public function root($name, $type = 'array', NodeBuilder $builder = null)
{
$builder = $builder ?: new NodeBuilder();
return $this->root = $builder->node($name, $type)->setParent($this);
}
/**
* Builds the tree.
*
* @return NodeInterface
*
* @throws \RuntimeException
*/
public function buildTree()
{
$this->assertTreeHasRootNode();
if (null !== $this->tree) {
return $this->tree;
}
return $this->tree = $this->root->getNode(true);
}
public function setPathSeparator(string $separator)
{
$this->assertTreeHasRootNode();
// unset last built as changing path separator changes all nodes
$this->tree = null;
$this->root->setPathSeparator($separator);
}
/**
* @throws \RuntimeException if root node is not defined
*/
private function assertTreeHasRootNode()
{
if (null === $this->root) {
throw new TreeWithoutRootNodeException('The configuration tree has no root node.');
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
/**
* This class builds validation conditions.
*
* @author Christophe Coevoet <[email protected]>
*/
class ValidationBuilder
{
protected $node;
public $rules = array();
public function __construct(NodeDefinition $node)
{
$this->node = $node;
}
/**
* Registers a closure to run as normalization or an expression builder to build it if null is provided.
*
* @return ExprBuilder|$this
*/
public function rule(\Closure $closure = null)
{
if (null !== $closure) {
$this->rules[] = $closure;
return $this;
}
return $this->rules[] = new ExprBuilder($this->node);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Builder;
use Symfony\Component\Config\Definition\VariableNode;
/**
* This class provides a fluent interface for defining a node.
*
* @author Johannes M. Schmitt <[email protected]>
*/
class VariableNodeDefinition extends NodeDefinition
{
/**
* Instantiate a Node.
*
* @return VariableNode The node
*/
protected function instantiateNode()
{
return new VariableNode($this->name, $this->parent, $this->pathSeparator);
}
/**
* {@inheritdoc}
*/
protected function createNode()
{
$node = $this->instantiateNode();
if (null !== $this->normalization) {
$node->setNormalizationClosures($this->normalization->before);
}
if (null !== $this->merge) {
$node->setAllowOverwrite($this->merge->allowOverwrite);
}
if (true === $this->default) {
$node->setDefaultValue($this->defaultValue);
}
$node->setAllowEmptyValue($this->allowEmptyValue);
$node->addEquivalentValue(null, $this->nullEquivalent);
$node->addEquivalentValue(true, $this->trueEquivalent);
$node->addEquivalentValue(false, $this->falseEquivalent);
$node->setRequired($this->required);
$node->setDeprecated($this->deprecationMessage);
if (null !== $this->validation) {
$node->setFinalValidationClosures($this->validation->rules);
}
return $node;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
/**
* Configuration interface.
*
* @author Victor Berchet <[email protected]>
*/
interface ConfigurationInterface
{
/**
* Generates the configuration tree builder.
*
* @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder
*/
public function getConfigTreeBuilder();
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Dumper;
use Symfony\Component\Config\Definition\ArrayNode;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\Definition\EnumNode;
use Symfony\Component\Config\Definition\NodeInterface;
use Symfony\Component\Config\Definition\PrototypedArrayNode;
/**
* Dumps a XML reference configuration for the given configuration/node instance.
*
* @author Wouter J <[email protected]>
*/
class XmlReferenceDumper
{
private $reference;
public function dump(ConfigurationInterface $configuration, $namespace = null)
{
return $this->dumpNode($configuration->getConfigTreeBuilder()->buildTree(), $namespace);
}
public function dumpNode(NodeInterface $node, $namespace = null)
{
$this->reference = '';
$this->writeNode($node, 0, true, $namespace);
$ref = $this->reference;
$this->reference = null;
return $ref;
}
private function writeNode(NodeInterface $node, int $depth = 0, bool $root = false, string $namespace = null)
{
$rootName = ($root ? 'config' : $node->getName());
$rootNamespace = ($namespace ?: ($root ? 'http://example.org/schema/dic/'.$node->getName() : null));
// xml remapping
if ($node->getParent()) {
$remapping = array_filter($node->getParent()->getXmlRemappings(), function ($mapping) use ($rootName) {
return $rootName === $mapping[1];
});
if (\count($remapping)) {
list($singular) = current($remapping);
$rootName = $singular;
}
}
$rootName = str_replace('_', '-', $rootName);
$rootAttributes = array();
$rootAttributeComments = array();
$rootChildren = array();
$rootComments = array();
if ($node instanceof ArrayNode) {
$children = $node->getChildren();
// comments about the root node
if ($rootInfo = $node->getInfo()) {
$rootComments[] = $rootInfo;
}
if ($rootNamespace) {
$rootComments[] = 'Namespace: '.$rootNamespace;
}
// render prototyped nodes
if ($node instanceof PrototypedArrayNode) {
$prototype = $node->getPrototype();
$info = 'prototype';
if (null !== $prototype->getInfo()) {
$info .= ': '.$prototype->getInfo();
}
array_unshift($rootComments, $info);
if ($key = $node->getKeyAttribute()) {
$rootAttributes[$key] = str_replace('-', ' ', $rootName).' '.$key;
}
if ($prototype instanceof PrototypedArrayNode) {
$prototype->setName($key);
$children = array($key => $prototype);
} elseif ($prototype instanceof ArrayNode) {
$children = $prototype->getChildren();
} else {
if ($prototype->hasDefaultValue()) {
$prototypeValue = $prototype->getDefaultValue();
} else {
switch (\get_class($prototype)) {
case 'Symfony\Component\Config\Definition\ScalarNode':
$prototypeValue = 'scalar value';
break;
case 'Symfony\Component\Config\Definition\FloatNode':
case 'Symfony\Component\Config\Definition\IntegerNode':
$prototypeValue = 'numeric value';
break;
case 'Symfony\Component\Config\Definition\BooleanNode':
$prototypeValue = 'true|false';
break;
case 'Symfony\Component\Config\Definition\EnumNode':
$prototypeValue = implode('|', array_map('json_encode', $prototype->getValues()));
break;
default:
$prototypeValue = 'value';
}
}
}
}
// get attributes and elements
foreach ($children as $child) {
if (!$child instanceof ArrayNode) {
// get attributes
// metadata
$name = str_replace('_', '-', $child->getName());
$value = '%%%%not_defined%%%%'; // use a string which isn't used in the normal world
// comments
$comments = array();
if ($info = $child->getInfo()) {
$comments[] = $info;
}
if ($example = $child->getExample()) {
$comments[] = 'Example: '.$example;
}
if ($child->isRequired()) {
$comments[] = 'Required';
}
if ($child->isDeprecated()) {
$comments[] = sprintf('Deprecated (%s)', $child->getDeprecationMessage($child->getName(), $node->getPath()));
}
if ($child instanceof EnumNode) {
$comments[] = 'One of '.implode('; ', array_map('json_encode', $child->getValues()));
}
if (\count($comments)) {
$rootAttributeComments[$name] = implode(";\n", $comments);
}
// default values
if ($child->hasDefaultValue()) {
$value = $child->getDefaultValue();
}
// append attribute
$rootAttributes[$name] = $value;
} else {
// get elements
$rootChildren[] = $child;
}
}
}
// render comments
// root node comment
if (\count($rootComments)) {
foreach ($rootComments as $comment) {
$this->writeLine('<!-- '.$comment.' -->', $depth);
}
}
// attribute comments
if (\count($rootAttributeComments)) {
foreach ($rootAttributeComments as $attrName => $comment) {
$commentDepth = $depth + 4 + \strlen($attrName) + 2;
$commentLines = explode("\n", $comment);
$multiline = (\count($commentLines) > 1);
$comment = implode(PHP_EOL.str_repeat(' ', $commentDepth), $commentLines);
if ($multiline) {
$this->writeLine('<!--', $depth);
$this->writeLine($attrName.': '.$comment, $depth + 4);
$this->writeLine('-->', $depth);
} else {
$this->writeLine('<!-- '.$attrName.': '.$comment.' -->', $depth);
}
}
}
// render start tag + attributes
$rootIsVariablePrototype = isset($prototypeValue);
$rootIsEmptyTag = (0 === \count($rootChildren) && !$rootIsVariablePrototype);
$rootOpenTag = '<'.$rootName;
if (1 >= ($attributesCount = \count($rootAttributes))) {
if (1 === $attributesCount) {
$rootOpenTag .= sprintf(' %s="%s"', current(array_keys($rootAttributes)), $this->writeValue(current($rootAttributes)));
}
$rootOpenTag .= $rootIsEmptyTag ? ' />' : '>';
if ($rootIsVariablePrototype) {
$rootOpenTag .= $prototypeValue.'</'.$rootName.'>';
}
$this->writeLine($rootOpenTag, $depth);
} else {
$this->writeLine($rootOpenTag, $depth);
$i = 1;
foreach ($rootAttributes as $attrName => $attrValue) {
$attr = sprintf('%s="%s"', $attrName, $this->writeValue($attrValue));
$this->writeLine($attr, $depth + 4);
if ($attributesCount === $i++) {
$this->writeLine($rootIsEmptyTag ? '/>' : '>', $depth);
if ($rootIsVariablePrototype) {
$rootOpenTag .= $prototypeValue.'</'.$rootName.'>';
}
}
}
}
// render children tags
foreach ($rootChildren as $child) {
$this->writeLine('');
$this->writeNode($child, $depth + 4);
}
// render end tag
if (!$rootIsEmptyTag && !$rootIsVariablePrototype) {
$this->writeLine('');
$rootEndTag = '</'.$rootName.'>';
$this->writeLine($rootEndTag, $depth);
}
}
/**
* Outputs a single config reference line.
*/
private function writeLine(string $text, int $indent = 0)
{
$indent = \strlen($text) + $indent;
$format = '%'.$indent.'s';
$this->reference .= sprintf($format, $text).PHP_EOL;
}
/**
* Renders the string conversion of the value.
*
* @param mixed $value
*/
private function writeValue($value): string
{
if ('%%%%not_defined%%%%' === $value) {
return '';
}
if (\is_string($value) || is_numeric($value)) {
return $value;
}
if (false === $value) {
return 'false';
}
if (true === $value) {
return 'true';
}
if (null === $value) {
return 'null';
}
if (empty($value)) {
return '';
}
if (\is_array($value)) {
return implode(',', $value);
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Dumper;
use Symfony\Component\Config\Definition\ArrayNode;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\Definition\EnumNode;
use Symfony\Component\Config\Definition\NodeInterface;
use Symfony\Component\Config\Definition\PrototypedArrayNode;
use Symfony\Component\Config\Definition\ScalarNode;
use Symfony\Component\Yaml\Inline;
/**
* Dumps a Yaml reference configuration for the given configuration/node instance.
*
* @author Kevin Bond <[email protected]>
*/
class YamlReferenceDumper
{
private $reference;
public function dump(ConfigurationInterface $configuration)
{
return $this->dumpNode($configuration->getConfigTreeBuilder()->buildTree());
}
public function dumpAtPath(ConfigurationInterface $configuration, $path)
{
$rootNode = $node = $configuration->getConfigTreeBuilder()->buildTree();
foreach (explode('.', $path) as $step) {
if (!$node instanceof ArrayNode) {
throw new \UnexpectedValueException(sprintf('Unable to find node at path "%s.%s"', $rootNode->getName(), $path));
}
/** @var NodeInterface[] $children */
$children = $node instanceof PrototypedArrayNode ? $this->getPrototypeChildren($node) : $node->getChildren();
foreach ($children as $child) {
if ($child->getName() === $step) {
$node = $child;
continue 2;
}
}
throw new \UnexpectedValueException(sprintf('Unable to find node at path "%s.%s"', $rootNode->getName(), $path));
}
return $this->dumpNode($node);
}
public function dumpNode(NodeInterface $node)
{
$this->reference = '';
$this->writeNode($node);
$ref = $this->reference;
$this->reference = null;
return $ref;
}
private function writeNode(NodeInterface $node, NodeInterface $parentNode = null, int $depth = 0, bool $prototypedArray = false)
{
$comments = array();
$default = '';
$defaultArray = null;
$children = null;
$example = $node->getExample();
// defaults
if ($node instanceof ArrayNode) {
$children = $node->getChildren();
if ($node instanceof PrototypedArrayNode) {
$children = $this->getPrototypeChildren($node);
}
if (!$children) {
if ($node->hasDefaultValue() && \count($defaultArray = $node->getDefaultValue())) {
$default = '';
} elseif (!\is_array($example)) {
$default = '[]';
}
}
} elseif ($node instanceof EnumNode) {
$comments[] = 'One of '.implode('; ', array_map('json_encode', $node->getValues()));
$default = $node->hasDefaultValue() ? Inline::dump($node->getDefaultValue()) : '~';
} else {
$default = '~';
if ($node->hasDefaultValue()) {
$default = $node->getDefaultValue();
if (\is_array($default)) {
if (\count($defaultArray = $node->getDefaultValue())) {
$default = '';
} elseif (!\is_array($example)) {
$default = '[]';
}
} else {
$default = Inline::dump($default);
}
}
}
// required?
if ($node->isRequired()) {
$comments[] = 'Required';
}
// deprecated?
if ($node->isDeprecated()) {
$comments[] = sprintf('Deprecated (%s)', $node->getDeprecationMessage($node->getName(), $parentNode ? $parentNode->getPath() : $node->getPath()));
}
// example
if ($example && !\is_array($example)) {
$comments[] = 'Example: '.$example;
}
$default = '' != (string) $default ? ' '.$default : '';
$comments = \count($comments) ? '# '.implode(', ', $comments) : '';
$key = $prototypedArray ? '-' : $node->getName().':';
$text = rtrim(sprintf('%-21s%s %s', $key, $default, $comments), ' ');
if ($info = $node->getInfo()) {
$this->writeLine('');
// indenting multi-line info
$info = str_replace("\n", sprintf("\n%".($depth * 4).'s# ', ' '), $info);
$this->writeLine('# '.$info, $depth * 4);
}
$this->writeLine($text, $depth * 4);
// output defaults
if ($defaultArray) {
$this->writeLine('');
$message = \count($defaultArray) > 1 ? 'Defaults' : 'Default';
$this->writeLine('# '.$message.':', $depth * 4 + 4);
$this->writeArray($defaultArray, $depth + 1);
}
if (\is_array($example)) {
$this->writeLine('');
$message = \count($example) > 1 ? 'Examples' : 'Example';
$this->writeLine('# '.$message.':', $depth * 4 + 4);
$this->writeArray($example, $depth + 1);
}
if ($children) {
foreach ($children as $childNode) {
$this->writeNode($childNode, $node, $depth + 1, $node instanceof PrototypedArrayNode && !$node->getKeyAttribute());
}
}
}
/**
* Outputs a single config reference line.
*/
private function writeLine(string $text, int $indent = 0)
{
$indent = \strlen($text) + $indent;
$format = '%'.$indent.'s';
$this->reference .= sprintf($format, $text)."\n";
}
private function writeArray(array $array, $depth)
{
$isIndexed = array_values($array) === $array;
foreach ($array as $key => $value) {
if (\is_array($value)) {
$val = '';
} else {
$val = $value;
}
if ($isIndexed) {
$this->writeLine('- '.$val, $depth * 4);
} else {
$this->writeLine(sprintf('%-20s %s', $key.':', $val), $depth * 4);
}
if (\is_array($value)) {
$this->writeArray($value, $depth + 1);
}
}
}
private function getPrototypeChildren(PrototypedArrayNode $node): array
{
$prototype = $node->getPrototype();
$key = $node->getKeyAttribute();
// Do not expand prototype if it isn't an array node nor uses attribute as key
if (!$key && !$prototype instanceof ArrayNode) {
return $node->getChildren();
}
if ($prototype instanceof ArrayNode) {
$keyNode = new ArrayNode($key, $node);
$children = $prototype->getChildren();
if ($prototype instanceof PrototypedArrayNode && $prototype->getKeyAttribute()) {
$children = $this->getPrototypeChildren($prototype);
}
// add children
foreach ($children as $childNode) {
$keyNode->addChild($childNode);
}
} else {
$keyNode = new ScalarNode($key, $node);
}
$info = 'Prototype';
if (null !== $prototype->getInfo()) {
$info .= ': '.$prototype->getInfo();
}
$keyNode->setInfo($info);
return array($key => $keyNode);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
/**
* Node which only allows a finite set of values.
*
* @author Johannes M. Schmitt <[email protected]>
*/
class EnumNode extends ScalarNode
{
private $values;
public function __construct(?string $name, NodeInterface $parent = null, array $values = array(), string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR)
{
$values = array_unique($values);
if (empty($values)) {
throw new \InvalidArgumentException('$values must contain at least one element.');
}
parent::__construct($name, $parent, $pathSeparator);
$this->values = $values;
}
public function getValues()
{
return $this->values;
}
protected function finalizeValue($value)
{
$value = parent::finalizeValue($value);
if (!\in_array($value, $this->values, true)) {
$ex = new InvalidConfigurationException(sprintf('The value %s is not allowed for path "%s". Permissible values: %s', json_encode($value), $this->getPath(), implode(', ', array_map('json_encode', $this->values))));
$ex->setPath($this->getPath());
throw $ex;
}
return $value;
}
/**
* {@inheritdoc}
*/
protected function allowPlaceholders(): bool
{
return false;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Exception;
/**
* This exception is thrown whenever the key of an array is not unique. This can
* only be the case if the configuration is coming from an XML file.
*
* @author Johannes M. Schmitt <[email protected]>
*/
class DuplicateKeyException extends InvalidConfigurationException
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Exception;
/**
* Base exception for all configuration exceptions.
*
* @author Johannes M. Schmitt <[email protected]>
*/
class Exception extends \RuntimeException
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Exception;
/**
* This exception is thrown when a configuration path is overwritten from a
* subsequent configuration file, but the entry node specifically forbids this.
*
* @author Johannes M. Schmitt <[email protected]>
*/
class ForbiddenOverwriteException extends InvalidConfigurationException
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Exception;
/**
* A very general exception which can be thrown whenever non of the more specific
* exceptions is suitable.
*
* @author Johannes M. Schmitt <[email protected]>
*/
class InvalidConfigurationException extends Exception
{
private $path;
private $containsHints = false;
public function setPath($path)
{
$this->path = $path;
}
public function getPath()
{
return $this->path;
}
/**
* Adds extra information that is suffixed to the original exception message.
*
* @param string $hint
*/
public function addHint($hint)
{
if (!$this->containsHints) {
$this->message .= "\nHint: ".$hint;
$this->containsHints = true;
} else {
$this->message .= ', '.$hint;
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Exception;
/**
* Thrown when an error is detected in a node Definition.
*
* @author Victor Berchet <[email protected]>
*/
class InvalidDefinitionException extends Exception
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Exception;
/**
* This exception is thrown if an invalid type is encountered.
*
* @author Johannes M. Schmitt <[email protected]>
*/
class InvalidTypeException extends InvalidConfigurationException
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Exception;
/**
* @author Roland Franssen <[email protected]>
*/
class TreeWithoutRootNodeException extends \RuntimeException
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition\Exception;
/**
* This exception is usually not encountered by the end-user, but only used
* internally to signal the parent scope to unset a key.
*
* @author Johannes M. Schmitt <[email protected]>
*/
class UnsetKeyException extends Exception
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
/**
* This node represents a float value in the config tree.
*
* @author Jeanmonod David <[email protected]>
*/
class FloatNode extends NumericNode
{
/**
* {@inheritdoc}
*/
protected function validateType($value)
{
// Integers are also accepted, we just cast them
if (\is_int($value)) {
$value = (float) $value;
}
if (!\is_float($value)) {
$ex = new InvalidTypeException(sprintf('Invalid type for path "%s". Expected float, but got %s.', $this->getPath(), \gettype($value)));
if ($hint = $this->getInfo()) {
$ex->addHint($hint);
}
$ex->setPath($this->getPath());
throw $ex;
}
}
/**
* {@inheritdoc}
*/
protected function getValidPlaceholderTypes(): array
{
return array('float');
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
/**
* This node represents an integer value in the config tree.
*
* @author Jeanmonod David <[email protected]>
*/
class IntegerNode extends NumericNode
{
/**
* {@inheritdoc}
*/
protected function validateType($value)
{
if (!\is_int($value)) {
$ex = new InvalidTypeException(sprintf('Invalid type for path "%s". Expected int, but got %s.', $this->getPath(), \gettype($value)));
if ($hint = $this->getInfo()) {
$ex->addHint($hint);
}
$ex->setPath($this->getPath());
throw $ex;
}
}
/**
* {@inheritdoc}
*/
protected function getValidPlaceholderTypes(): array
{
return array('int');
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
use Symfony\Component\Config\Definition\Exception\ForbiddenOverwriteException;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
/**
* Common Interface among all nodes.
*
* In most cases, it is better to inherit from BaseNode instead of implementing
* this interface yourself.
*
* @author Johannes M. Schmitt <[email protected]>
*/
interface NodeInterface
{
/**
* Returns the name of the node.
*
* @return string The name of the node
*/
public function getName();
/**
* Returns the path of the node.
*
* @return string The node path
*/
public function getPath();
/**
* Returns true when the node is required.
*
* @return bool If the node is required
*/
public function isRequired();
/**
* Returns true when the node has a default value.
*
* @return bool If the node has a default value
*/
public function hasDefaultValue();
/**
* Returns the default value of the node.
*
* @return mixed The default value
*
* @throws \RuntimeException if the node has no default value
*/
public function getDefaultValue();
/**
* Normalizes a value.
*
* @param mixed $value The value to normalize
*
* @return mixed The normalized value
*
* @throws InvalidTypeException if the value type is invalid
*/
public function normalize($value);
/**
* Merges two values together.
*
* @param mixed $leftSide
* @param mixed $rightSide
*
* @return mixed The merged value
*
* @throws ForbiddenOverwriteException if the configuration path cannot be overwritten
* @throws InvalidTypeException if the value type is invalid
*/
public function merge($leftSide, $rightSide);
/**
* Finalizes a value.
*
* @param mixed $value The value to finalize
*
* @return mixed The finalized value
*
* @throws InvalidTypeException if the value type is invalid
* @throws InvalidConfigurationException if the value is invalid configuration
*/
public function finalize($value);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
/**
* This node represents a numeric value in the config tree.
*
* @author David Jeanmonod <[email protected]>
*/
class NumericNode extends ScalarNode
{
protected $min;
protected $max;
public function __construct(?string $name, NodeInterface $parent = null, $min = null, $max = null, string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR)
{
parent::__construct($name, $parent, $pathSeparator);
$this->min = $min;
$this->max = $max;
}
/**
* {@inheritdoc}
*/
protected function finalizeValue($value)
{
$value = parent::finalizeValue($value);
$errorMsg = null;
if (isset($this->min) && $value < $this->min) {
$errorMsg = sprintf('The value %s is too small for path "%s". Should be greater than or equal to %s', $value, $this->getPath(), $this->min);
}
if (isset($this->max) && $value > $this->max) {
$errorMsg = sprintf('The value %s is too big for path "%s". Should be less than or equal to %s', $value, $this->getPath(), $this->max);
}
if (isset($errorMsg)) {
$ex = new InvalidConfigurationException($errorMsg);
$ex->setPath($this->getPath());
throw $ex;
}
return $value;
}
/**
* {@inheritdoc}
*/
protected function isValueEmpty($value)
{
// a numeric value cannot be empty
return false;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
/**
* This class is the entry point for config normalization/merging/finalization.
*
* @author Johannes M. Schmitt <[email protected]>
*
* @final since version 4.1
*/
class Processor
{
/**
* Processes an array of configurations.
*
* @param NodeInterface $configTree The node tree describing the configuration
* @param array $configs An array of configuration items to process
*
* @return array The processed configuration
*/
public function process(NodeInterface $configTree, array $configs)
{
$currentConfig = array();
foreach ($configs as $config) {
$config = $configTree->normalize($config);
$currentConfig = $configTree->merge($currentConfig, $config);
}
return $configTree->finalize($currentConfig);
}
/**
* Processes an array of configurations.
*
* @param ConfigurationInterface $configuration The configuration class
* @param array $configs An array of configuration items to process
*
* @return array The processed configuration
*/
public function processConfiguration(ConfigurationInterface $configuration, array $configs)
{
return $this->process($configuration->getConfigTreeBuilder()->buildTree(), $configs);
}
/**
* Normalizes a configuration entry.
*
* This method returns a normalize configuration array for a given key
* to remove the differences due to the original format (YAML and XML mainly).
*
* Here is an example.
*
* The configuration in XML:
*
* <twig:extension>twig.extension.foo</twig:extension>
* <twig:extension>twig.extension.bar</twig:extension>
*
* And the same configuration in YAML:
*
* extensions: ['twig.extension.foo', 'twig.extension.bar']
*
* @param array $config A config array
* @param string $key The key to normalize
* @param string $plural The plural form of the key if it is irregular
*
* @return array
*/
public static function normalizeConfig($config, $key, $plural = null)
{
if (null === $plural) {
$plural = $key.'s';
}
if (isset($config[$plural])) {
return $config[$plural];
}
if (isset($config[$key])) {
if (\is_string($config[$key]) || !\is_int(key($config[$key]))) {
// only one
return array($config[$key]);
}
return $config[$key];
}
return array();
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
use Symfony\Component\Config\Definition\Exception\DuplicateKeyException;
use Symfony\Component\Config\Definition\Exception\Exception;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\Config\Definition\Exception\UnsetKeyException;
/**
* Represents a prototyped Array node in the config tree.
*
* @author Johannes M. Schmitt <[email protected]>
*/
class PrototypedArrayNode extends ArrayNode
{
protected $prototype;
protected $keyAttribute;
protected $removeKeyAttribute = false;
protected $minNumberOfElements = 0;
protected $defaultValue = array();
protected $defaultChildren;
/**
* @var NodeInterface[] An array of the prototypes of the simplified value children
*/
private $valuePrototypes = array();
/**
* Sets the minimum number of elements that a prototype based node must
* contain. By default this is zero, meaning no elements.
*
* @param int $number
*/
public function setMinNumberOfElements($number)
{
$this->minNumberOfElements = $number;
}
/**
* Sets the attribute which value is to be used as key.
*
* This is useful when you have an indexed array that should be an
* associative array. You can select an item from within the array
* to be the key of the particular item. For example, if "id" is the
* "key", then:
*
* array(
* array('id' => 'my_name', 'foo' => 'bar'),
* );
*
* becomes
*
* array(
* 'my_name' => array('foo' => 'bar'),
* );
*
* If you'd like "'id' => 'my_name'" to still be present in the resulting
* array, then you can set the second argument of this method to false.
*
* @param string $attribute The name of the attribute which value is to be used as a key
* @param bool $remove Whether or not to remove the key
*/
public function setKeyAttribute($attribute, $remove = true)
{
$this->keyAttribute = $attribute;
$this->removeKeyAttribute = $remove;
}
/**
* Retrieves the name of the attribute which value should be used as key.
*
* @return string The name of the attribute
*/
public function getKeyAttribute()
{
return $this->keyAttribute;
}
/**
* Sets the default value of this node.
*
* @param string $value
*
* @throws \InvalidArgumentException if the default value is not an array
*/
public function setDefaultValue($value)
{
if (!\is_array($value)) {
throw new \InvalidArgumentException($this->getPath().': the default value of an array node has to be an array.');
}
$this->defaultValue = $value;
}
/**
* {@inheritdoc}
*/
public function hasDefaultValue()
{
return true;
}
/**
* Adds default children when none are set.
*
* @param int|string|array|null $children The number of children|The child name|The children names to be added
*/
public function setAddChildrenIfNoneSet($children = array('defaults'))
{
if (null === $children) {
$this->defaultChildren = array('defaults');
} else {
$this->defaultChildren = \is_int($children) && $children > 0 ? range(1, $children) : (array) $children;
}
}
/**
* {@inheritdoc}
*
* The default value could be either explicited or derived from the prototype
* default value.
*/
public function getDefaultValue()
{
if (null !== $this->defaultChildren) {
$default = $this->prototype->hasDefaultValue() ? $this->prototype->getDefaultValue() : array();
$defaults = array();
foreach (array_values($this->defaultChildren) as $i => $name) {
$defaults[null === $this->keyAttribute ? $i : $name] = $default;
}
return $defaults;
}
return $this->defaultValue;
}
/**
* Sets the node prototype.
*/
public function setPrototype(PrototypeNodeInterface $node)
{
$this->prototype = $node;
}
/**
* Retrieves the prototype.
*
* @return PrototypeNodeInterface The prototype
*/
public function getPrototype()
{
return $this->prototype;
}
/**
* Disable adding concrete children for prototyped nodes.
*
* @throws Exception
*/
public function addChild(NodeInterface $node)
{
throw new Exception('A prototyped array node can not have concrete children.');
}
/**
* Finalizes the value of this node.
*
* @param mixed $value
*
* @return mixed The finalized value
*
* @throws UnsetKeyException
* @throws InvalidConfigurationException if the node doesn't have enough children
*/
protected function finalizeValue($value)
{
if (false === $value) {
throw new UnsetKeyException(sprintf('Unsetting key for path "%s", value: %s', $this->getPath(), json_encode($value)));
}
foreach ($value as $k => $v) {
$prototype = $this->getPrototypeForChild($k);
try {
$value[$k] = $prototype->finalize($v);
} catch (UnsetKeyException $e) {
unset($value[$k]);
}
}
if (\count($value) < $this->minNumberOfElements) {
$ex = new InvalidConfigurationException(sprintf('The path "%s" should have at least %d element(s) defined.', $this->getPath(), $this->minNumberOfElements));
$ex->setPath($this->getPath());
throw $ex;
}
return $value;
}
/**
* Normalizes the value.
*
* @param mixed $value The value to normalize
*
* @return mixed The normalized value
*
* @throws InvalidConfigurationException
* @throws DuplicateKeyException
*/
protected function normalizeValue($value)
{
if (false === $value) {
return $value;
}
$value = $this->remapXml($value);
$isAssoc = array_keys($value) !== range(0, \count($value) - 1);
$normalized = array();
foreach ($value as $k => $v) {
if (null !== $this->keyAttribute && \is_array($v)) {
if (!isset($v[$this->keyAttribute]) && \is_int($k) && !$isAssoc) {
$ex = new InvalidConfigurationException(sprintf('The attribute "%s" must be set for path "%s".', $this->keyAttribute, $this->getPath()));
$ex->setPath($this->getPath());
throw $ex;
} elseif (isset($v[$this->keyAttribute])) {
$k = $v[$this->keyAttribute];
// remove the key attribute when required
if ($this->removeKeyAttribute) {
unset($v[$this->keyAttribute]);
}
// if only "value" is left
if (array_keys($v) === array('value')) {
$v = $v['value'];
if ($this->prototype instanceof ArrayNode && ($children = $this->prototype->getChildren()) && array_key_exists('value', $children)) {
$valuePrototype = current($this->valuePrototypes) ?: clone $children['value'];
$valuePrototype->parent = $this;
$originalClosures = $this->prototype->normalizationClosures;
if (\is_array($originalClosures)) {
$valuePrototypeClosures = $valuePrototype->normalizationClosures;
$valuePrototype->normalizationClosures = \is_array($valuePrototypeClosures) ? array_merge($originalClosures, $valuePrototypeClosures) : $originalClosures;
}
$this->valuePrototypes[$k] = $valuePrototype;
}
}
}
if (array_key_exists($k, $normalized)) {
$ex = new DuplicateKeyException(sprintf('Duplicate key "%s" for path "%s".', $k, $this->getPath()));
$ex->setPath($this->getPath());
throw $ex;
}
}
$prototype = $this->getPrototypeForChild($k);
if (null !== $this->keyAttribute || $isAssoc) {
$normalized[$k] = $prototype->normalize($v);
} else {
$normalized[] = $prototype->normalize($v);
}
}
return $normalized;
}
/**
* Merges values together.
*
* @param mixed $leftSide The left side to merge
* @param mixed $rightSide The right side to merge
*
* @return mixed The merged values
*
* @throws InvalidConfigurationException
* @throws \RuntimeException
*/
protected function mergeValues($leftSide, $rightSide)
{
if (false === $rightSide) {
// if this is still false after the last config has been merged the
// finalization pass will take care of removing this key entirely
return false;
}
if (false === $leftSide || !$this->performDeepMerging) {
return $rightSide;
}
foreach ($rightSide as $k => $v) {
// prototype, and key is irrelevant, so simply append the element
if (null === $this->keyAttribute) {
$leftSide[] = $v;
continue;
}
// no conflict
if (!array_key_exists($k, $leftSide)) {
if (!$this->allowNewKeys) {
$ex = new InvalidConfigurationException(sprintf('You are not allowed to define new elements for path "%s". Please define all elements for this path in one config file.', $this->getPath()));
$ex->setPath($this->getPath());
throw $ex;
}
$leftSide[$k] = $v;
continue;
}
$prototype = $this->getPrototypeForChild($k);
$leftSide[$k] = $prototype->merge($leftSide[$k], $v);
}
return $leftSide;
}
/**
* Returns a prototype for the child node that is associated to $key in the value array.
* For general child nodes, this will be $this->prototype.
* But if $this->removeKeyAttribute is true and there are only two keys in the child node:
* one is same as this->keyAttribute and the other is 'value', then the prototype will be different.
*
* For example, assume $this->keyAttribute is 'name' and the value array is as follows:
*
* array(
* array(
* 'name' => 'name001',
* 'value' => 'value001'
* )
* )
*
* Now, the key is 0 and the child node is:
*
* array(
* 'name' => 'name001',
* 'value' => 'value001'
* )
*
* When normalizing the value array, the 'name' element will removed from the child node
* and its value becomes the new key of the child node:
*
* array(
* 'name001' => array('value' => 'value001')
* )
*
* Now only 'value' element is left in the child node which can be further simplified into a string:
*
* array('name001' => 'value001')
*
* Now, the key becomes 'name001' and the child node becomes 'value001' and
* the prototype of child node 'name001' should be a ScalarNode instead of an ArrayNode instance.
*
* @return mixed The prototype instance
*/
private function getPrototypeForChild(string $key)
{
$prototype = isset($this->valuePrototypes[$key]) ? $this->valuePrototypes[$key] : $this->prototype;
$prototype->setName($key);
return $prototype;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
/**
* This interface must be implemented by nodes which can be used as prototypes.
*
* @author Johannes M. Schmitt <[email protected]>
*/
interface PrototypeNodeInterface extends NodeInterface
{
/**
* Sets the name of the node.
*
* @param string $name The name of the node
*/
public function setName($name);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
/**
* This node represents a scalar value in the config tree.
*
* The following values are considered scalars:
* * booleans
* * strings
* * null
* * integers
* * floats
*
* @author Johannes M. Schmitt <[email protected]>
*/
class ScalarNode extends VariableNode
{
/**
* {@inheritdoc}
*/
protected function validateType($value)
{
if (!is_scalar($value) && null !== $value) {
$ex = new InvalidTypeException(sprintf('Invalid type for path "%s". Expected scalar, but got %s.', $this->getPath(), \gettype($value)));
if ($hint = $this->getInfo()) {
$ex->addHint($hint);
}
$ex->setPath($this->getPath());
throw $ex;
}
}
/**
* {@inheritdoc}
*/
protected function isValueEmpty($value)
{
if ($this->isHandlingPlaceholder()) {
return false;
}
return null === $value || '' === $value;
}
/**
* {@inheritdoc}
*/
protected function getValidPlaceholderTypes(): array
{
return array('bool', 'int', 'float', 'string');
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Definition;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
/**
* This node represents a value of variable type in the config tree.
*
* This node is intended for values of arbitrary type.
* Any PHP type is accepted as a value.
*
* @author Jeremy Mikola <[email protected]>
*/
class VariableNode extends BaseNode implements PrototypeNodeInterface
{
protected $defaultValueSet = false;
protected $defaultValue;
protected $allowEmptyValue = true;
public function setDefaultValue($value)
{
$this->defaultValueSet = true;
$this->defaultValue = $value;
}
/**
* {@inheritdoc}
*/
public function hasDefaultValue()
{
return $this->defaultValueSet;
}
/**
* {@inheritdoc}
*/
public function getDefaultValue()
{
$v = $this->defaultValue;
return $v instanceof \Closure ? $v() : $v;
}
/**
* Sets if this node is allowed to have an empty value.
*
* @param bool $boolean True if this entity will accept empty values
*/
public function setAllowEmptyValue($boolean)
{
$this->allowEmptyValue = (bool) $boolean;
}
/**
* {@inheritdoc}
*/
public function setName($name)
{
$this->name = $name;
}
/**
* {@inheritdoc}
*/
protected function validateType($value)
{
}
/**
* {@inheritdoc}
*/
protected function finalizeValue($value)
{
if (!$this->allowEmptyValue && $this->isValueEmpty($value)) {
$ex = new InvalidConfigurationException(sprintf('The path "%s" cannot contain an empty value, but got %s.', $this->getPath(), json_encode($value)));
if ($hint = $this->getInfo()) {
$ex->addHint($hint);
}
$ex->setPath($this->getPath());
throw $ex;
}
return $value;
}
/**
* {@inheritdoc}
*/
protected function normalizeValue($value)
{
return $value;
}
/**
* {@inheritdoc}
*/
protected function mergeValues($leftSide, $rightSide)
{
return $rightSide;
}
/**
* Evaluates if the given value is to be treated as empty.
*
* By default, PHP's empty() function is used to test for emptiness. This
* method may be overridden by subtypes to better match their understanding
* of empty data.
*
* @param mixed $value
*
* @return bool
*/
protected function isValueEmpty($value)
{
return empty($value);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Exception;
/**
* Exception class for when a circular reference is detected when importing resources.
*
* @author Fabien Potencier <[email protected]>
*/
class FileLoaderImportCircularReferenceException extends FileLoaderLoadException
{
public function __construct(array $resources, int $code = null, \Exception $previous = null)
{
$message = sprintf('Circular reference detected in "%s" ("%s" > "%s").', $this->varToString($resources[0]), implode('" > "', $resources), $resources[0]);
\Exception::__construct($message, $code, $previous);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Exception;
/**
* Exception class for when a resource cannot be loaded or imported.
*
* @author Ryan Weaver <[email protected]>
*/
class FileLoaderLoadException extends \Exception
{
/**
* @param string $resource The resource that could not be imported
* @param string $sourceResource The original resource importing the new resource
* @param int $code The error code
* @param \Exception $previous A previous exception
* @param string $type The type of resource
*/
public function __construct(string $resource, string $sourceResource = null, int $code = null, \Exception $previous = null, string $type = null)
{
$message = '';
if ($previous) {
// Include the previous exception, to help the user see what might be the underlying cause
// Trim the trailing period of the previous message. We only want 1 period remove so no rtrim...
if ('.' === substr($previous->getMessage(), -1)) {
$trimmedMessage = substr($previous->getMessage(), 0, -1);
$message .= sprintf('%s', $trimmedMessage).' in ';
} else {
$message .= sprintf('%s', $previous->getMessage()).' in ';
}
$message .= $resource.' ';
// show tweaked trace to complete the human readable sentence
if (null === $sourceResource) {
$message .= sprintf('(which is loaded in resource "%s")', $this->varToString($resource));
} else {
$message .= sprintf('(which is being imported from "%s")', $this->varToString($sourceResource));
}
$message .= '.';
// if there's no previous message, present it the default way
} elseif (null === $sourceResource) {
$message .= sprintf('Cannot load resource "%s".', $this->varToString($resource));
} else {
$message .= sprintf('Cannot import resource "%s" from "%s".', $this->varToString($resource), $this->varToString($sourceResource));
}
// Is the resource located inside a bundle?
if ('@' === $resource[0]) {
$parts = explode(\DIRECTORY_SEPARATOR, $resource);
$bundle = substr($parts[0], 1);
$message .= sprintf(' Make sure the "%s" bundle is correctly registered and loaded in the application kernel class.', $bundle);
$message .= sprintf(' If the bundle is registered, make sure the bundle path "%s" is not empty.', $resource);
} elseif (null !== $type) {
// maybe there is no loader for this specific type
if ('annotation' === $type) {
$message .= ' Make sure annotations are installed and enabled.';
} else {
$message .= sprintf(' Make sure there is a loader supporting the "%s" type.', $type);
}
}
parent::__construct($message, $code, $previous);
}
protected function varToString($var)
{
if (\is_object($var)) {
return sprintf('Object(%s)', \get_class($var));
}
if (\is_array($var)) {
$a = array();
foreach ($var as $k => $v) {
$a[] = sprintf('%s => %s', $k, $this->varToString($v));
}
return sprintf('Array(%s)', implode(', ', $a));
}
if (\is_resource($var)) {
return sprintf('Resource(%s)', get_resource_type($var));
}
if (null === $var) {
return 'null';
}
if (false === $var) {
return 'false';
}
if (true === $var) {
return 'true';
}
return (string) $var;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Exception;
/**
* File locator exception if a file does not exist.
*
* @author Leo Feyer <https://github.com/leofeyer>
*/
class FileLocatorFileNotFoundException extends \InvalidArgumentException
{
private $paths;
public function __construct(string $message = '', int $code = 0, \Exception $previous = null, array $paths = array())
{
parent::__construct($message, $code, $previous);
$this->paths = $paths;
}
public function getPaths()
{
return $this->paths;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config;
use Symfony\Component\Config\Exception\FileLocatorFileNotFoundException;
/**
* FileLocator uses an array of pre-defined paths to find files.
*
* @author Fabien Potencier <[email protected]>
*/
class FileLocator implements FileLocatorInterface
{
protected $paths;
/**
* @param string|string[] $paths A path or an array of paths where to look for resources
*/
public function __construct($paths = array())
{
$this->paths = (array) $paths;
}
/**
* {@inheritdoc}
*/
public function locate($name, $currentPath = null, $first = true)
{
if ('' == $name) {
throw new \InvalidArgumentException('An empty file name is not valid to be located.');
}
if ($this->isAbsolutePath($name)) {
if (!file_exists($name)) {
throw new FileLocatorFileNotFoundException(sprintf('The file "%s" does not exist.', $name), 0, null, array($name));
}
return $name;
}
$paths = $this->paths;
if (null !== $currentPath) {
array_unshift($paths, $currentPath);
}
$paths = array_unique($paths);
$filepaths = $notfound = array();
foreach ($paths as $path) {
if (@file_exists($file = $path.\DIRECTORY_SEPARATOR.$name)) {
if (true === $first) {
return $file;
}
$filepaths[] = $file;
} else {
$notfound[] = $file;
}
}
if (!$filepaths) {
throw new FileLocatorFileNotFoundException(sprintf('The file "%s" does not exist (in: %s).', $name, implode(', ', $paths)), 0, null, $notfound);
}
return $filepaths;
}
/**
* Returns whether the file path is an absolute path.
*
* @param string $file A file path
*
* @return bool
*/
private function isAbsolutePath($file)
{
if ('/' === $file[0] || '\\' === $file[0]
|| (\strlen($file) > 3 && ctype_alpha($file[0])
&& ':' === $file[1]
&& ('\\' === $file[2] || '/' === $file[2])
)
|| null !== parse_url($file, PHP_URL_SCHEME)
) {
return true;
}
return false;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config;
use Symfony\Component\Config\Exception\FileLocatorFileNotFoundException;
/**
* @author Fabien Potencier <[email protected]>
*/
interface FileLocatorInterface
{
/**
* Returns a full path for a given file name.
*
* @param string $name The file name to locate
* @param string|null $currentPath The current path
* @param bool $first Whether to return the first occurrence or an array of filenames
*
* @return string|array The full path to the file or an array of file paths
*
* @throws \InvalidArgumentException If $name is empty
* @throws FileLocatorFileNotFoundException If a file is not found
*/
public function locate($name, $currentPath = null, $first = true);
}
Copyright (c) 2004-2018 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Loader;
use Symfony\Component\Config\Exception\FileLoaderLoadException;
/**
* DelegatingLoader delegates loading to other loaders using a loader resolver.
*
* This loader acts as an array of LoaderInterface objects - each having
* a chance to load a given resource (handled by the resolver)
*
* @author Fabien Potencier <[email protected]>
*/
class DelegatingLoader extends Loader
{
public function __construct(LoaderResolverInterface $resolver)
{
$this->resolver = $resolver;
}
/**
* {@inheritdoc}
*/
public function load($resource, $type = null)
{
if (false === $loader = $this->resolver->resolve($resource, $type)) {
throw new FileLoaderLoadException($resource, null, null, null, $type);
}
return $loader->load($resource, $type);
}
/**
* {@inheritdoc}
*/
public function supports($resource, $type = null)
{
return false !== $this->resolver->resolve($resource, $type);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Loader;
use Symfony\Component\Config\Exception\FileLoaderImportCircularReferenceException;
use Symfony\Component\Config\Exception\FileLoaderLoadException;
use Symfony\Component\Config\Exception\FileLocatorFileNotFoundException;
use Symfony\Component\Config\FileLocatorInterface;
use Symfony\Component\Config\Resource\FileExistenceResource;
use Symfony\Component\Config\Resource\GlobResource;
/**
* FileLoader is the abstract class used by all built-in loaders that are file based.
*
* @author Fabien Potencier <[email protected]>
*/
abstract class FileLoader extends Loader
{
protected static $loading = array();
protected $locator;
private $currentDir;
public function __construct(FileLocatorInterface $locator)
{
$this->locator = $locator;
}
/**
* Sets the current directory.
*
* @param string $dir
*/
public function setCurrentDir($dir)
{
$this->currentDir = $dir;
}
/**
* Returns the file locator used by this loader.
*
* @return FileLocatorInterface
*/
public function getLocator()
{
return $this->locator;
}
/**
* Imports a resource.
*
* @param mixed $resource A Resource
* @param string|null $type The resource type or null if unknown
* @param bool $ignoreErrors Whether to ignore import errors or not
* @param string|null $sourceResource The original resource importing the new resource
*
* @return mixed
*
* @throws FileLoaderLoadException
* @throws FileLoaderImportCircularReferenceException
* @throws FileLocatorFileNotFoundException
*/
public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null)
{
if (\is_string($resource) && \strlen($resource) !== $i = strcspn($resource, '*?{[')) {
$ret = array();
$isSubpath = 0 !== $i && false !== strpos(substr($resource, 0, $i), '/');
foreach ($this->glob($resource, false, $_, $ignoreErrors || !$isSubpath) as $path => $info) {
if (null !== $res = $this->doImport($path, $type, $ignoreErrors, $sourceResource)) {
$ret[] = $res;
}
$isSubpath = true;
}
if ($isSubpath) {
return isset($ret[1]) ? $ret : (isset($ret[0]) ? $ret[0] : null);
}
}
return $this->doImport($resource, $type, $ignoreErrors, $sourceResource);
}
/**
* @internal
*/
protected function glob(string $pattern, bool $recursive, &$resource = null, bool $ignoreErrors = false)
{
if (\strlen($pattern) === $i = strcspn($pattern, '*?{[')) {
$prefix = $pattern;
$pattern = '';
} elseif (0 === $i || false === strpos(substr($pattern, 0, $i), '/')) {
$prefix = '.';
$pattern = '/'.$pattern;
} else {
$prefix = \dirname(substr($pattern, 0, 1 + $i));
$pattern = substr($pattern, \strlen($prefix));
}
try {
$prefix = $this->locator->locate($prefix, $this->currentDir, true);
} catch (FileLocatorFileNotFoundException $e) {
if (!$ignoreErrors) {
throw $e;
}
$resource = array();
foreach ($e->getPaths() as $path) {
$resource[] = new FileExistenceResource($path);
}
return;
}
$resource = new GlobResource($prefix, $pattern, $recursive);
foreach ($resource as $path => $info) {
yield $path => $info;
}
}
private function doImport($resource, $type = null, bool $ignoreErrors = false, $sourceResource = null)
{
try {
$loader = $this->resolve($resource, $type);
if ($loader instanceof self && null !== $this->currentDir) {
$resource = $loader->getLocator()->locate($resource, $this->currentDir, false);
}
$resources = \is_array($resource) ? $resource : array($resource);
for ($i = 0; $i < $resourcesCount = \count($resources); ++$i) {
if (isset(self::$loading[$resources[$i]])) {
if ($i == $resourcesCount - 1) {
throw new FileLoaderImportCircularReferenceException(array_keys(self::$loading));
}
} else {
$resource = $resources[$i];
break;
}
}
self::$loading[$resource] = true;
try {
$ret = $loader->load($resource, $type);
} finally {
unset(self::$loading[$resource]);
}
return $ret;
} catch (FileLoaderImportCircularReferenceException $e) {
throw $e;
} catch (\Exception $e) {
if (!$ignoreErrors) {
// prevent embedded imports from nesting multiple exceptions
if ($e instanceof FileLoaderLoadException) {
throw $e;
}
throw new FileLoaderLoadException($resource, $sourceResource, null, $e, $type);
}
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Loader;
/**
* GlobFileLoader loads files from a glob pattern.
*
* @author Fabien Potencier <[email protected]>
*/
class GlobFileLoader extends FileLoader
{
/**
* {@inheritdoc}
*/
public function load($resource, $type = null)
{
return $this->import($resource);
}
/**
* {@inheritdoc}
*/
public function supports($resource, $type = null)
{
return 'glob' === $type;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Loader;
use Symfony\Component\Config\Exception\FileLoaderLoadException;
/**
* Loader is the abstract class used by all built-in loaders.
*
* @author Fabien Potencier <[email protected]>
*/
abstract class Loader implements LoaderInterface
{
protected $resolver;
/**
* {@inheritdoc}
*/
public function getResolver()
{
return $this->resolver;
}
/**
* {@inheritdoc}
*/
public function setResolver(LoaderResolverInterface $resolver)
{
$this->resolver = $resolver;
}
/**
* Imports a resource.
*
* @param mixed $resource A resource
* @param string|null $type The resource type or null if unknown
*
* @return mixed
*/
public function import($resource, $type = null)
{
return $this->resolve($resource, $type)->load($resource, $type);
}
/**
* Finds a loader able to load an imported resource.
*
* @param mixed $resource A resource
* @param string|null $type The resource type or null if unknown
*
* @return $this|LoaderInterface
*
* @throws FileLoaderLoadException If no loader is found
*/
public function resolve($resource, $type = null)
{
if ($this->supports($resource, $type)) {
return $this;
}
$loader = null === $this->resolver ? false : $this->resolver->resolve($resource, $type);
if (false === $loader) {
throw new FileLoaderLoadException($resource, null, null, null, $type);
}
return $loader;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Loader;
/**
* LoaderInterface is the interface implemented by all loader classes.
*
* @author Fabien Potencier <[email protected]>
*/
interface LoaderInterface
{
/**
* Loads a resource.
*
* @param mixed $resource The resource
* @param string|null $type The resource type or null if unknown
*
* @throws \Exception If something went wrong
*/
public function load($resource, $type = null);
/**
* Returns whether this class supports the given resource.
*
* @param mixed $resource A resource
* @param string|null $type The resource type or null if unknown
*
* @return bool True if this class supports the given resource, false otherwise
*/
public function supports($resource, $type = null);
/**
* Gets the loader resolver.
*
* @return LoaderResolverInterface A LoaderResolverInterface instance
*/
public function getResolver();
/**
* Sets the loader resolver.
*/
public function setResolver(LoaderResolverInterface $resolver);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Loader;
/**
* LoaderResolver selects a loader for a given resource.
*
* A resource can be anything (e.g. a full path to a config file or a Closure).
* Each loader determines whether it can load a resource and how.
*
* @author Fabien Potencier <[email protected]>
*/
class LoaderResolver implements LoaderResolverInterface
{
/**
* @var LoaderInterface[] An array of LoaderInterface objects
*/
private $loaders = array();
/**
* @param LoaderInterface[] $loaders An array of loaders
*/
public function __construct(array $loaders = array())
{
foreach ($loaders as $loader) {
$this->addLoader($loader);
}
}
/**
* {@inheritdoc}
*/
public function resolve($resource, $type = null)
{
foreach ($this->loaders as $loader) {
if ($loader->supports($resource, $type)) {
return $loader;
}
}
return false;
}
public function addLoader(LoaderInterface $loader)
{
$this->loaders[] = $loader;
$loader->setResolver($this);
}
/**
* Returns the registered loaders.
*
* @return LoaderInterface[] An array of LoaderInterface instances
*/
public function getLoaders()
{
return $this->loaders;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Loader;
/**
* LoaderResolverInterface selects a loader for a given resource.
*
* @author Fabien Potencier <[email protected]>
*/
interface LoaderResolverInterface
{
/**
* Returns a loader able to load the resource.
*
* @param mixed $resource A resource
* @param string|null $type The resource type or null if unknown
*
* @return LoaderInterface|false The loader or false if none is able to load the resource
*/
public function resolve($resource, $type = null);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Resource;
/**
* ClassExistenceResource represents a class existence.
* Freshness is only evaluated against resource existence.
*
* The resource must be a fully-qualified class name.
*
* @author Fabien Potencier <[email protected]>
*/
class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializable
{
private $resource;
private $exists;
private static $autoloadLevel = 0;
private static $autoloadedClass;
private static $existsCache = array();
/**
* @param string $resource The fully-qualified class name
* @param bool|null $exists Boolean when the existency check has already been done
*/
public function __construct(string $resource, bool $exists = null)
{
$this->resource = $resource;
$this->exists = $exists;
}
/**
* {@inheritdoc}
*/
public function __toString()
{
return $this->resource;
}
/**
* @return string The file path to the resource
*/
public function getResource()
{
return $this->resource;
}
/**
* {@inheritdoc}
*
* @throws \ReflectionException when a parent class/interface/trait is not found
*/
public function isFresh($timestamp)
{
$loaded = class_exists($this->resource, false) || interface_exists($this->resource, false) || trait_exists($this->resource, false);
if (null !== $exists = &self::$existsCache[(int) (0 >= $timestamp)][$this->resource]) {
$exists = $exists || $loaded;
} elseif (!$exists = $loaded) {
if (!self::$autoloadLevel++) {
spl_autoload_register(__CLASS__.'::throwOnRequiredClass');
}
$autoloadedClass = self::$autoloadedClass;
self::$autoloadedClass = $this->resource;
try {
$exists = class_exists($this->resource) || interface_exists($this->resource, false) || trait_exists($this->resource, false);
} catch (\ReflectionException $e) {
if (0 >= $timestamp) {
unset(self::$existsCache[1][$this->resource]);
throw $e;
}
} finally {
self::$autoloadedClass = $autoloadedClass;
if (!--self::$autoloadLevel) {
spl_autoload_unregister(__CLASS__.'::throwOnRequiredClass');
}
}
}
if (null === $this->exists) {
$this->exists = $exists;
}
return $this->exists xor !$exists;
}
/**
* {@inheritdoc}
*/
public function serialize()
{
if (null === $this->exists) {
$this->isFresh(0);
}
return serialize(array($this->resource, $this->exists));
}
/**
* {@inheritdoc}
*/
public function unserialize($serialized)
{
list($this->resource, $this->exists) = unserialize($serialized);
}
/**
* @throws \ReflectionException When $class is not found and is required
*/
private static function throwOnRequiredClass($class)
{
if (self::$autoloadedClass === $class) {
return;
}
$e = new \ReflectionException("Class $class not found");
$trace = $e->getTrace();
$autoloadFrame = array(
'function' => 'spl_autoload_call',
'args' => array($class),
);
$i = 1 + array_search($autoloadFrame, $trace, true);
if (isset($trace[$i]['function']) && !isset($trace[$i]['class'])) {
switch ($trace[$i]['function']) {
case 'get_class_methods':
case 'get_class_vars':
case 'get_parent_class':
case 'is_a':
case 'is_subclass_of':
case 'class_exists':
case 'class_implements':
case 'class_parents':
case 'trait_exists':
case 'defined':
case 'interface_exists':
case 'method_exists':
case 'property_exists':
case 'is_callable':
return;
}
$props = array(
'file' => $trace[$i]['file'],
'line' => $trace[$i]['line'],
'trace' => \array_slice($trace, 1 + $i),
);
foreach ($props as $p => $v) {
$r = new \ReflectionProperty('Exception', $p);
$r->setAccessible(true);
$r->setValue($e, $v);
}
}
throw $e;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Resource;
/**
* ComposerResource tracks the PHP version and Composer dependencies.
*
* @author Nicolas Grekas <[email protected]>
*/
class ComposerResource implements SelfCheckingResourceInterface, \Serializable
{
private $vendors;
private static $runtimeVendors;
public function __construct()
{
self::refresh();
$this->vendors = self::$runtimeVendors;
}
public function getVendors()
{
return array_keys($this->vendors);
}
/**
* {@inheritdoc}
*/
public function __toString()
{
return __CLASS__;
}
/**
* {@inheritdoc}
*/
public function isFresh($timestamp)
{
self::refresh();
return self::$runtimeVendors === $this->vendors;
}
public function serialize()
{
return serialize($this->vendors);
}
public function unserialize($serialized)
{
$this->vendors = unserialize($serialized);
}
private static function refresh()
{
self::$runtimeVendors = array();
foreach (get_declared_classes() as $class) {
if ('C' === $class[0] && 0 === strpos($class, 'ComposerAutoloaderInit')) {
$r = new \ReflectionClass($class);
$v = \dirname(\dirname($r->getFileName()));
if (file_exists($v.'/composer/installed.json')) {
self::$runtimeVendors[$v] = @filemtime($v.'/composer/installed.json');
}
}
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Resource;
/**
* DirectoryResource represents a resources stored in a subdirectory tree.
*
* @author Fabien Potencier <[email protected]>
*/
class DirectoryResource implements SelfCheckingResourceInterface, \Serializable
{
private $resource;
private $pattern;
/**
* @param string $resource The file path to the resource
* @param string|null $pattern A pattern to restrict monitored files
*
* @throws \InvalidArgumentException
*/
public function __construct(string $resource, string $pattern = null)
{
$this->resource = realpath($resource) ?: (file_exists($resource) ? $resource : false);
$this->pattern = $pattern;
if (false === $this->resource || !is_dir($this->resource)) {
throw new \InvalidArgumentException(sprintf('The directory "%s" does not exist.', $resource));
}
}
/**
* {@inheritdoc}
*/
public function __toString()
{
return md5(serialize(array($this->resource, $this->pattern)));
}
/**
* @return string The file path to the resource
*/
public function getResource()
{
return $this->resource;
}
/**
* Returns the pattern to restrict monitored files.
*
* @return string|null
*/
public function getPattern()
{
return $this->pattern;
}
/**
* {@inheritdoc}
*/
public function isFresh($timestamp)
{
if (!is_dir($this->resource)) {
return false;
}
if ($timestamp < filemtime($this->resource)) {
return false;
}
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->resource), \RecursiveIteratorIterator::SELF_FIRST) as $file) {
// if regex filtering is enabled only check matching files
if ($this->pattern && $file->isFile() && !preg_match($this->pattern, $file->getBasename())) {
continue;
}
// always monitor directories for changes, except the .. entries
// (otherwise deleted files wouldn't get detected)
if ($file->isDir() && '/..' === substr($file, -3)) {
continue;
}
// for broken links
try {
$fileMTime = $file->getMTime();
} catch (\RuntimeException $e) {
continue;
}
// early return if a file's mtime exceeds the passed timestamp
if ($timestamp < $fileMTime) {
return false;
}
}
return true;
}
public function serialize()
{
return serialize(array($this->resource, $this->pattern));
}
public function unserialize($serialized)
{
list($this->resource, $this->pattern) = unserialize($serialized);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Resource;
/**
* FileExistenceResource represents a resource stored on the filesystem.
* Freshness is only evaluated against resource creation or deletion.
*
* The resource can be a file or a directory.
*
* @author Charles-Henri Bruyand <[email protected]>
*/
class FileExistenceResource implements SelfCheckingResourceInterface, \Serializable
{
private $resource;
private $exists;
/**
* @param string $resource The file path to the resource
*/
public function __construct(string $resource)
{
$this->resource = $resource;
$this->exists = file_exists($resource);
}
/**
* {@inheritdoc}
*/
public function __toString()
{
return $this->resource;
}
/**
* @return string The file path to the resource
*/
public function getResource()
{
return $this->resource;
}
/**
* {@inheritdoc}
*/
public function isFresh($timestamp)
{
return file_exists($this->resource) === $this->exists;
}
/**
* {@inheritdoc}
*/
public function serialize()
{
return serialize(array($this->resource, $this->exists));
}
/**
* {@inheritdoc}
*/
public function unserialize($serialized)
{
list($this->resource, $this->exists) = unserialize($serialized);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Resource;
/**
* FileResource represents a resource stored on the filesystem.
*
* The resource can be a file or a directory.
*
* @author Fabien Potencier <[email protected]>
*/
class FileResource implements SelfCheckingResourceInterface, \Serializable
{
/**
* @var string|false
*/
private $resource;
/**
* @param string $resource The file path to the resource
*
* @throws \InvalidArgumentException
*/
public function __construct(string $resource)
{
$this->resource = realpath($resource) ?: (file_exists($resource) ? $resource : false);
if (false === $this->resource) {
throw new \InvalidArgumentException(sprintf('The file "%s" does not exist.', $resource));
}
}
/**
* {@inheritdoc}
*/
public function __toString()
{
return $this->resource;
}
/**
* @return string The canonicalized, absolute path to the resource
*/
public function getResource()
{
return $this->resource;
}
/**
* {@inheritdoc}
*/
public function isFresh($timestamp)
{
return false !== ($filemtime = @filemtime($this->resource)) && $filemtime <= $timestamp;
}
public function serialize()
{
return serialize($this->resource);
}
public function unserialize($serialized)
{
$this->resource = unserialize($serialized);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Resource;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\Glob;
/**
* GlobResource represents a set of resources stored on the filesystem.
*
* Only existence/removal is tracked (not mtimes.)
*
* @author Nicolas Grekas <[email protected]>
*/
class GlobResource implements \IteratorAggregate, SelfCheckingResourceInterface, \Serializable
{
private $prefix;
private $pattern;
private $recursive;
private $hash;
/**
* @param string $prefix A directory prefix
* @param string $pattern A glob pattern
* @param bool $recursive Whether directories should be scanned recursively or not
*
* @throws \InvalidArgumentException
*/
public function __construct(?string $prefix, string $pattern, bool $recursive)
{
$this->prefix = realpath($prefix) ?: (file_exists($prefix) ? $prefix : false);
$this->pattern = $pattern;
$this->recursive = $recursive;
if (false === $this->prefix) {
throw new \InvalidArgumentException(sprintf('The path "%s" does not exist.', $prefix));
}
}
public function getPrefix()
{
return $this->prefix;
}
/**
* {@inheritdoc}
*/
public function __toString()
{
return 'glob.'.$this->prefix.$this->pattern.(int) $this->recursive;
}
/**
* {@inheritdoc}
*/
public function isFresh($timestamp)
{
$hash = $this->computeHash();
if (null === $this->hash) {
$this->hash = $hash;
}
return $this->hash === $hash;
}
public function serialize()
{
if (null === $this->hash) {
$this->hash = $this->computeHash();
}
return serialize(array($this->prefix, $this->pattern, $this->recursive, $this->hash));
}
public function unserialize($serialized)
{
list($this->prefix, $this->pattern, $this->recursive, $this->hash) = unserialize($serialized);
}
public function getIterator()
{
if (!file_exists($this->prefix) || (!$this->recursive && '' === $this->pattern)) {
return;
}
if (0 !== strpos($this->prefix, 'phar://') && false === strpos($this->pattern, '/**/') && (\defined('GLOB_BRACE') || false === strpos($this->pattern, '{'))) {
foreach (glob($this->prefix.$this->pattern, \defined('GLOB_BRACE') ? GLOB_BRACE : 0) as $path) {
if ($this->recursive && is_dir($path)) {
$files = iterator_to_array(new \RecursiveIteratorIterator(
new \RecursiveCallbackFilterIterator(
new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS),
function (\SplFileInfo $file) { return '.' !== $file->getBasename()[0]; }
),
\RecursiveIteratorIterator::LEAVES_ONLY
));
uasort($files, function (\SplFileInfo $a, \SplFileInfo $b) {
return (string) $a > (string) $b ? 1 : -1;
});
foreach ($files as $path => $info) {
if ($info->isFile()) {
yield $path => $info;
}
}
} elseif (is_file($path)) {
yield $path => new \SplFileInfo($path);
}
}
return;
}
if (!class_exists(Finder::class)) {
throw new \LogicException(sprintf('Extended glob pattern "%s" cannot be used as the Finder component is not installed.', $this->pattern));
}
$finder = new Finder();
$regex = Glob::toRegex($this->pattern);
if ($this->recursive) {
$regex = substr_replace($regex, '(/|$)', -2, 1);
}
$prefixLen = \strlen($this->prefix);
foreach ($finder->followLinks()->sortByName()->in($this->prefix) as $path => $info) {
if (preg_match($regex, substr('\\' === \DIRECTORY_SEPARATOR ? str_replace('\\', '/', $path) : $path, $prefixLen)) && $info->isFile()) {
yield $path => $info;
}
}
}
private function computeHash()
{
$hash = hash_init('md5');
foreach ($this->getIterator() as $path => $info) {
hash_update($hash, $path."\n");
}
return hash_final($hash);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Resource;
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* @author Nicolas Grekas <[email protected]>
*/
class ReflectionClassResource implements SelfCheckingResourceInterface, \Serializable
{
private $files = array();
private $className;
private $classReflector;
private $excludedVendors = array();
private $hash;
public function __construct(\ReflectionClass $classReflector, array $excludedVendors = array())
{
$this->className = $classReflector->name;
$this->classReflector = $classReflector;
$this->excludedVendors = $excludedVendors;
}
public function isFresh($timestamp)
{
if (null === $this->hash) {
$this->hash = $this->computeHash();
$this->loadFiles($this->classReflector);
}
foreach ($this->files as $file => $v) {
if (false === $filemtime = @filemtime($file)) {
return false;
}
if ($filemtime > $timestamp) {
return $this->hash === $this->computeHash();
}
}
return true;
}
public function __toString()
{
return 'reflection.'.$this->className;
}
public function serialize()
{
if (null === $this->hash) {
$this->hash = $this->computeHash();
$this->loadFiles($this->classReflector);
}
return serialize(array($this->files, $this->className, $this->hash));
}
public function unserialize($serialized)
{
list($this->files, $this->className, $this->hash) = unserialize($serialized);
}
private function loadFiles(\ReflectionClass $class)
{
foreach ($class->getInterfaces() as $v) {
$this->loadFiles($v);
}
do {
$file = $class->getFileName();
if (false !== $file && file_exists($file)) {
foreach ($this->excludedVendors as $vendor) {
if (0 === strpos($file, $vendor) && false !== strpbrk(substr($file, \strlen($vendor), 1), '/'.\DIRECTORY_SEPARATOR)) {
$file = false;
break;
}
}
if ($file) {
$this->files[$file] = null;
}
}
foreach ($class->getTraits() as $v) {
$this->loadFiles($v);
}
} while ($class = $class->getParentClass());
}
private function computeHash()
{
if (null === $this->classReflector) {
try {
$this->classReflector = new \ReflectionClass($this->className);
} catch (\ReflectionException $e) {
// the class does not exist anymore
return false;
}
}
$hash = hash_init('md5');
foreach ($this->generateSignature($this->classReflector) as $info) {
hash_update($hash, $info);
}
return hash_final($hash);
}
private function generateSignature(\ReflectionClass $class)
{
yield $class->getDocComment();
yield (int) $class->isFinal();
yield (int) $class->isAbstract();
if ($class->isTrait()) {
yield print_r(class_uses($class->name), true);
} else {
yield print_r(class_parents($class->name), true);
yield print_r(class_implements($class->name), true);
yield print_r($class->getConstants(), true);
}
if (!$class->isInterface()) {
$defaults = $class->getDefaultProperties();
foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC | \ReflectionProperty::IS_PROTECTED) as $p) {
yield $p->getDocComment().$p;
yield print_r($defaults[$p->name], true);
}
}
foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $m) {
yield preg_replace('/^ @@.*/m', '', $m);
$defaults = array();
foreach ($m->getParameters() as $p) {
$defaults[$p->name] = $p->isDefaultValueAvailable() ? $p->getDefaultValue() : null;
}
yield print_r($defaults, true);
}
if ($class->isAbstract() || $class->isInterface() || $class->isTrait()) {
return;
}
if (interface_exists(EventSubscriberInterface::class, false) && $class->isSubclassOf(EventSubscriberInterface::class)) {
yield EventSubscriberInterface::class;
yield print_r(\call_user_func(array($class->name, 'getSubscribedEvents')), true);
}
if (interface_exists(ServiceSubscriberInterface::class, false) && $class->isSubclassOf(ServiceSubscriberInterface::class)) {
yield ServiceSubscriberInterface::class;
yield print_r(\call_user_func(array($class->name, 'getSubscribedServices')), true);
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Resource;
/**
* ResourceInterface is the interface that must be implemented by all Resource classes.
*
* @author Fabien Potencier <[email protected]>
*/
interface ResourceInterface
{
/**
* Returns a string representation of the Resource.
*
* This method is necessary to allow for resource de-duplication, for example by means
* of array_unique(). The string returned need not have a particular meaning, but has
* to be identical for different ResourceInterface instances referring to the same
* resource; and it should be unlikely to collide with that of other, unrelated
* resource instances.
*
* @return string A string representation unique to the underlying Resource
*/
public function __toString();
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Resource;
use Symfony\Component\Config\ResourceCheckerInterface;
/**
* Resource checker for instances of SelfCheckingResourceInterface.
*
* As these resources perform the actual check themselves, we can provide
* this class as a standard way of validating them.
*
* @author Matthias Pigulla <[email protected]>
*/
class SelfCheckingResourceChecker implements ResourceCheckerInterface
{
public function supports(ResourceInterface $metadata)
{
return $metadata instanceof SelfCheckingResourceInterface;
}
public function isFresh(ResourceInterface $resource, $timestamp)
{
/* @var SelfCheckingResourceInterface $resource */
return $resource->isFresh($timestamp);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Resource;
/**
* Interface for Resources that can check for freshness autonomously,
* without special support from external services.
*
* @author Matthias Pigulla <[email protected]>
*/
interface SelfCheckingResourceInterface extends ResourceInterface
{
/**
* Returns true if the resource has not been updated since the given timestamp.
*
* @param int $timestamp The last time the resource was loaded
*
* @return bool True if the resource has not been updated, false otherwise
*/
public function isFresh($timestamp);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config;
use Symfony\Component\Config\Resource\ResourceInterface;
use Symfony\Component\Filesystem\Exception\IOException;
use Symfony\Component\Filesystem\Filesystem;
/**
* ResourceCheckerConfigCache uses instances of ResourceCheckerInterface
* to check whether cached data is still fresh.
*
* @author Matthias Pigulla <[email protected]>
*/
class ResourceCheckerConfigCache implements ConfigCacheInterface
{
/**
* @var string
*/
private $file;
/**
* @var iterable|ResourceCheckerInterface[]
*/
private $resourceCheckers;
/**
* @param string $file The absolute cache path
* @param iterable|ResourceCheckerInterface[] $resourceCheckers The ResourceCheckers to use for the freshness check
*/
public function __construct(string $file, iterable $resourceCheckers = array())
{
$this->file = $file;
$this->resourceCheckers = $resourceCheckers;
}
/**
* {@inheritdoc}
*/
public function getPath()
{
return $this->file;
}
/**
* Checks if the cache is still fresh.
*
* This implementation will make a decision solely based on the ResourceCheckers
* passed in the constructor.
*
* The first ResourceChecker that supports a given resource is considered authoritative.
* Resources with no matching ResourceChecker will silently be ignored and considered fresh.
*
* @return bool true if the cache is fresh, false otherwise
*/
public function isFresh()
{
if (!is_file($this->file)) {
return false;
}
if ($this->resourceCheckers instanceof \Traversable && !$this->resourceCheckers instanceof \Countable) {
$this->resourceCheckers = iterator_to_array($this->resourceCheckers);
}
if (!\count($this->resourceCheckers)) {
return true; // shortcut - if we don't have any checkers we don't need to bother with the meta file at all
}
$metadata = $this->getMetaFile();
if (!is_file($metadata)) {
return false;
}
$meta = $this->safelyUnserialize($metadata);
if (false === $meta) {
return false;
}
$time = filemtime($this->file);
foreach ($meta as $resource) {
/* @var ResourceInterface $resource */
foreach ($this->resourceCheckers as $checker) {
if (!$checker->supports($resource)) {
continue; // next checker
}
if ($checker->isFresh($resource, $time)) {
break; // no need to further check this resource
}
return false; // cache is stale
}
// no suitable checker found, ignore this resource
}
return true;
}
/**
* Writes cache.
*
* @param string $content The content to write in the cache
* @param ResourceInterface[] $metadata An array of metadata
*
* @throws \RuntimeException When cache file can't be written
*/
public function write($content, array $metadata = null)
{
$mode = 0666;
$umask = umask();
$filesystem = new Filesystem();
$filesystem->dumpFile($this->file, $content);
try {
$filesystem->chmod($this->file, $mode, $umask);
} catch (IOException $e) {
// discard chmod failure (some filesystem may not support it)
}
if (null !== $metadata) {
$filesystem->dumpFile($this->getMetaFile(), serialize($metadata));
try {
$filesystem->chmod($this->getMetaFile(), $mode, $umask);
} catch (IOException $e) {
// discard chmod failure (some filesystem may not support it)
}
}
if (\function_exists('opcache_invalidate') && ini_get('opcache.enable')) {
@opcache_invalidate($this->file, true);
}
}
/**
* Gets the meta file path.
*
* @return string The meta file path
*/
private function getMetaFile()
{
return $this->file.'.meta';
}
private function safelyUnserialize($file)
{
$e = null;
$meta = false;
$signalingException = new \UnexpectedValueException();
$prevUnserializeHandler = ini_set('unserialize_callback_func', '');
$prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = array()) use (&$prevErrorHandler, $signalingException) {
if (E_WARNING === $type && 'Class __PHP_Incomplete_Class has no unserializer' === $msg) {
throw $signalingException;
}
return $prevErrorHandler ? $prevErrorHandler($type, $msg, $file, $line, $context) : false;
});
try {
$meta = unserialize(file_get_contents($file));
} catch (\Throwable $e) {
if ($e !== $signalingException) {
throw $e;
}
} finally {
restore_error_handler();
ini_set('unserialize_callback_func', $prevUnserializeHandler);
}
return $meta;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config;
/**
* A ConfigCacheFactory implementation that validates the
* cache with an arbitrary set of ResourceCheckers.
*
* @author Matthias Pigulla <[email protected]>
*/
class ResourceCheckerConfigCacheFactory implements ConfigCacheFactoryInterface
{
private $resourceCheckers = array();
/**
* @param iterable|ResourceCheckerInterface[] $resourceCheckers
*/
public function __construct(iterable $resourceCheckers = array())
{
$this->resourceCheckers = $resourceCheckers;
}
/**
* {@inheritdoc}
*/
public function cache($file, $callback)
{
if (!\is_callable($callback)) {
throw new \InvalidArgumentException(sprintf('Invalid type for callback argument. Expected callable, but got "%s".', \gettype($callback)));
}
$cache = new ResourceCheckerConfigCache($file, $this->resourceCheckers);
if (!$cache->isFresh()) {
\call_user_func($callback, $cache);
}
return $cache;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config;
use Symfony\Component\Config\Resource\ResourceInterface;
/**
* Interface for ResourceCheckers.
*
* When a ResourceCheckerConfigCache instance is checked for freshness, all its associated
* metadata resources are passed to ResourceCheckers. The ResourceCheckers
* can then inspect the resources and decide whether the cache can be considered
* fresh or not.
*
* @author Matthias Pigulla <[email protected]>
* @author Benjamin Klotz <[email protected]>
*/
interface ResourceCheckerInterface
{
/**
* Queries the ResourceChecker whether it can validate a given
* resource or not.
*
* @param ResourceInterface $metadata The resource to be checked for freshness
*
* @return bool True if the ResourceChecker can handle this resource type, false if not
*/
public function supports(ResourceInterface $metadata);
/**
* Validates the resource.
*
* @param ResourceInterface $resource The resource to be validated
* @param int $timestamp The timestamp at which the cache associated with this resource was created
*
* @return bool True if the resource has not changed since the given timestamp, false otherwise
*/
public function isFresh(ResourceInterface $resource, $timestamp);
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Config\ConfigCacheFactory;
class ConfigCacheFactoryTest extends TestCase
{
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Invalid type for callback argument. Expected callable, but got "object".
*/
public function testCacheWithInvalidCallback()
{
$cacheFactory = new ConfigCacheFactory(true);
$cacheFactory->cache('file', new \stdClass());
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Config\ConfigCache;
use Symfony\Component\Config\Tests\Resource\ResourceStub;
class ConfigCacheTest extends TestCase
{
private $cacheFile = null;
protected function setUp()
{
$this->cacheFile = tempnam(sys_get_temp_dir(), 'config_');
}
protected function tearDown()
{
$files = array($this->cacheFile, $this->cacheFile.'.meta');
foreach ($files as $file) {
if (file_exists($file)) {
unlink($file);
}
}
}
/**
* @dataProvider debugModes
*/
public function testCacheIsNotValidIfNothingHasBeenCached($debug)
{
unlink($this->cacheFile); // remove tempnam() side effect
$cache = new ConfigCache($this->cacheFile, $debug);
$this->assertFalse($cache->isFresh());
}
public function testIsAlwaysFreshInProduction()
{
$staleResource = new ResourceStub();
$staleResource->setFresh(false);
$cache = new ConfigCache($this->cacheFile, false);
$cache->write('', array($staleResource));
$this->assertTrue($cache->isFresh());
}
/**
* @dataProvider debugModes
*/
public function testIsFreshWhenNoResourceProvided($debug)
{
$cache = new ConfigCache($this->cacheFile, $debug);
$cache->write('', array());
$this->assertTrue($cache->isFresh());
}
public function testFreshResourceInDebug()
{
$freshResource = new ResourceStub();
$freshResource->setFresh(true);
$cache = new ConfigCache($this->cacheFile, true);
$cache->write('', array($freshResource));
$this->assertTrue($cache->isFresh());
}
public function testStaleResourceInDebug()
{
$staleResource = new ResourceStub();
$staleResource->setFresh(false);
$cache = new ConfigCache($this->cacheFile, true);
$cache->write('', array($staleResource));
$this->assertFalse($cache->isFresh());
}
public function debugModes()
{
return array(
array(true),
array(false),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment