vendor/friendsofsymfony/http-cache-bundle/src/DependencyInjection/FOSHttpCacheExtension.php line 41

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the FOSHttpCacheBundle package.
  4.  *
  5.  * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace FOS\HttpCacheBundle\DependencyInjection;
  11. use FOS\HttpCache\ProxyClient\HttpDispatcher;
  12. use FOS\HttpCache\ProxyClient\ProxyClient;
  13. use FOS\HttpCache\SymfonyCache\KernelDispatcher;
  14. use FOS\HttpCache\TagHeaderFormatter\MaxHeaderValueLengthFormatter;
  15. use FOS\HttpCacheBundle\DependencyInjection\Compiler\HashGeneratorPass;
  16. use FOS\HttpCacheBundle\Http\ResponseMatcher\ExpressionResponseMatcher;
  17. use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
  18. use Symfony\Component\Config\FileLocator;
  19. use Symfony\Component\Console\Application;
  20. use Symfony\Component\DependencyInjection\ChildDefinition;
  21. use Symfony\Component\DependencyInjection\ContainerBuilder;
  22. use Symfony\Component\DependencyInjection\Definition;
  23. use Symfony\Component\DependencyInjection\DefinitionDecorator;
  24. use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
  25. use Symfony\Component\DependencyInjection\Reference;
  26. use Symfony\Component\HttpKernel\DependencyInjection\Extension;
  27. use Symfony\Component\HttpKernel\Kernel;
  28. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  29. /**
  30.  * {@inheritdoc}
  31.  */
  32. class FOSHttpCacheExtension extends Extension
  33. {
  34.     /**
  35.      * {@inheritdoc}
  36.      */
  37.     public function getConfiguration(array $configContainerBuilder $container)
  38.     {
  39.         return new Configuration($container->getParameter('kernel.debug'));
  40.     }
  41.     /**
  42.      * {@inheritdoc}
  43.      */
  44.     public function load(array $configsContainerBuilder $container)
  45.     {
  46.         $configuration $this->getConfiguration($configs$container);
  47.         $config $this->processConfiguration($configuration$configs);
  48.         $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
  49.         $loader->load('matcher.xml');
  50.         if ($config['debug']['enabled'] || (!empty($config['cache_control']))) {
  51.             $debugHeader $config['debug']['enabled'] ? $config['debug']['header'] : false;
  52.             $container->setParameter('fos_http_cache.debug_header'$debugHeader);
  53.             $loader->load('cache_control_listener.xml');
  54.         }
  55.         $this->loadCacheable($container$config['cacheable']);
  56.         if (!empty($config['cache_control'])) {
  57.             $this->loadCacheControl($container$config['cache_control']);
  58.         }
  59.         if (isset($config['proxy_client'])) {
  60.             $this->loadProxyClient($container$loader$config['proxy_client']);
  61.         }
  62.         if (isset($config['test'])) {
  63.             $this->loadTest($container$loader$config['test']);
  64.         }
  65.         if ($config['cache_manager']['enabled']) {
  66.             if (array_key_exists('custom_proxy_client'$config['cache_manager'])) {
  67.                 // overwrite the previously set alias, if a proxy client was also configured
  68.                 $container->setAlias(
  69.                     'fos_http_cache.default_proxy_client',
  70.                     $config['cache_manager']['custom_proxy_client']
  71.                 );
  72.             }
  73.             if ('auto' === $config['cache_manager']['generate_url_type']) {
  74.                 if (array_key_exists('custom_proxy_client'$config['cache_manager'])) {
  75.                     $generateUrlType UrlGeneratorInterface::ABSOLUTE_URL;
  76.                 } else {
  77.                     $defaultClient $this->getDefaultProxyClient($config['proxy_client']);
  78.                     if ('noop' !== $defaultClient
  79.                         && array_key_exists('base_url'$config['proxy_client'][$defaultClient])) {
  80.                         $generateUrlType UrlGeneratorInterface::ABSOLUTE_PATH;
  81.                     } else {
  82.                         $generateUrlType UrlGeneratorInterface::ABSOLUTE_URL;
  83.                     }
  84.                 }
  85.             } else {
  86.                 $generateUrlType $config['cache_manager']['generate_url_type'];
  87.             }
  88.             $container->setParameter('fos_http_cache.cache_manager.generate_url_type'$generateUrlType);
  89.             $loader->load('cache_manager.xml');
  90.             if (class_exists(Application::class)) {
  91.                 $loader->load('cache_manager_commands.xml');
  92.             }
  93.         }
  94.         if ($config['tags']['enabled']) {
  95.             $this->loadCacheTagging(
  96.                 $container,
  97.                 $loader,
  98.                 $config['tags'],
  99.                 array_key_exists('proxy_client'$config)
  100.                     ? $this->getDefaultProxyClient($config['proxy_client'])
  101.                     : 'custom'
  102.             );
  103.         } else {
  104.             $container->setParameter('fos_http_cache.compiler_pass.tag_annotations'false);
  105.         }
  106.         if ($config['invalidation']['enabled']) {
  107.             $loader->load('invalidation_listener.xml');
  108.             if (!empty($config['invalidation']['expression_language'])) {
  109.                 $container->setAlias(
  110.                     'fos_http_cache.invalidation.expression_language',
  111.                     $config['invalidation']['expression_language']
  112.                 );
  113.             }
  114.             if (!empty($config['invalidation']['rules'])) {
  115.                 $this->loadInvalidatorRules($container$config['invalidation']['rules']);
  116.             }
  117.         }
  118.         if ($config['user_context']['enabled']) {
  119.             $this->loadUserContext($container$loader$config['user_context']);
  120.         }
  121.         if (!empty($config['flash_message']) && $config['flash_message']['enabled']) {
  122.             unset($config['flash_message']['enabled']);
  123.             $container->setParameter('fos_http_cache.event_listener.flash_message.options'$config['flash_message']);
  124.             $loader->load('flash_message.xml');
  125.         }
  126.         if (\PHP_VERSION_ID >= 80000) {
  127.             $loader->load('php8_attributes.xml');
  128.         }
  129.     }
  130.     private function loadCacheable(ContainerBuilder $container, array $config)
  131.     {
  132.         $definition $container->getDefinition('fos_http_cache.response_matcher.cacheable');
  133.         // Change CacheableResponseMatcher to ExpressionResponseMatcher
  134.         if ($config['response']['expression']) {
  135.             $definition->setClass(ExpressionResponseMatcher::class)
  136.                 ->setArguments([$config['response']['expression']]);
  137.         } else {
  138.             $container->setParameter(
  139.                 'fos_http_cache.cacheable.response.additional_status',
  140.                 $config['response']['additional_status']
  141.             );
  142.         }
  143.     }
  144.     /**
  145.      * @throws InvalidConfigurationException
  146.      */
  147.     private function loadCacheControl(ContainerBuilder $container, array $config)
  148.     {
  149.         $controlDefinition $container->getDefinition('fos_http_cache.event_listener.cache_control');
  150.         foreach ($config['rules'] as $rule) {
  151.             $ruleMatcher $this->parseRuleMatcher($container$rule['match']);
  152.             if ('default' === $rule['headers']['overwrite']) {
  153.                 $rule['headers']['overwrite'] = $config['defaults']['overwrite'];
  154.             }
  155.             $controlDefinition->addMethodCall('addRule', [$ruleMatcher$rule['headers']]);
  156.         }
  157.     }
  158.     /**
  159.      * Parse one cache control rule match configuration.
  160.      *
  161.      * @param array $match Request and response match criteria
  162.      *
  163.      * @return Reference pointing to a rule matcher service
  164.      */
  165.     private function parseRuleMatcher(ContainerBuilder $container, array $match)
  166.     {
  167.         $requestMatcher $this->parseRequestMatcher($container$match);
  168.         $responseMatcher $this->parseResponseMatcher($container$match);
  169.         $signature serialize([(string) $requestMatcher, (string) $responseMatcher]);
  170.         $id 'fos_http_cache.cache_control.rule_matcher.'.md5($signature);
  171.         if ($container->hasDefinition($id)) {
  172.             throw new InvalidConfigurationException('Duplicate match criteria. Would be hidden by a previous rule. match: '.json_encode($match));
  173.         }
  174.         $container
  175.             ->setDefinition($id$this->createChildDefinition('fos_http_cache.rule_matcher'))
  176.             ->replaceArgument(0$requestMatcher)
  177.             ->replaceArgument(1$responseMatcher)
  178.         ;
  179.         return new Reference($id);
  180.     }
  181.     /**
  182.      * Used for cache control, tag and invalidation rules.
  183.      *
  184.      * @return Reference to the request matcher
  185.      */
  186.     private function parseRequestMatcher(ContainerBuilder $container, array $match)
  187.     {
  188.         $match['ips'] = (empty($match['ips'])) ? null $match['ips'];
  189.         $arguments = [
  190.             $match['path'],
  191.             $match['host'],
  192.             $match['methods'],
  193.             $match['ips'],
  194.             $match['attributes'],
  195.         ];
  196.         $serialized serialize($arguments);
  197.         $id 'fos_http_cache.request_matcher.'.md5($serialized).sha1($serialized);
  198.         if (!$container->hasDefinition($id)) {
  199.             $container
  200.                 ->setDefinition($id$this->createChildDefinition('fos_http_cache.request_matcher'))
  201.                 ->setArguments($arguments)
  202.             ;
  203.             if (!empty($match['query_string'])) {
  204.                 $container->getDefinition($id)->addMethodCall('setQueryString', [$match['query_string']]);
  205.             }
  206.         }
  207.         return new Reference($id);
  208.     }
  209.     /**
  210.      * Used only for cache control rules.
  211.      *
  212.      * @return Reference to the correct response matcher service
  213.      */
  214.     private function parseResponseMatcher(ContainerBuilder $container, array $config)
  215.     {
  216.         if (!empty($config['additional_response_status'])) {
  217.             $id 'fos_http_cache.cache_control.expression.'.md5(serialize($config['additional_response_status']));
  218.             if (!$container->hasDefinition($id)) {
  219.                 $container
  220.                     ->setDefinition($id$this->createChildDefinition('fos_http_cache.response_matcher.cache_control.cacheable_response'))
  221.                     ->setArguments([$config['additional_response_status']])
  222.                 ;
  223.             }
  224.         } elseif (!empty($config['match_response'])) {
  225.             $id 'fos_http_cache.cache_control.match_response.'.md5($config['match_response']);
  226.             if (!$container->hasDefinition($id)) {
  227.                 $container
  228.                     ->setDefinition($id$this->createChildDefinition('fos_http_cache.response_matcher.cache_control.expression'))
  229.                     ->replaceArgument(0$config['match_response'])
  230.                 ;
  231.             }
  232.         } else {
  233.             $id 'fos_http_cache.response_matcher.cacheable';
  234.         }
  235.         return new Reference($id);
  236.     }
  237.     private function loadUserContext(ContainerBuilder $containerXmlFileLoader $loader, array $config)
  238.     {
  239.         $configuredUserIdentifierHeaders array_map('strtolower'$config['user_identifier_headers']);
  240.         $completeUserIdentifierHeaders $configuredUserIdentifierHeaders;
  241.         if (false !== $config['session_name_prefix'] && !in_array('cookie'$completeUserIdentifierHeaders)) {
  242.             $completeUserIdentifierHeaders[] = 'cookie';
  243.         }
  244.         $loader->load('user_context.xml');
  245.         $container->getDefinition('fos_http_cache.user_context.request_matcher')
  246.             ->replaceArgument(0$config['match']['accept'])
  247.             ->replaceArgument(1$config['match']['method']);
  248.         $container->setParameter('fos_http_cache.event_listener.user_context.options', [
  249.             'user_identifier_headers' => $completeUserIdentifierHeaders,
  250.             'user_hash_header' => $config['user_hash_header'],
  251.             'ttl' => $config['hash_cache_ttl'],
  252.             'add_vary_on_hash' => $config['always_vary_on_context_hash'],
  253.         ]);
  254.         $container->getDefinition('fos_http_cache.event_listener.user_context')
  255.             ->replaceArgument(0, new Reference($config['match']['matcher_service']))
  256.         ;
  257.         $options = [
  258.             'user_identifier_headers' => $configuredUserIdentifierHeaders,
  259.             'session_name_prefix' => $config['session_name_prefix'],
  260.         ];
  261.         $container->getDefinition('fos_http_cache.user_context.anonymous_request_matcher')
  262.             ->replaceArgument(0$options);
  263.         if ($config['logout_handler']['enabled']) {
  264.             $container->setAlias('security.logout.handler.session''fos_http_cache.user_context.session_logout_handler');
  265.         } else {
  266.             $container->removeDefinition('fos_http_cache.user_context.logout_handler');
  267.             $container->removeDefinition('fos_http_cache.user_context.session_logout_handler');
  268.             $container->removeDefinition('fos_http_cache.user_context_invalidator');
  269.         }
  270.         if ($config['role_provider']) {
  271.             $container->getDefinition('fos_http_cache.user_context.role_provider')
  272.                 ->addTag(HashGeneratorPass::TAG_NAME)
  273.                 ->setAbstract(false);
  274.         }
  275.         // Only decorate default SessionListener for Symfony 3.4 - 4.0
  276.         // For Symfony 4.1+, the UserContextListener sets the header that tells
  277.         // the SessionListener to leave the cache-control header unchanged.
  278.         if (version_compare(Kernel::VERSION'3.4''>=')
  279.             && version_compare(Kernel::VERSION'4.1''<')
  280.         ) {
  281.             $container->getDefinition('fos_http_cache.user_context.session_listener')
  282.                 ->setArgument(1strtolower($config['user_hash_header']))
  283.                 ->setArgument(2$completeUserIdentifierHeaders);
  284.         } else {
  285.             $container->removeDefinition('fos_http_cache.user_context.session_listener');
  286.         }
  287.     }
  288.     private function loadProxyClient(ContainerBuilder $containerXmlFileLoader $loader, array $config)
  289.     {
  290.         if (isset($config['varnish'])) {
  291.             $this->loadVarnish($container$loader$config['varnish']);
  292.         }
  293.         if (isset($config['nginx'])) {
  294.             $this->loadNginx($container$loader$config['nginx']);
  295.         }
  296.         if (isset($config['symfony'])) {
  297.             $this->loadSymfony($container$loader$config['symfony']);
  298.         }
  299.         if (isset($config['noop'])) {
  300.             $loader->load('noop.xml');
  301.         }
  302.         $container->setAlias(
  303.             'fos_http_cache.default_proxy_client',
  304.             'fos_http_cache.proxy_client.'.$this->getDefaultProxyClient($config)
  305.         );
  306.         $container->setAlias(
  307.             ProxyClient::class,
  308.             'fos_http_cache.default_proxy_client'
  309.         );
  310.     }
  311.     /**
  312.      * Define the http dispatcher service for the proxy client $name.
  313.      *
  314.      * @param string $serviceName
  315.      */
  316.     private function createHttpDispatcherDefinition(ContainerBuilder $container, array $config$serviceName)
  317.     {
  318.         if (array_key_exists('servers'$config)) {
  319.             foreach ($config['servers'] as $url) {
  320.                 $usedEnvs = [];
  321.                 $container->resolveEnvPlaceholders($urlnull$usedEnvs);
  322.                 if (=== \count($usedEnvs)) {
  323.                     $this->validateUrl($url'Not a valid Varnish server address: "%s"');
  324.                 }
  325.             }
  326.         }
  327.         if (array_key_exists('servers_from_jsonenv'$config) && is_string($config['servers_from_jsonenv'])) {
  328.             // check that the config contains an env var
  329.             $usedEnvs = [];
  330.             $container->resolveEnvPlaceholders($config['servers_from_jsonenv'], null$usedEnvs);
  331.             if (=== \count($usedEnvs)) {
  332.                 throw new InvalidConfigurationException('Not a valid Varnish servers_from_jsonenv configuration: '.$config['servers_from_jsonenv']);
  333.             }
  334.             $config['servers'] = $config['servers_from_jsonenv'];
  335.         }
  336.         if (!empty($config['base_url'])) {
  337.             $baseUrl $config['base_url'];
  338.             $usedEnvs = [];
  339.             $container->resolveEnvPlaceholders($baseUrlnull$usedEnvs);
  340.             if (=== \count($usedEnvs)) {
  341.                 $baseUrl $this->prefixSchema($baseUrl);
  342.                 $this->validateUrl($baseUrl'Not a valid base path: "%s"');
  343.             }
  344.         } else {
  345.             $baseUrl null;
  346.         }
  347.         $httpClient null;
  348.         if ($config['http_client']) {
  349.             $httpClient = new Reference($config['http_client']);
  350.         }
  351.         $definition = new Definition(HttpDispatcher::class, [
  352.             $config['servers'],
  353.             $baseUrl,
  354.             $httpClient,
  355.         ]);
  356.         $container->setDefinition($serviceName$definition);
  357.     }
  358.     private function loadVarnish(ContainerBuilder $containerXmlFileLoader $loader, array $config)
  359.     {
  360.         $this->createHttpDispatcherDefinition($container$config['http'], 'fos_http_cache.proxy_client.varnish.http_dispatcher');
  361.         $options = [
  362.             'tag_mode' => $config['tag_mode'],
  363.             'tags_header' => $config['tags_header'],
  364.         ];
  365.         if (!empty($config['header_length'])) {
  366.             $options['header_length'] = $config['header_length'];
  367.         }
  368.         if (!empty($config['default_ban_headers'])) {
  369.             $options['default_ban_headers'] = $config['default_ban_headers'];
  370.         }
  371.         $container->setParameter('fos_http_cache.proxy_client.varnish.options'$options);
  372.         $loader->load('varnish.xml');
  373.     }
  374.     private function loadNginx(ContainerBuilder $containerXmlFileLoader $loader, array $config)
  375.     {
  376.         $this->createHttpDispatcherDefinition($container$config['http'], 'fos_http_cache.proxy_client.nginx.http_dispatcher');
  377.         $container->setParameter('fos_http_cache.proxy_client.nginx.options', [
  378.             'purge_location' => $config['purge_location'],
  379.         ]);
  380.         $loader->load('nginx.xml');
  381.     }
  382.     private function loadSymfony(ContainerBuilder $containerXmlFileLoader $loader, array $config)
  383.     {
  384.         $serviceName 'fos_http_cache.proxy_client.symfony.http_dispatcher';
  385.         if ($config['use_kernel_dispatcher']) {
  386.             $definition = new Definition(KernelDispatcher::class, [
  387.                 new Reference('kernel'),
  388.             ]);
  389.             $container->setDefinition($serviceName$definition);
  390.         } else {
  391.             $this->createHttpDispatcherDefinition($container$config['http'], $serviceName);
  392.         }
  393.         $options = [
  394.             'tags_header' => $config['tags_header'],
  395.             'tags_method' => $config['tags_method'],
  396.             'purge_method' => $config['purge_method'],
  397.         ];
  398.         if (!empty($config['header_length'])) {
  399.             $options['header_length'] = $config['header_length'];
  400.         }
  401.         $container->setParameter('fos_http_cache.proxy_client.symfony.options'$options);
  402.         $loader->load('symfony.xml');
  403.     }
  404.     /**
  405.      * @param array  $config Configuration section for the tags node
  406.      * @param string $client Name of the client used with the cache manager,
  407.      *                       "custom" when a custom client is used
  408.      */
  409.     private function loadCacheTagging(ContainerBuilder $containerXmlFileLoader $loader, array $config$client)
  410.     {
  411.         if ('auto' === $config['enabled'] && !in_array($client, ['varnish''symfony'])) {
  412.             $container->setParameter('fos_http_cache.compiler_pass.tag_annotations'false);
  413.             return;
  414.         }
  415.         if (!in_array($client, ['varnish''symfony''custom''noop'])) {
  416.             throw new InvalidConfigurationException(sprintf('You can not enable cache tagging with the %s client'$client));
  417.         }
  418.         $container->setParameter('fos_http_cache.compiler_pass.tag_annotations'$config['annotations']['enabled']);
  419.         $container->setParameter('fos_http_cache.tag_handler.response_header'$config['response_header']);
  420.         $container->setParameter('fos_http_cache.tag_handler.separator'$config['separator']);
  421.         $container->setParameter('fos_http_cache.tag_handler.strict'$config['strict']);
  422.         $loader->load('cache_tagging.xml');
  423.         if (class_exists(Application::class)) {
  424.             $loader->load('cache_tagging_commands.xml');
  425.         }
  426.         if (!empty($config['expression_language'])) {
  427.             $container->setAlias(
  428.                 'fos_http_cache.tag_handler.expression_language',
  429.                 $config['expression_language']
  430.             );
  431.         }
  432.         if (!empty($config['rules'])) {
  433.             $this->loadTagRules($container$config['rules']);
  434.         }
  435.         if (null !== $config['max_header_value_length']) {
  436.             $container->register('fos_http_cache.tag_handler.max_header_value_length_header_formatter'MaxHeaderValueLengthFormatter::class)
  437.                 ->setDecoratedService('fos_http_cache.tag_handler.header_formatter')
  438.                 ->addArgument(new Reference('fos_http_cache.tag_handler.max_header_value_length_header_formatter.inner'))
  439.                 ->addArgument((int) $config['max_header_value_length']);
  440.         }
  441.     }
  442.     private function loadTest(ContainerBuilder $containerXmlFileLoader $loader, array $config)
  443.     {
  444.         $container->setParameter('fos_http_cache.test.cache_header'$config['cache_header']);
  445.         if ($config['proxy_server']) {
  446.             $this->loadProxyServer($container$loader$config['proxy_server']);
  447.         }
  448.     }
  449.     private function loadProxyServer(ContainerBuilder $containerXmlFileLoader $loader, array $config)
  450.     {
  451.         if (isset($config['varnish'])) {
  452.             $this->loadVarnishProxyServer($container$loader$config['varnish']);
  453.         }
  454.         if (isset($config['nginx'])) {
  455.             $this->loadNginxProxyServer($container$loader$config['nginx']);
  456.         }
  457.         $container->setAlias(
  458.             'fos_http_cache.test.default_proxy_server',
  459.             'fos_http_cache.test.proxy_server.'.$this->getDefaultProxyClient($config)
  460.         );
  461.     }
  462.     private function loadVarnishProxyServer(ContainerBuilder $containerXmlFileLoader $loader$config)
  463.     {
  464.         $loader->load('varnish_proxy.xml');
  465.         foreach ($config as $key => $value) {
  466.             $container->setParameter(
  467.                 'fos_http_cache.test.proxy_server.varnish.'.$key,
  468.                 $value
  469.             );
  470.         }
  471.     }
  472.     private function loadNginxProxyServer(ContainerBuilder $containerXmlFileLoader $loader$config)
  473.     {
  474.         $loader->load('nginx_proxy.xml');
  475.         foreach ($config as $key => $value) {
  476.             $container->setParameter(
  477.                 'fos_http_cache.test.proxy_server.nginx.'.$key,
  478.                 $value
  479.             );
  480.         }
  481.     }
  482.     private function loadTagRules(ContainerBuilder $container, array $config)
  483.     {
  484.         $tagDefinition $container->getDefinition('fos_http_cache.event_listener.tag');
  485.         foreach ($config as $rule) {
  486.             $ruleMatcher $this->parseRequestMatcher($container$rule['match']);
  487.             $tags = [
  488.                 'tags' => $rule['tags'],
  489.                 'expressions' => $rule['tag_expressions'],
  490.             ];
  491.             $tagDefinition->addMethodCall('addRule', [$ruleMatcher$tags]);
  492.         }
  493.     }
  494.     private function loadInvalidatorRules(ContainerBuilder $container, array $config)
  495.     {
  496.         $tagDefinition $container->getDefinition('fos_http_cache.event_listener.invalidation');
  497.         foreach ($config as $rule) {
  498.             $ruleMatcher $this->parseRequestMatcher($container$rule['match']);
  499.             $tagDefinition->addMethodCall('addRule', [$ruleMatcher$rule['routes']]);
  500.         }
  501.     }
  502.     private function validateUrl($url$msg)
  503.     {
  504.         $prefixed $this->prefixSchema($url);
  505.         if (!$parts parse_url($prefixed)) {
  506.             throw new InvalidConfigurationException(sprintf($msg$url));
  507.         }
  508.     }
  509.     private function prefixSchema($url)
  510.     {
  511.         if (false === strpos($url'://')) {
  512.             $url sprintf('%s://%s''http'$url);
  513.         }
  514.         return $url;
  515.     }
  516.     private function getDefaultProxyClient(array $config)
  517.     {
  518.         if (isset($config['default'])) {
  519.             return $config['default'];
  520.         }
  521.         if (isset($config['varnish'])) {
  522.             return 'varnish';
  523.         }
  524.         if (isset($config['nginx'])) {
  525.             return 'nginx';
  526.         }
  527.         if (isset($config['symfony'])) {
  528.             return 'symfony';
  529.         }
  530.         if (isset($config['noop'])) {
  531.             return 'noop';
  532.         }
  533.         throw new InvalidConfigurationException('No proxy client configured');
  534.     }
  535.     /**
  536.      * Build the child definition with fallback for Symfony versions < 3.3.
  537.      *
  538.      * @param string $id Id of the service to extend
  539.      *
  540.      * @return ChildDefinition|DefinitionDecorator
  541.      */
  542.     private function createChildDefinition($id)
  543.     {
  544.         if (class_exists(ChildDefinition::class)) {
  545.             return new ChildDefinition($id);
  546.         }
  547.         return new DefinitionDecorator($id);
  548.     }
  549. }