From 7fd0d0ab7611a018f29574a7999c4a1d8b2b94d1 Mon Sep 17 00:00:00 2001 From: Mponos George Date: Fri, 27 Dec 2019 11:55:05 +0200 Subject: [PATCH 1/5] Declare strict types --- src/ClientFactory/AutoDiscoveryFactory.php | 2 + src/ClientFactory/BuzzFactory.php | 15 +- src/ClientFactory/ClientFactory.php | 4 +- src/ClientFactory/CurlFactory.php | 6 +- src/ClientFactory/DummyClient.php | 2 + src/ClientFactory/Guzzle5Factory.php | 5 +- src/ClientFactory/Guzzle6Factory.php | 2 + src/ClientFactory/MockFactory.php | 2 + src/ClientFactory/PluginClientFactory.php | 2 + src/ClientFactory/ReactFactory.php | 5 +- src/ClientFactory/SocketFactory.php | 5 +- src/Collector/Collector.php | 15 +- src/Collector/Formatter.php | 10 +- src/Collector/PluginClientFactory.php | 15 +- src/Collector/PluginClientFactoryListener.php | 5 +- src/Collector/Profile.php | 2 + src/Collector/ProfileClient.php | 25 +- src/Collector/ProfileClientFactory.php | 5 +- src/Collector/ProfilePlugin.php | 24 +- src/Collector/Stack.php | 5 +- src/Collector/StackPlugin.php | 6 +- .../Twig/HttpMessageMarkupExtension.php | 2 + src/DependencyInjection/Configuration.php | 1058 ++++++++--------- src/DependencyInjection/HttplugExtension.php | 59 +- src/Discovery/ConfiguredClientsStrategy.php | 4 +- src/HttplugBundle.php | 2 + tests/Functional/DiscoveredClientsTest.php | 4 +- tests/Functional/DiscoveryTest.php | 4 +- tests/Functional/ProfilerTest.php | 2 + tests/Functional/ProfilingTest.php | 2 + tests/Functional/ServiceInstantiationTest.php | 2 + tests/Unit/ClientFactory/BuzzFactoryTest.php | 2 + tests/Unit/ClientFactory/CurlFactoryTest.php | 4 +- .../Unit/ClientFactory/Guzzle6FactoryTest.php | 4 +- tests/Unit/ClientFactory/MockFactoryTest.php | 2 + tests/Unit/ClientFactory/ReactFactoryTest.php | 2 + .../Unit/ClientFactory/SocketFactoryTest.php | 2 + tests/Unit/Collector/CollectorTest.php | 2 + tests/Unit/Collector/FormatterTest.php | 2 + .../PluginClientFactoryListenerTest.php | 2 + .../Collector/ProfileClientFactoryTest.php | 2 + tests/Unit/Collector/ProfileClientTest.php | 2 + tests/Unit/Collector/ProfilePluginTest.php | 2 + tests/Unit/Collector/StackPluginTest.php | 2 + .../DependencyInjection/ConfigurationTest.php | 8 +- .../HttplugExtensionTest.php | 4 +- .../ConfiguredClientsStrategyTest.php | 2 + 47 files changed, 651 insertions(+), 694 deletions(-) diff --git a/src/ClientFactory/AutoDiscoveryFactory.php b/src/ClientFactory/AutoDiscoveryFactory.php index 78b64f78..1c2bf5b9 100644 --- a/src/ClientFactory/AutoDiscoveryFactory.php +++ b/src/ClientFactory/AutoDiscoveryFactory.php @@ -1,5 +1,7 @@ messageFactory = $messageFactory; @@ -47,18 +46,16 @@ public function createClient(array $config = []) /** * Get options to configure the Buzz client. - * - * @param array $config */ private function getOptions(array $config = []) { $resolver = new OptionsResolver(); $resolver->setDefaults([ - 'timeout' => 5, - 'verify_peer' => true, - 'verify_host' => 2, - 'proxy' => null, + 'timeout' => 5, + 'verify_peer' => true, + 'verify_host' => 2, + 'proxy' => null, ]); $resolver->setAllowedTypes('timeout', 'int'); diff --git a/src/ClientFactory/ClientFactory.php b/src/ClientFactory/ClientFactory.php index 78a67a8a..afae4b7f 100644 --- a/src/ClientFactory/ClientFactory.php +++ b/src/ClientFactory/ClientFactory.php @@ -1,5 +1,7 @@ responseFactory = $responseFactory; diff --git a/src/ClientFactory/DummyClient.php b/src/ClientFactory/DummyClient.php index 2fd6f1c4..09665e5e 100644 --- a/src/ClientFactory/DummyClient.php +++ b/src/ClientFactory/DummyClient.php @@ -1,5 +1,7 @@ messageFactory = $messageFactory; diff --git a/src/ClientFactory/Guzzle6Factory.php b/src/ClientFactory/Guzzle6Factory.php index 802f9e52..92d9da46 100644 --- a/src/ClientFactory/Guzzle6Factory.php +++ b/src/ClientFactory/Guzzle6Factory.php @@ -1,5 +1,7 @@ messageFactory = $messageFactory; diff --git a/src/ClientFactory/SocketFactory.php b/src/ClientFactory/SocketFactory.php index 58c93fa6..2c3582df 100644 --- a/src/ClientFactory/SocketFactory.php +++ b/src/ClientFactory/SocketFactory.php @@ -1,5 +1,7 @@ messageFactory = $messageFactory; diff --git a/src/Collector/Collector.php b/src/Collector/Collector.php index c274507b..c2a2a642 100644 --- a/src/Collector/Collector.php +++ b/src/Collector/Collector.php @@ -1,11 +1,13 @@ activeStack; } - /** - * @param Stack $stack - */ public function addStack(Stack $stack) { $this->data['stacks'][] = $stack; } /** - * @param Stack $parent - * * @return Stack[] */ public function getChildrenStacks(Stack $parent) @@ -172,8 +165,6 @@ public function countClientMessages($client) /** * Recursively count message in stack. * - * @param Stack $stack - * * @return int */ private function countStackMessages(Stack $stack) diff --git a/src/Collector/Formatter.php b/src/Collector/Formatter.php index e2eb9c12..f4759d36 100644 --- a/src/Collector/Formatter.php +++ b/src/Collector/Formatter.php @@ -1,5 +1,7 @@ formatter = $formatter; @@ -44,8 +42,6 @@ public function __construct(MessageFormatter $formatter, CurlCommandFormatter $c /** * Formats an exception. * - * @param \Throwable $exception - * * @return string */ public function formatException(\Throwable $exception) @@ -80,8 +76,6 @@ public function formatResponse(ResponseInterface $response) /** * Format a RequestInterface as a cURL command. * - * @param RequestInterface $request - * * @return string */ public function formatAsCurlCommand(RequestInterface $request) diff --git a/src/Collector/PluginClientFactory.php b/src/Collector/PluginClientFactory.php index 91c22216..53eb5130 100644 --- a/src/Collector/PluginClientFactory.php +++ b/src/Collector/PluginClientFactory.php @@ -1,5 +1,7 @@ collector = $collector; @@ -51,13 +48,13 @@ public function __construct(Collector $collector, Formatter $formatter, Stopwatc * @param Plugin[] $plugins * @param array $options { * - * @var string $client_name to give client a name which may be used when displaying client information like in - * the HTTPlugBundle profiler. - * } + * @return PluginClient * * @see PluginClient constructor for PluginClient specific $options. * - * @return PluginClient + * @var string $client_name to give client a name which may be used when displaying client information like in + * the HTTPlugBundle profiler. + * } */ public function createClient($client, array $plugins = [], array $options = []) { diff --git a/src/Collector/PluginClientFactoryListener.php b/src/Collector/PluginClientFactoryListener.php index b86a402f..44e0b4e0 100644 --- a/src/Collector/PluginClientFactoryListener.php +++ b/src/Collector/PluginClientFactoryListener.php @@ -1,5 +1,7 @@ factory = $factory; diff --git a/src/Collector/Profile.php b/src/Collector/Profile.php index 5543e216..1240effa 100644 --- a/src/Collector/Profile.php +++ b/src/Collector/Profile.php @@ -1,5 +1,7 @@ setRequestTarget($request->getRequestTarget()); @@ -163,11 +158,6 @@ private function collectRequestInformations(RequestInterface $request, Stack $st $stack->setCurlCommand($this->formatter->formatAsCurlCommand($request)); } - /** - * @param ResponseInterface $response - * @param StopwatchEvent $event - * @param Stack $stack - */ private function collectResponseInformations(ResponseInterface $response, StopwatchEvent $event, Stack $stack) { $stack->setDuration($event->getDuration()); @@ -175,11 +165,6 @@ private function collectResponseInformations(ResponseInterface $response, Stopwa $stack->setClientResponse($this->formatter->formatResponse($response)); } - /** - * @param \Throwable $exception - * @param StopwatchEvent $event - * @param Stack $stack - */ private function collectExceptionInformations(\Throwable $exception, StopwatchEvent $event, Stack $stack) { if ($exception instanceof HttpException) { @@ -193,8 +178,6 @@ private function collectExceptionInformations(\Throwable $exception, StopwatchEv /** * Generates the event name. * - * @param RequestInterface $request - * * @return string */ private function getStopwatchEventName(RequestInterface $request) diff --git a/src/Collector/ProfileClientFactory.php b/src/Collector/ProfileClientFactory.php index e2adffa4..23d17fdc 100644 --- a/src/Collector/ProfileClientFactory.php +++ b/src/Collector/ProfileClientFactory.php @@ -1,5 +1,7 @@ plugin = $plugin; @@ -87,10 +84,7 @@ protected function doHandleRequest(RequestInterface $request, callable $next, ca } /** - * @param RequestInterface $request - * @param Profile $profile - * @param Exception $exception - * @param Stack $stack + * @param Stack $stack */ private function onException( RequestInterface $request, @@ -103,20 +97,13 @@ private function onException( $this->collectRequestInformation($request, $stack); } - /** - * @param RequestInterface $request - * @param Profile $profile - */ private function onOutgoingRequest(RequestInterface $request, Profile $profile) { $profile->setRequest($this->formatter->formatRequest($request)); } /** - * @param ResponseInterface $response - * @param Profile $profile - * @param RequestInterface $request - * @param Stack $stack + * @param Stack $stack */ private function onOutgoingResponse(ResponseInterface $response, Profile $profile, RequestInterface $request, Stack $stack = null) { @@ -127,9 +114,6 @@ private function onOutgoingResponse(ResponseInterface $response, Profile $profil /** * Collect request information when not already done by the HTTP client. This happens when using the CachePlugin * and the cache is hit without re-validation. - * - * @param RequestInterface $request - * @param Stack|null $stack */ private function collectRequestInformation(RequestInterface $request, Stack $stack = null) { diff --git a/src/Collector/Stack.php b/src/Collector/Stack.php index 755e9487..9ce09682 100644 --- a/src/Collector/Stack.php +++ b/src/Collector/Stack.php @@ -1,5 +1,7 @@ parent = $parent; } - /** - * @param Profile $profile - */ public function addProfile(Profile $profile) { $this->profiles[] = $profile; diff --git a/src/Collector/StackPlugin.php b/src/Collector/StackPlugin.php index 0bb527d5..cb423b61 100644 --- a/src/Collector/StackPlugin.php +++ b/src/Collector/StackPlugin.php @@ -1,5 +1,7 @@ validate() - ->ifTrue(function ($v) { - return !empty($v['classes']['client']) - || !empty($v['classes']['message_factory']) - || !empty($v['classes']['uri_factory']) - || !empty($v['classes']['stream_factory']); - }) - ->then(function ($v) { - foreach ($v['classes'] as $key => $class) { - if (null !== $class && !class_exists($class)) { - throw new InvalidConfigurationException(sprintf( - 'Class %s specified for httplug.classes.%s does not exist.', - $class, - $key - )); - } + ->ifTrue(function ($v) { + return !empty($v['classes']['client']) + || !empty($v['classes']['message_factory']) + || !empty($v['classes']['uri_factory']) + || !empty($v['classes']['stream_factory']); + }) + ->then(function ($v) { + foreach ($v['classes'] as $key => $class) { + if (null !== $class && !class_exists($class)) { + throw new InvalidConfigurationException(sprintf('Class %s specified for httplug.classes.%s does not exist.', $class, $key)); } + } - return $v; - }) + return $v; + }) ->end() ->beforeNormalization() - ->ifTrue(function ($v) { - return is_array($v) && array_key_exists('toolbar', $v) && is_array($v['toolbar']); - }) - ->then(function ($v) { - if (array_key_exists('profiling', $v)) { - throw new InvalidConfigurationException('Can\'t configure both "toolbar" and "profiling" section. The "toolbar" config is deprecated as of version 1.3.0, please only use "profiling".'); - } + ->ifTrue(function ($v) { + return is_array($v) && array_key_exists('toolbar', $v) && is_array($v['toolbar']); + }) + ->then(function ($v) { + if (array_key_exists('profiling', $v)) { + throw new InvalidConfigurationException('Can\'t configure both "toolbar" and "profiling" section. The "toolbar" config is deprecated as of version 1.3.0, please only use "profiling".'); + } - @trigger_error('"httplug.toolbar" config is deprecated since version 1.3 and will be removed in 2.0. Use "httplug.profiling" instead.', E_USER_DEPRECATED); + @trigger_error('"httplug.toolbar" config is deprecated since version 1.3 and will be removed in 2.0. Use "httplug.profiling" instead.', E_USER_DEPRECATED); - if (array_key_exists('enabled', $v['toolbar']) && 'auto' === $v['toolbar']['enabled']) { - @trigger_error('"auto" value in "httplug.toolbar" config is deprecated since version 1.3 and will be removed in 2.0. Use a boolean value instead.', E_USER_DEPRECATED); - $v['toolbar']['enabled'] = $this->debug; - } + if (array_key_exists('enabled', $v['toolbar']) && 'auto' === $v['toolbar']['enabled']) { + @trigger_error('"auto" value in "httplug.toolbar" config is deprecated since version 1.3 and will be removed in 2.0. Use a boolean value instead.', E_USER_DEPRECATED); + $v['toolbar']['enabled'] = $this->debug; + } - $v['profiling'] = $v['toolbar']; + $v['profiling'] = $v['toolbar']; - unset($v['toolbar']); + unset($v['toolbar']); - return $v; - }) + return $v; + }) ->end() ->fixXmlConfig('client') ->children() - ->booleanNode('default_client_autowiring') - ->defaultTrue() - ->info('Set to false to not autowire HttpClient and HttpAsyncClient.') - ->end() - ->arrayNode('main_alias') - ->addDefaultsIfNotSet() - ->info('Configure which service the main alias point to.') - ->children() - ->scalarNode('client')->defaultValue('httplug.client.default')->end() - ->scalarNode('message_factory')->defaultValue('httplug.message_factory.default')->end() - ->scalarNode('uri_factory')->defaultValue('httplug.uri_factory.default')->end() - ->scalarNode('stream_factory')->defaultValue('httplug.stream_factory.default')->end() - ->end() - ->end() - ->arrayNode('classes') - ->addDefaultsIfNotSet() - ->info('Overwrite a service class instead of using the discovery mechanism.') - ->children() - ->scalarNode('client')->defaultNull()->end() - ->scalarNode('message_factory')->defaultNull()->end() - ->scalarNode('uri_factory')->defaultNull()->end() - ->scalarNode('stream_factory')->defaultNull()->end() - ->end() - ->end() - ->arrayNode('profiling') - ->addDefaultsIfNotSet() - ->treatFalseLike(['enabled' => false]) - ->treatTrueLike(['enabled' => true]) - ->treatNullLike(['enabled' => $this->debug]) - ->info('Extend the debug profiler with information about requests.') - ->children() - ->booleanNode('enabled') - ->info('Turn the toolbar on or off. Defaults to kernel debug mode.') - ->defaultValue($this->debug) - ->end() - ->scalarNode('formatter')->defaultNull()->end() - ->scalarNode('captured_body_length') - ->validate() - ->ifTrue(function ($v) { - return null !== $v && !is_int($v); - }) - ->thenInvalid('The child node "captured_body_length" at path "httplug.profiling" must be an integer or null ("%s" given).') - ->end() - ->defaultValue(0) - ->info('Limit long HTTP message bodies to x characters. If set to 0 we do not read the message body. If null the body will not be truncated. Only available with the default formatter (FullHttpMessageFormatter).') - ->end() - ->end() - ->end() - ->arrayNode('discovery') - ->addDefaultsIfNotSet() - ->info('Control what clients should be found by the discovery.') - ->children() - ->scalarNode('client') - ->defaultValue('auto') - ->info('Set to "auto" to see auto discovered client in the web profiler. If provided a service id for a client then this client will be found by auto discovery.') - ->end() - ->scalarNode('async_client') - ->defaultNull() - ->info('Set to "auto" to see auto discovered client in the web profiler. If provided a service id for a client then this client will be found by auto discovery.') - ->end() - ->end() - ->end() + ->booleanNode('default_client_autowiring') + ->defaultTrue() + ->info('Set to false to not autowire HttpClient and HttpAsyncClient.') + ->end() + ->arrayNode('main_alias') + ->addDefaultsIfNotSet() + ->info('Configure which service the main alias point to.') + ->children() + ->scalarNode('client')->defaultValue('httplug.client.default')->end() + ->scalarNode('message_factory')->defaultValue('httplug.message_factory.default')->end() + ->scalarNode('uri_factory')->defaultValue('httplug.uri_factory.default')->end() + ->scalarNode('stream_factory')->defaultValue('httplug.stream_factory.default')->end() + ->end() + ->end() + ->arrayNode('classes') + ->addDefaultsIfNotSet() + ->info('Overwrite a service class instead of using the discovery mechanism.') + ->children() + ->scalarNode('client')->defaultNull()->end() + ->scalarNode('message_factory')->defaultNull()->end() + ->scalarNode('uri_factory')->defaultNull()->end() + ->scalarNode('stream_factory')->defaultNull()->end() + ->end() + ->end() + ->arrayNode('profiling') + ->addDefaultsIfNotSet() + ->treatFalseLike(['enabled' => false]) + ->treatTrueLike(['enabled' => true]) + ->treatNullLike(['enabled' => $this->debug]) + ->info('Extend the debug profiler with information about requests.') + ->children() + ->booleanNode('enabled') + ->info('Turn the toolbar on or off. Defaults to kernel debug mode.') + ->defaultValue($this->debug) + ->end() + ->scalarNode('formatter')->defaultNull()->end() + ->scalarNode('captured_body_length') + ->validate() + ->ifTrue(function ($v) { + return null !== $v && !is_int($v); + }) + ->thenInvalid('The child node "captured_body_length" at path "httplug.profiling" must be an integer or null ("%s" given).') + ->end() + ->defaultValue(0) + ->info('Limit long HTTP message bodies to x characters. If set to 0 we do not read the message body. If null the body will not be truncated. Only available with the default formatter (FullHttpMessageFormatter).') + ->end() + ->end() + ->end() + ->arrayNode('discovery') + ->addDefaultsIfNotSet() + ->info('Control what clients should be found by the discovery.') + ->children() + ->scalarNode('client') + ->defaultValue('auto') + ->info('Set to "auto" to see auto discovered client in the web profiler. If provided a service id for a client then this client will be found by auto discovery.') + ->end() + ->scalarNode('async_client') + ->defaultNull() + ->info('Set to "auto" to see auto discovered client in the web profiler. If provided a service id for a client then this client will be found by auto discovery.') + ->end() + ->end() + ->end() ->end(); return $treeBuilder; @@ -182,72 +180,68 @@ private function configureClients(ArrayNodeDefinition $root) { $root->children() ->arrayNode('clients') - ->useAttributeAsKey('name') - ->prototype('array') - ->fixXmlConfig('plugin') - ->validate() - ->ifTrue(function ($config) { - // Make sure we only allow one of these to be true - return (bool) $config['flexible_client'] + (bool) $config['http_methods_client'] + (bool) $config['batch_client'] >= 2; - }) - ->thenInvalid('A http client can\'t be decorated with several of FlexibleHttpClient, HttpMethodsClient and BatchClient. Only one of the following options can be true. ("flexible_client", "http_methods_client", "batch_client")') - ->end() - ->validate() - ->ifTrue(function ($config) { - return 'httplug.factory.auto' === $config['factory'] && !empty($config['config']); - }) - ->thenInvalid('If you want to use the "config" key you must also specify a valid "factory".') - ->end() - ->validate() - ->ifTrue(function ($config) { - return !empty($config['service']) && ('httplug.factory.auto' !== $config['factory'] || !empty($config['config'])); - }) - ->thenInvalid('If you want to use the "service" key you cannot specify "factory" or "config".') - ->end() - ->children() - ->scalarNode('factory') - ->defaultValue('httplug.factory.auto') - ->cannotBeEmpty() - ->info('The service id of a factory to use when creating the adapter.') - ->end() - ->scalarNode('service') - ->defaultNull() - ->info('The service id of the client to use.') - ->end() - ->booleanNode('public') - ->defaultNull() - ->info('Set to true if you really cannot use dependency injection and need to make the client service public.') - ->end() - ->booleanNode('flexible_client') - ->defaultFalse() - ->info('Set to true to get the client wrapped in a FlexibleHttpClient which emulates async or sync behavior.') - ->end() - ->booleanNode('http_methods_client') - ->defaultFalse() - ->info('Set to true to get the client wrapped in a HttpMethodsClient which emulates provides functions for HTTP verbs.') - ->end() - ->booleanNode('batch_client') - ->defaultFalse() - ->info('Set to true to get the client wrapped in a BatchClient which allows you to send multiple request at the same time.') - ->end() - ->variableNode('config')->defaultValue([])->end() - ->append($this->createClientPluginNode()) - ->end() - ->end() - ->end(); + ->useAttributeAsKey('name') + ->prototype('array') + ->fixXmlConfig('plugin') + ->validate() + ->ifTrue(function ($config) { + // Make sure we only allow one of these to be true + return (bool) $config['flexible_client'] + (bool) $config['http_methods_client'] + (bool) $config['batch_client'] >= 2; + }) + ->thenInvalid('A http client can\'t be decorated with several of FlexibleHttpClient, HttpMethodsClient and BatchClient. Only one of the following options can be true. ("flexible_client", "http_methods_client", "batch_client")') + ->end() + ->validate() + ->ifTrue(function ($config) { + return 'httplug.factory.auto' === $config['factory'] && !empty($config['config']); + }) + ->thenInvalid('If you want to use the "config" key you must also specify a valid "factory".') + ->end() + ->validate() + ->ifTrue(function ($config) { + return !empty($config['service']) && ('httplug.factory.auto' !== $config['factory'] || !empty($config['config'])); + }) + ->thenInvalid('If you want to use the "service" key you cannot specify "factory" or "config".') + ->end() + ->children() + ->scalarNode('factory') + ->defaultValue('httplug.factory.auto') + ->cannotBeEmpty() + ->info('The service id of a factory to use when creating the adapter.') + ->end() + ->scalarNode('service') + ->defaultNull() + ->info('The service id of the client to use.') + ->end() + ->booleanNode('public') + ->defaultNull() + ->info('Set to true if you really cannot use dependency injection and need to make the client service public.') + ->end() + ->booleanNode('flexible_client') + ->defaultFalse() + ->info('Set to true to get the client wrapped in a FlexibleHttpClient which emulates async or sync behavior.') + ->end() + ->booleanNode('http_methods_client') + ->defaultFalse() + ->info('Set to true to get the client wrapped in a HttpMethodsClient which emulates provides functions for HTTP verbs.') + ->end() + ->booleanNode('batch_client') + ->defaultFalse() + ->info('Set to true to get the client wrapped in a BatchClient which allows you to send multiple request at the same time.') + ->end() + ->variableNode('config')->defaultValue([])->end() + ->append($this->createClientPluginNode()) + ->end() + ->end() + ->end(); } - /** - * @param ArrayNodeDefinition $root - */ private function configureSharedPlugins(ArrayNodeDefinition $root) { $pluginsNode = $root ->children() - ->arrayNode('plugins') - ->info('Global plugin configuration. Plugins need to be explicitly added to clients.') - ->addDefaultsIfNotSet() - // don't call end to get the plugins node + ->arrayNode('plugins') + ->info('Global plugin configuration. Plugins need to be explicitly added to clients.') + ->addDefaultsIfNotSet()// don't call end to get the plugins node ; $this->addSharedPluginNodes($pluginsNode); } @@ -270,222 +264,219 @@ private function createClientPluginNode() /** @var ArrayNodeDefinition $pluginList */ $pluginList = $node ->info('A list of plugin service ids and client specific plugin definitions. The order is important.') - ->prototype('array') - ; + ->prototype('array'); $pluginList // support having just a service id in the list ->beforeNormalization() - ->always(function ($plugin) { - if (is_string($plugin)) { - return [ - 'reference' => [ - 'enabled' => true, - 'id' => $plugin, - ], - ]; - } - - return $plugin; - }) + ->always(function ($plugin) { + if (is_string($plugin)) { + return [ + 'reference' => [ + 'enabled' => true, + 'id' => $plugin, + ], + ]; + } + + return $plugin; + }) ->end() - ->validate() - ->always(function ($plugins) { - foreach ($plugins as $name => $definition) { - if ('authentication' === $name) { - if (!count($definition)) { - unset($plugins['authentication']); - } - } elseif (!$definition['enabled']) { - unset($plugins[$name]); + ->always(function ($plugins) { + foreach ($plugins as $name => $definition) { + if ('authentication' === $name) { + if (!count($definition)) { + unset($plugins['authentication']); } + } elseif (!$definition['enabled']) { + unset($plugins[$name]); } + } - return $plugins; - }) - ->end() - ; + return $plugins; + }) + ->end(); $this->addSharedPluginNodes($pluginList, true); $pluginList ->children() - ->arrayNode('reference') - ->canBeEnabled() - ->info('Reference to a plugin service') - ->children() - ->scalarNode('id') - ->info('Service id of a plugin') - ->isRequired() - ->cannotBeEmpty() - ->end() - ->end() - ->end() - ->arrayNode('add_host') - ->canBeEnabled() - ->addDefaultsIfNotSet() - ->info('Set scheme, host and port in the request URI.') - ->children() - ->scalarNode('host') - ->info('Host name including protocol and optionally the port number, e.g. https://api.local:8000') - ->isRequired() - ->cannotBeEmpty() - ->end() - ->scalarNode('replace') - ->info('Whether to replace the host if request already specifies one') - ->defaultValue(false) - ->end() - ->end() - ->end() - ->arrayNode('add_path') - ->canBeEnabled() - ->addDefaultsIfNotSet() - ->info('Add a base path to the request.') - ->children() - ->scalarNode('path') - ->info('Path to be added, e.g. /api/v1') - ->isRequired() - ->cannotBeEmpty() - ->end() - ->end() - ->end() - ->arrayNode('base_uri') - ->canBeEnabled() - ->addDefaultsIfNotSet() - ->info('Set a base URI to the request.') - ->children() - ->scalarNode('uri') - ->info('Base Uri including protocol, optionally the port number and prepend path, e.g. https://api.local:8000/api') - ->isRequired() - ->cannotBeEmpty() - ->end() - ->scalarNode('replace') - ->info('Whether to replace the host if request already specifies one') - ->defaultValue(false) - ->end() - ->end() - ->end() - ->arrayNode('content_type') - ->canBeEnabled() - ->info('Detect the content type of a request body and set the Content-Type header if it is not already set.') - ->children() - ->booleanNode('skip_detection') - ->info('Whether to skip detection when request body is larger than size_limit') - ->defaultFalse() - ->end() - ->scalarNode('size_limit') - ->info('Skip content type detection if request body is larger than size_limit bytes') - ->end() - ->end() - ->end() - ->arrayNode('header_append') - ->canBeEnabled() - ->info('Append headers to the request. If the header already exists the value will be appended to the current value.') - ->fixXmlConfig('header') - ->children() - ->arrayNode('headers') - ->info('Keys are the header names, values the header values') - ->normalizeKeys(false) - ->useAttributeAsKey('name') - ->prototype('scalar')->end() - ->end() - ->end() - ->end() - ->arrayNode('header_defaults') - ->canBeEnabled() - ->info('Set header to default value if it does not exist.') - ->fixXmlConfig('header') - ->children() - ->arrayNode('headers') - ->info('Keys are the header names, values the header values') - ->normalizeKeys(false) - ->useAttributeAsKey('name') - ->prototype('scalar')->end() - ->end() - ->end() - ->end() - ->arrayNode('header_set') - ->canBeEnabled() - ->info('Set headers to requests. If the header does not exist it wil be set, if the header already exists it will be replaced.') - ->fixXmlConfig('header') - ->children() - ->arrayNode('headers') - ->info('Keys are the header names, values the header values') - ->normalizeKeys(false) - ->useAttributeAsKey('name') - ->prototype('scalar')->end() - ->end() - ->end() - ->end() - ->arrayNode('header_remove') - ->canBeEnabled() - ->info('Remove headers from requests.') - ->fixXmlConfig('header') - ->children() - ->arrayNode('headers') - ->info('List of header names to remove') - ->prototype('scalar')->end() - ->end() - ->end() - ->end() - ->arrayNode('query_defaults') - ->canBeEnabled() - ->info('Sets query parameters to default value if they are not present in the request.') - ->fixXmlConfig('parameter') - ->children() - ->arrayNode('parameters') - ->info('List of query parameters. Names and values must not be url encoded as the plugin will encode them.') - ->normalizeKeys(false) - ->useAttributeAsKey('name') - ->prototype('scalar')->end() - ->end() - ->end() - ->end() - ->arrayNode('vcr') - ->canBeEnabled() - ->addDefaultsIfNotSet() - ->info('Record response to be replayed during tests or development cycle.') - ->validate() - ->ifTrue(function ($config) { - return 'filesystem' === $config['recorder'] && empty($config['fixtures_directory']); - }) - ->thenInvalid('If you want to use the "filesystem" recorder you must also specify a "fixtures_directory".') - ->end() - ->children() - ->enumNode('mode') - ->info('What should be the behavior of the plugin?') - ->values(['record', 'replay', 'replay_or_record']) - ->isRequired() - ->cannotBeEmpty() - ->end() - ->scalarNode('recorder') - ->info(sprintf('Which recorder to use. Can be "in_memory", "filesystem" or the ID of your service implementing %s and %s. When using filesystem, specify "fixtures_directory" as well.', RecorderInterface::class, PlayerInterface::class)) - ->defaultValue('filesystem') - ->cannotBeEmpty() - ->end() - ->scalarNode('naming_strategy') - ->info(sprintf('Which naming strategy to use. Add the ID of your service implementing %s to override the default one.', NamingStrategyInterface::class)) - ->defaultValue('default') - ->cannotBeEmpty() - ->end() - ->arrayNode('naming_strategy_options') - ->info('See http://docs.php-http.org/en/latest/plugins/vcr.html#the-naming-strategy for more details') - ->children() - ->arrayNode('hash_headers') - ->info('List of header(s) that make the request unique (Ex: ‘Authorization’)') - ->prototype('scalar')->end() - ->end() - ->arrayNode('hash_body_methods') - ->info('for which request methods the body makes requests distinct.') - ->prototype('scalar')->end() - ->end() - ->end() - ->end() // End naming_strategy_options - ->scalarNode('fixtures_directory') - ->info('Where the responses will be stored and replay from when using the filesystem recorder. Should be accessible to your VCS.') - ->end() - ->end() - ->end() - ->end(); + ->arrayNode('reference') + ->canBeEnabled() + ->info('Reference to a plugin service') + ->children() + ->scalarNode('id') + ->info('Service id of a plugin') + ->isRequired() + ->cannotBeEmpty() + ->end() + ->end() + ->end() + ->arrayNode('add_host') + ->canBeEnabled() + ->addDefaultsIfNotSet() + ->info('Set scheme, host and port in the request URI.') + ->children() + ->scalarNode('host') + ->info('Host name including protocol and optionally the port number, e.g. https://api.local:8000') + ->isRequired() + ->cannotBeEmpty() + ->end() + ->scalarNode('replace') + ->info('Whether to replace the host if request already specifies one') + ->defaultValue(false) + ->end() + ->end() + ->end() + ->arrayNode('add_path') + ->canBeEnabled() + ->addDefaultsIfNotSet() + ->info('Add a base path to the request.') + ->children() + ->scalarNode('path') + ->info('Path to be added, e.g. /api/v1') + ->isRequired() + ->cannotBeEmpty() + ->end() + ->end() + ->end() + ->arrayNode('base_uri') + ->canBeEnabled() + ->addDefaultsIfNotSet() + ->info('Set a base URI to the request.') + ->children() + ->scalarNode('uri') + ->info('Base Uri including protocol, optionally the port number and prepend path, e.g. https://api.local:8000/api') + ->isRequired() + ->cannotBeEmpty() + ->end() + ->scalarNode('replace') + ->info('Whether to replace the host if request already specifies one') + ->defaultValue(false) + ->end() + ->end() + ->end() + ->arrayNode('content_type') + ->canBeEnabled() + ->info('Detect the content type of a request body and set the Content-Type header if it is not already set.') + ->children() + ->booleanNode('skip_detection') + ->info('Whether to skip detection when request body is larger than size_limit') + ->defaultFalse() + ->end() + ->scalarNode('size_limit') + ->info('Skip content type detection if request body is larger than size_limit bytes') + ->end() + ->end() + ->end() + ->arrayNode('header_append') + ->canBeEnabled() + ->info('Append headers to the request. If the header already exists the value will be appended to the current value.') + ->fixXmlConfig('header') + ->children() + ->arrayNode('headers') + ->info('Keys are the header names, values the header values') + ->normalizeKeys(false) + ->useAttributeAsKey('name') + ->prototype('scalar')->end() + ->end() + ->end() + ->end() + ->arrayNode('header_defaults') + ->canBeEnabled() + ->info('Set header to default value if it does not exist.') + ->fixXmlConfig('header') + ->children() + ->arrayNode('headers') + ->info('Keys are the header names, values the header values') + ->normalizeKeys(false) + ->useAttributeAsKey('name') + ->prototype('scalar')->end() + ->end() + ->end() + ->end() + ->arrayNode('header_set') + ->canBeEnabled() + ->info('Set headers to requests. If the header does not exist it wil be set, if the header already exists it will be replaced.') + ->fixXmlConfig('header') + ->children() + ->arrayNode('headers') + ->info('Keys are the header names, values the header values') + ->normalizeKeys(false) + ->useAttributeAsKey('name') + ->prototype('scalar')->end() + ->end() + ->end() + ->end() + ->arrayNode('header_remove') + ->canBeEnabled() + ->info('Remove headers from requests.') + ->fixXmlConfig('header') + ->children() + ->arrayNode('headers') + ->info('List of header names to remove') + ->prototype('scalar')->end() + ->end() + ->end() + ->end() + ->arrayNode('query_defaults') + ->canBeEnabled() + ->info('Sets query parameters to default value if they are not present in the request.') + ->fixXmlConfig('parameter') + ->children() + ->arrayNode('parameters') + ->info('List of query parameters. Names and values must not be url encoded as the plugin will encode them.') + ->normalizeKeys(false) + ->useAttributeAsKey('name') + ->prototype('scalar')->end() + ->end() + ->end() + ->end() + ->arrayNode('vcr') + ->canBeEnabled() + ->addDefaultsIfNotSet() + ->info('Record response to be replayed during tests or development cycle.') + ->validate() + ->ifTrue(function ($config) { + return 'filesystem' === $config['recorder'] && empty($config['fixtures_directory']); + }) + ->thenInvalid('If you want to use the "filesystem" recorder you must also specify a "fixtures_directory".') + ->end() + ->children() + ->enumNode('mode') + ->info('What should be the behavior of the plugin?') + ->values(['record', 'replay', 'replay_or_record']) + ->isRequired() + ->cannotBeEmpty() + ->end() + ->scalarNode('recorder') + ->info(sprintf('Which recorder to use. Can be "in_memory", "filesystem" or the ID of your service implementing %s and %s. When using filesystem, specify "fixtures_directory" as well.', RecorderInterface::class, PlayerInterface::class)) + ->defaultValue('filesystem') + ->cannotBeEmpty() + ->end() + ->scalarNode('naming_strategy') + ->info(sprintf('Which naming strategy to use. Add the ID of your service implementing %s to override the default one.', NamingStrategyInterface::class)) + ->defaultValue('default') + ->cannotBeEmpty() + ->end() + ->arrayNode('naming_strategy_options') + ->info('See http://docs.php-http.org/en/latest/plugins/vcr.html#the-naming-strategy for more details') + ->children() + ->arrayNode('hash_headers') + ->info('List of header(s) that make the request unique (Ex: ‘Authorization’)') + ->prototype('scalar')->end() + ->end() + ->arrayNode('hash_body_methods') + ->info('for which request methods the body makes requests distinct.') + ->prototype('scalar')->end() + ->end() + ->end() + ->end() // End naming_strategy_options + ->scalarNode('fixtures_directory') + ->info('Where the responses will be stored and replay from when using the filesystem recorder. Should be accessible to your VCS.') + ->end() + ->end() + ->end() + ->end(); return $node; } @@ -505,27 +496,27 @@ private function addSharedPluginNodes(ArrayNodeDefinition $pluginNode, $disableA $children ->arrayNode('cookie') - ->canBeEnabled() - ->children() - ->scalarNode('cookie_jar') - ->info('This must be a service id to a service implementing '.CookieJar::class) - ->isRequired() - ->cannotBeEmpty() - ->end() - ->end() + ->canBeEnabled() + ->children() + ->scalarNode('cookie_jar') + ->info('This must be a service id to a service implementing '.CookieJar::class) + ->isRequired() + ->cannotBeEmpty() + ->end() + ->end() ->end(); // End cookie plugin $children ->arrayNode('history') - ->canBeEnabled() - ->children() - ->scalarNode('journal') - ->info('This must be a service id to a service implementing '.Journal::class) - ->isRequired() - ->cannotBeEmpty() - ->end() - ->end() + ->canBeEnabled() + ->children() + ->scalarNode('journal') + ->info('This must be a service id to a service implementing '.Journal::class) + ->isRequired() + ->cannotBeEmpty() + ->end() + ->end() ->end(); // End history plugin @@ -533,58 +524,58 @@ private function addSharedPluginNodes(ArrayNodeDefinition $pluginNode, $disableA $disableAll ? $decoder->canBeEnabled() : $decoder->canBeDisabled(); $decoder->addDefaultsIfNotSet() ->children() - ->scalarNode('use_content_encoding')->defaultTrue()->end() + ->scalarNode('use_content_encoding')->defaultTrue()->end() ->end() - ->end(); + ->end(); // End decoder plugin $logger = $children->arrayNode('logger'); $disableAll ? $logger->canBeEnabled() : $logger->canBeDisabled(); $logger->addDefaultsIfNotSet() ->children() - ->scalarNode('logger') - ->info('This must be a service id to a service implementing '.LoggerInterface::class) - ->defaultValue('logger') - ->cannotBeEmpty() - ->end() - ->scalarNode('formatter') - ->info('This must be a service id to a service implementing '.Formatter::class) - ->defaultNull() - ->end() - ->end() - ->end(); + ->scalarNode('logger') + ->info('This must be a service id to a service implementing '.LoggerInterface::class) + ->defaultValue('logger') + ->cannotBeEmpty() + ->end() + ->scalarNode('formatter') + ->info('This must be a service id to a service implementing '.Formatter::class) + ->defaultNull() + ->end() + ->end() + ->end(); // End logger plugin $redirect = $children->arrayNode('redirect'); $disableAll ? $redirect->canBeEnabled() : $redirect->canBeDisabled(); $redirect->addDefaultsIfNotSet() ->children() - ->scalarNode('preserve_header')->defaultTrue()->end() - ->scalarNode('use_default_for_multiple')->defaultTrue()->end() + ->scalarNode('preserve_header')->defaultTrue()->end() + ->scalarNode('use_default_for_multiple')->defaultTrue()->end() ->end() - ->end(); + ->end(); // End redirect plugin $retry = $children->arrayNode('retry'); $disableAll ? $retry->canBeEnabled() : $retry->canBeDisabled(); $retry->addDefaultsIfNotSet() ->children() - ->scalarNode('retry')->defaultValue(1)->end() // TODO: should be called retries for consistency with the class + ->scalarNode('retry')->defaultValue(1)->end() // TODO: should be called retries for consistency with the class ->end() - ->end(); + ->end(); // End retry plugin $stopwatch = $children->arrayNode('stopwatch'); $disableAll ? $stopwatch->canBeEnabled() : $stopwatch->canBeDisabled(); $stopwatch->addDefaultsIfNotSet() ->children() - ->scalarNode('stopwatch') - ->info('This must be a service id to a service extending Symfony\Component\Stopwatch\Stopwatch') - ->defaultValue('debug.stopwatch') - ->cannotBeEmpty() - ->end() + ->scalarNode('stopwatch') + ->info('This must be a service id to a service extending Symfony\Component\Stopwatch\Stopwatch') + ->defaultValue('debug.stopwatch') + ->cannotBeEmpty() + ->end() ->end() - ->end(); + ->end(); // End stopwatch plugin } @@ -606,48 +597,48 @@ private function createAuthenticationPluginNode() $node ->useAttributeAsKey('name') ->prototype('array') - ->validate() - ->always() - ->then(function ($config) { - switch ($config['type']) { - case 'basic': - $this->validateAuthenticationType(['username', 'password'], $config, 'basic'); - - break; - case 'bearer': - $this->validateAuthenticationType(['token'], $config, 'bearer'); - - break; - case 'service': - $this->validateAuthenticationType(['service'], $config, 'service'); - - break; - case 'wsse': - $this->validateAuthenticationType(['username', 'password'], $config, 'wsse'); - - break; - case 'query_param': - $this->validateAuthenticationType(['params'], $config, 'query_param'); - - break; - } + ->validate() + ->always() + ->then(function ($config) { + switch ($config['type']) { + case 'basic': + $this->validateAuthenticationType(['username', 'password'], $config, 'basic'); + + break; + case 'bearer': + $this->validateAuthenticationType(['token'], $config, 'bearer'); + + break; + case 'service': + $this->validateAuthenticationType(['service'], $config, 'service'); + + break; + case 'wsse': + $this->validateAuthenticationType(['username', 'password'], $config, 'wsse'); + + break; + case 'query_param': + $this->validateAuthenticationType(['params'], $config, 'query_param'); - return $config; - }) - ->end() - ->children() - ->enumNode('type') - ->values(['basic', 'bearer', 'wsse', 'service', 'query_param']) - ->isRequired() - ->cannotBeEmpty() - ->end() - ->scalarNode('username')->end() - ->scalarNode('password')->end() - ->scalarNode('token')->end() - ->scalarNode('service')->end() - ->arrayNode('params')->prototype('scalar')->end() - ->end() - ->end() + break; + } + + return $config; + }) + ->end() + ->children() + ->enumNode('type') + ->values(['basic', 'bearer', 'wsse', 'service', 'query_param']) + ->isRequired() + ->cannotBeEmpty() + ->end() + ->scalarNode('username')->end() + ->scalarNode('password')->end() + ->scalarNode('token')->end() + ->scalarNode('service')->end() + ->arrayNode('params')->prototype('scalar')->end() + ->end() + ->end() ->end(); // End authentication plugin return $node; @@ -677,12 +668,7 @@ private function validateAuthenticationType(array $expected, array $actual, $aut return; } - throw new InvalidConfigurationException(sprintf( - 'Authentication "%s" requires %s but got %s', - $authName, - implode(', ', $expected), - implode(', ', $actual) - )); + throw new InvalidConfigurationException(sprintf('Authentication "%s" requires %s but got %s', $authName, implode(', ', $expected), implode(', ', $actual))); } /** @@ -705,83 +691,82 @@ private function createCachePluginNode() ->fixXmlConfig('respect_response_cache_directive') ->addDefaultsIfNotSet() ->validate() - ->ifTrue(function ($config) { - // Cannot set both respect_cache_headers and respect_response_cache_directives - return isset($config['respect_cache_headers'], $config['respect_response_cache_directives']); - }) - ->thenInvalid('You can\'t provide config option "respect_cache_headers" and "respect_response_cache_directives" simultaniously. Use "respect_response_cache_directives" instead.') + ->ifTrue(function ($config) { + // Cannot set both respect_cache_headers and respect_response_cache_directives + return isset($config['respect_cache_headers'], $config['respect_response_cache_directives']); + }) + ->thenInvalid('You can\'t provide config option "respect_cache_headers" and "respect_response_cache_directives" simultaniously. Use "respect_response_cache_directives" instead.') ->end() ->children() - ->scalarNode('cache_key_generator') - ->info('This must be a service id to a service implementing '.CacheKeyGenerator::class) - ->end() - ->integerNode('cache_lifetime') - ->info('The minimum time we should store a cache item') - ->end() - ->integerNode('default_ttl') - ->info('The default max age of a Response') - ->end() - ->arrayNode('blacklisted_paths') - ->info('An array of regular expression patterns for paths not to be cached. Defaults to an empty array.') - ->defaultValue([]) - ->beforeNormalization() - ->castToArray() - ->end() - ->prototype('scalar') - ->validate() - ->ifTrue(function ($v) { - return false === @preg_match($v, ''); - }) - ->thenInvalid('Invalid regular expression for a blacklisted path: %s') - ->end() - ->end() - ->end() - ->enumNode('hash_algo') - ->info('Hashing algorithm to use') - ->values(hash_algos()) - ->cannotBeEmpty() - ->end() - ->arrayNode('methods') - ->info('Which request methods to cache') - ->defaultValue(['GET', 'HEAD']) - ->prototype('scalar') - ->validate() - ->ifTrue(function ($v) { - /* RFC7230 sections 3.1.1 and 3.2.6 except limited to uppercase characters. */ - return preg_match('/[^A-Z0-9!#$%&\'*+\-.^_`|~]+/', $v); - }) - ->thenInvalid('Invalid method: %s') - ->end() - ->end() - ->end() - ->scalarNode('respect_cache_headers') - ->info('Whether we should care about cache headers or not [DEPRECATED]') - ->beforeNormalization() - ->always(function ($v) { - @trigger_error('The option "respect_cache_headers" is deprecated since version 1.3 and will be removed in 2.0. Use "respect_response_cache_directives" instead.', E_USER_DEPRECATED); - - return $v; - }) - ->end() - ->validate() - ->ifNotInArray([null, true, false]) - ->thenInvalid('Value for "respect_cache_headers" must be null or boolean') - ->end() - ->end() - ->variableNode('respect_response_cache_directives') - ->info('A list of cache directives to respect when caching responses') - ->validate() - ->always(function ($v) { - if (is_null($v) || is_array($v)) { - return $v; - } - - throw new InvalidTypeException(); - }) - ->end() - ->end() + ->scalarNode('cache_key_generator') + ->info('This must be a service id to a service implementing '.CacheKeyGenerator::class) ->end() - ; + ->integerNode('cache_lifetime') + ->info('The minimum time we should store a cache item') + ->end() + ->integerNode('default_ttl') + ->info('The default max age of a Response') + ->end() + ->arrayNode('blacklisted_paths') + ->info('An array of regular expression patterns for paths not to be cached. Defaults to an empty array.') + ->defaultValue([]) + ->beforeNormalization() + ->castToArray() + ->end() + ->prototype('scalar') + ->validate() + ->ifTrue(function ($v) { + return false === @preg_match($v, ''); + }) + ->thenInvalid('Invalid regular expression for a blacklisted path: %s') + ->end() + ->end() + ->end() + ->enumNode('hash_algo') + ->info('Hashing algorithm to use') + ->values(hash_algos()) + ->cannotBeEmpty() + ->end() + ->arrayNode('methods') + ->info('Which request methods to cache') + ->defaultValue(['GET', 'HEAD']) + ->prototype('scalar') + ->validate() + ->ifTrue(function ($v) { + /* RFC7230 sections 3.1.1 and 3.2.6 except limited to uppercase characters. */ + return preg_match('/[^A-Z0-9!#$%&\'*+\-.^_`|~]+/', $v); + }) + ->thenInvalid('Invalid method: %s') + ->end() + ->end() + ->end() + ->scalarNode('respect_cache_headers') + ->info('Whether we should care about cache headers or not [DEPRECATED]') + ->beforeNormalization() + ->always(function ($v) { + @trigger_error('The option "respect_cache_headers" is deprecated since version 1.3 and will be removed in 2.0. Use "respect_response_cache_directives" instead.', E_USER_DEPRECATED); + + return $v; + }) + ->end() + ->validate() + ->ifNotInArray([null, true, false]) + ->thenInvalid('Value for "respect_cache_headers" must be null or boolean') + ->end() + ->end() + ->variableNode('respect_response_cache_directives') + ->info('A list of cache directives to respect when caching responses') + ->validate() + ->always(function ($v) { + if (is_null($v) || is_array($v)) { + return $v; + } + + throw new InvalidTypeException(); + }) + ->end() + ->end() + ->end(); $treeBuilder = new TreeBuilder('cache'); // Keep compatibility with symfony/config < 4.2 @@ -796,25 +781,24 @@ private function createCachePluginNode() ->info('Configure HTTP caching, requires the php-http/cache-plugin package') ->addDefaultsIfNotSet() ->validate() - ->ifTrue(function ($v) { - return !empty($v['enabled']) && !class_exists(CachePlugin::class); - }) - ->thenInvalid('To use the cache plugin, you need to require php-http/cache-plugin in your project') + ->ifTrue(function ($v) { + return !empty($v['enabled']) && !class_exists(CachePlugin::class); + }) + ->thenInvalid('To use the cache plugin, you need to require php-http/cache-plugin in your project') ->end() ->children() - ->scalarNode('cache_pool') - ->info('This must be a service id to a service implementing '.CacheItemPoolInterface::class) - ->isRequired() - ->cannotBeEmpty() - ->end() - ->scalarNode('stream_factory') - ->info('This must be a service id to a service implementing '.StreamFactory::class) - ->defaultValue('httplug.stream_factory') - ->cannotBeEmpty() - ->end() - ->end() - ->append($config) - ; + ->scalarNode('cache_pool') + ->info('This must be a service id to a service implementing '.CacheItemPoolInterface::class) + ->isRequired() + ->cannotBeEmpty() + ->end() + ->scalarNode('stream_factory') + ->info('This must be a service id to a service implementing '.StreamFactory::class) + ->defaultValue('httplug.stream_factory') + ->cannotBeEmpty() + ->end() + ->end() + ->append($config); return $cache; } diff --git a/src/DependencyInjection/HttplugExtension.php b/src/DependencyInjection/HttplugExtension.php index 965e3390..bbf50f8d 100644 --- a/src/DependencyInjection/HttplugExtension.php +++ b/src/DependencyInjection/HttplugExtension.php @@ -1,5 +1,7 @@ getDefinition('httplug.collector.formatter') - ->replaceArgument(0, new Reference($config['profiling']['formatter'])) - ; + ->replaceArgument(0, new Reference($config['profiling']['formatter'])); } $container ->getDefinition('httplug.formatter.full_http_message') - ->addArgument($config['profiling']['captured_body_length']) - ; + ->addArgument($config['profiling']['captured_body_length']); if (!class_exists(TwigEnvironment::class) && !class_exists(\Twig_Environment::class)) { $container->removeDefinition('httplug.collector.twig.http_message'); @@ -117,9 +117,6 @@ public function load(array $configs, ContainerBuilder $container) /** * Configure client services. - * - * @param ContainerBuilder $container - * @param array $config */ private function configureClients(ContainerBuilder $container, array $config) { @@ -170,9 +167,6 @@ private function configureClients(ContainerBuilder $container, array $config) /** * Configure all Httplug plugins or remove their service definition. - * - * @param ContainerBuilder $container - * @param array $config */ private function configurePlugins(ContainerBuilder $container, array $config) { @@ -193,10 +187,8 @@ private function configurePlugins(ContainerBuilder $container, array $config) /** * @param string $name - * @param Definition $definition - * @param array $config - * @param ContainerBuilder $container In case we need to add additional services for this plugin - * @param string $serviceId service id of the plugin, in case we need to add additional services for this plugin + * @param ContainerBuilder $container In case we need to add additional services for this plugin + * @param string $serviceId service id of the plugin, in case we need to add additional services for this plugin */ private function configurePluginByName($name, Definition $definition, array $config, ContainerBuilder $container, $serviceId) { @@ -317,9 +309,6 @@ private function configurePluginByName($name, Definition $definition, array $con } /** - * @param ContainerBuilder $container - * @param array $config - * * @return array list of service ids for the authentication plugins */ private function configureAuthentication(ContainerBuilder $container, array $config, $servicePrefix = 'httplug.plugin.authentication') @@ -361,8 +350,7 @@ private function configureAuthentication(ContainerBuilder $container, array $con $pluginServiceKey = $servicePrefix.'.'.$name; $container->register($pluginServiceKey, AuthenticationPlugin::class) - ->addArgument(new Reference($authServiceKey)) - ; + ->addArgument(new Reference($authServiceKey)); $pluginServices[] = $pluginServiceKey; } @@ -370,9 +358,7 @@ private function configureAuthentication(ContainerBuilder $container, array $con } /** - * @param ContainerBuilder $container - * @param string $clientName - * @param array $arguments + * @param string $clientName */ private function configureClient(ContainerBuilder $container, $clientName, array $arguments) { @@ -425,8 +411,7 @@ function ($id) { ->addArgument([ 'client_name' => $clientName, ]) - ->addTag(self::HTTPLUG_CLIENT_TAG) - ; + ->addTag(self::HTTPLUG_CLIENT_TAG); if (is_bool($arguments['public'])) { $definition->setPublic($arguments['public']); @@ -440,8 +425,7 @@ function ($id) { ->register($serviceId.'.flexible', FlexibleHttpClient::class) ->addArgument(new Reference($serviceId.'.flexible.inner')) ->setPublic($arguments['public'] ? true : false) - ->setDecoratedService($serviceId) - ; + ->setDecoratedService($serviceId); } if ($arguments['http_methods_client']) { @@ -449,8 +433,7 @@ function ($id) { ->register($serviceId.'.http_methods', HttpMethodsClient::class) ->setArguments([new Reference($serviceId.'.http_methods.inner'), new Reference('httplug.message_factory')]) ->setPublic($arguments['public'] ? true : false) - ->setDecoratedService($serviceId) - ; + ->setDecoratedService($serviceId); } if ($arguments['batch_client']) { @@ -458,17 +441,15 @@ function ($id) { ->register($serviceId.'.batch_client', BatchClient::class) ->setArguments([new Reference($serviceId.'.batch_client.inner')]) ->setPublic($arguments['public'] ? true : false) - ->setDecoratedService($serviceId) - ; + ->setDecoratedService($serviceId); } } /** * Create a URI object with the default URI factory. * - * @param ContainerBuilder $container - * @param string $serviceId Name of the private service to create - * @param string $uri String representation of the URI + * @param string $serviceId Name of the private service to create + * @param string $uri String representation of the URI */ private function createUri(ContainerBuilder $container, $serviceId, $uri) { @@ -476,16 +457,12 @@ private function createUri(ContainerBuilder $container, $serviceId, $uri) ->register($serviceId, UriInterface::class) ->setPublic(false) ->setFactory([new Reference('httplug.uri_factory'), 'createUri']) - ->addArgument($uri) - ; + ->addArgument($uri); } /** * Make the user can select what client is used for auto discovery. If none is provided, a service will be created * by finding a client using auto discovery. - * - * @param ContainerBuilder $container - * @param array $config */ private function configureAutoDiscoveryClients(ContainerBuilder $container, array $config) { @@ -529,10 +506,8 @@ public function getConfiguration(array $config, ContainerBuilder $container) /** * Configure a plugin using the parent definition from plugins.xml. * - * @param ContainerBuilder $container - * @param string $serviceId - * @param string $pluginName - * @param array $pluginConfig + * @param string $serviceId + * @param string $pluginName * * @return string configured service id */ diff --git a/src/Discovery/ConfiguredClientsStrategy.php b/src/Discovery/ConfiguredClientsStrategy.php index 212e1930..67336fd8 100644 --- a/src/Discovery/ConfiguredClientsStrategy.php +++ b/src/Discovery/ConfiguredClientsStrategy.php @@ -1,9 +1,11 @@ diff --git a/tests/Functional/ProfilerTest.php b/tests/Functional/ProfilerTest.php index d07f0044..92cead83 100644 --- a/tests/Functional/ProfilerTest.php +++ b/tests/Functional/ProfilerTest.php @@ -1,5 +1,7 @@ diff --git a/tests/Unit/Discovery/ConfiguredClientsStrategyTest.php b/tests/Unit/Discovery/ConfiguredClientsStrategyTest.php index 2efeff12..ed3f44a7 100644 --- a/tests/Unit/Discovery/ConfiguredClientsStrategyTest.php +++ b/tests/Unit/Discovery/ConfiguredClientsStrategyTest.php @@ -1,5 +1,7 @@ Date: Fri, 27 Dec 2019 12:56:59 +0200 Subject: [PATCH 2/5] Enable strict rule and allow risky rules --- .php_cs.dist | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.php_cs.dist b/.php_cs.dist index 8c7bcc22..b7475fd4 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -7,9 +7,11 @@ $finder = PhpCsFixer\Finder::create() ; return PhpCsFixer\Config::create() + ->setRiskyAllowed(true) ->setRules([ '@Symfony' => true, 'array_syntax' => ['syntax' => 'short'], + 'declare_strict_types' => true, 'visibility_required' => [ 'elements' => [ 'const', From 6fc8f35b83b0b99e79f064b6b1b5039cb7f148ad Mon Sep 17 00:00:00 2001 From: Mponos George Date: Fri, 27 Dec 2019 12:57:16 +0200 Subject: [PATCH 3/5] Added phpunit cache to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2e27c436..70efea11 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/.phpunit.result.cache /.php_cs.cache /behat.yml /build/ From cf42ba5944c2a09dba389b212303fe9f3111fa2f Mon Sep 17 00:00:00 2001 From: Mponos George Date: Fri, 27 Dec 2019 21:08:02 +0200 Subject: [PATCH 4/5] Revert whitespace --- src/ClientFactory/BuzzFactory.php | 13 +- src/ClientFactory/ClientFactory.php | 2 + src/ClientFactory/CurlFactory.php | 4 + src/ClientFactory/Guzzle5Factory.php | 3 + src/ClientFactory/ReactFactory.php | 3 + src/ClientFactory/SocketFactory.php | 3 + src/Collector/Collector.php | 11 + src/Collector/Formatter.php | 8 + src/Collector/PluginClientFactory.php | 13 +- src/Collector/PluginClientFactoryListener.php | 3 + src/Collector/ProfileClient.php | 23 +- src/Collector/ProfileClientFactory.php | 3 + src/Collector/ProfilePlugin.php | 22 +- src/Collector/Stack.php | 3 + src/Collector/StackPlugin.php | 4 +- src/DependencyInjection/Configuration.php | 1056 +++++++++-------- src/DependencyInjection/HttplugExtension.php | 57 +- src/Discovery/ConfiguredClientsStrategy.php | 2 +- 18 files changed, 685 insertions(+), 548 deletions(-) diff --git a/src/ClientFactory/BuzzFactory.php b/src/ClientFactory/BuzzFactory.php index fb7ad75a..7ef64ca2 100644 --- a/src/ClientFactory/BuzzFactory.php +++ b/src/ClientFactory/BuzzFactory.php @@ -19,6 +19,9 @@ class BuzzFactory implements ClientFactory */ private $messageFactory; + /** + * @param MessageFactory $messageFactory + */ public function __construct(MessageFactory $messageFactory) { $this->messageFactory = $messageFactory; @@ -46,16 +49,18 @@ public function createClient(array $config = []) /** * Get options to configure the Buzz client. + * + * @param array $config */ private function getOptions(array $config = []) { $resolver = new OptionsResolver(); $resolver->setDefaults([ - 'timeout' => 5, - 'verify_peer' => true, - 'verify_host' => 2, - 'proxy' => null, + 'timeout' => 5, + 'verify_peer' => true, + 'verify_host' => 2, + 'proxy' => null, ]); $resolver->setAllowedTypes('timeout', 'int'); diff --git a/src/ClientFactory/ClientFactory.php b/src/ClientFactory/ClientFactory.php index afae4b7f..6d0c600b 100644 --- a/src/ClientFactory/ClientFactory.php +++ b/src/ClientFactory/ClientFactory.php @@ -14,6 +14,8 @@ interface ClientFactory /** * Input an array of configuration to be able to create a HttpClient. * + * @param array $config + * * @return HttpClient */ public function createClient(array $config = []); diff --git a/src/ClientFactory/CurlFactory.php b/src/ClientFactory/CurlFactory.php index 1d663cb7..3ef6b385 100644 --- a/src/ClientFactory/CurlFactory.php +++ b/src/ClientFactory/CurlFactory.php @@ -23,6 +23,10 @@ class CurlFactory implements ClientFactory */ private $streamFactory; + /** + * @param ResponseFactoryInterface $responseFactory + * @param StreamFactoryInterface $streamFactory + */ public function __construct(ResponseFactoryInterface $responseFactory, StreamFactoryInterface $streamFactory) { $this->responseFactory = $responseFactory; diff --git a/src/ClientFactory/Guzzle5Factory.php b/src/ClientFactory/Guzzle5Factory.php index 38eb6d28..82ecd13f 100644 --- a/src/ClientFactory/Guzzle5Factory.php +++ b/src/ClientFactory/Guzzle5Factory.php @@ -18,6 +18,9 @@ class Guzzle5Factory implements ClientFactory */ private $messageFactory; + /** + * @param MessageFactory $messageFactory + */ public function __construct(MessageFactory $messageFactory) { $this->messageFactory = $messageFactory; diff --git a/src/ClientFactory/ReactFactory.php b/src/ClientFactory/ReactFactory.php index 489467ca..d1f90280 100644 --- a/src/ClientFactory/ReactFactory.php +++ b/src/ClientFactory/ReactFactory.php @@ -17,6 +17,9 @@ class ReactFactory implements ClientFactory */ private $messageFactory; + /** + * @param MessageFactory $messageFactory + */ public function __construct(MessageFactory $messageFactory) { $this->messageFactory = $messageFactory; diff --git a/src/ClientFactory/SocketFactory.php b/src/ClientFactory/SocketFactory.php index 2c3582df..c1e1016a 100644 --- a/src/ClientFactory/SocketFactory.php +++ b/src/ClientFactory/SocketFactory.php @@ -17,6 +17,9 @@ class SocketFactory implements ClientFactory */ private $messageFactory; + /** + * @param MessageFactory $messageFactory + */ public function __construct(MessageFactory $messageFactory) { $this->messageFactory = $messageFactory; diff --git a/src/Collector/Collector.php b/src/Collector/Collector.php index c2a2a642..5f1709f4 100644 --- a/src/Collector/Collector.php +++ b/src/Collector/Collector.php @@ -53,6 +53,8 @@ public function getName() /** * Mark the stack as active. If a stack was already active, use it as parent for our stack. + * + * @param Stack $stack */ public function activateStack(Stack $stack) { @@ -65,6 +67,8 @@ public function activateStack(Stack $stack) /** * Mark the stack as inactive. + * + * @param Stack $stack */ public function deactivateStack(Stack $stack) { @@ -79,12 +83,17 @@ public function getActiveStack() return $this->activeStack; } + /** + * @param Stack $stack + */ public function addStack(Stack $stack) { $this->data['stacks'][] = $stack; } /** + * @param Stack $parent + * * @return Stack[] */ public function getChildrenStacks(Stack $parent) @@ -165,6 +174,8 @@ public function countClientMessages($client) /** * Recursively count message in stack. * + * @param Stack $stack + * * @return int */ private function countStackMessages(Stack $stack) diff --git a/src/Collector/Formatter.php b/src/Collector/Formatter.php index f4759d36..80df7121 100644 --- a/src/Collector/Formatter.php +++ b/src/Collector/Formatter.php @@ -33,6 +33,10 @@ class Formatter implements MessageFormatter */ private $curlFormatter; + /** + * @param MessageFormatter $formatter + * @param CurlCommandFormatter $curlFormatter + */ public function __construct(MessageFormatter $formatter, CurlCommandFormatter $curlFormatter) { $this->formatter = $formatter; @@ -42,6 +46,8 @@ public function __construct(MessageFormatter $formatter, CurlCommandFormatter $c /** * Formats an exception. * + * @param \Throwable $exception + * * @return string */ public function formatException(\Throwable $exception) @@ -76,6 +82,8 @@ public function formatResponse(ResponseInterface $response) /** * Format a RequestInterface as a cURL command. * + * @param RequestInterface $request + * * @return string */ public function formatAsCurlCommand(RequestInterface $request) diff --git a/src/Collector/PluginClientFactory.php b/src/Collector/PluginClientFactory.php index 53eb5130..6d8d0342 100644 --- a/src/Collector/PluginClientFactory.php +++ b/src/Collector/PluginClientFactory.php @@ -36,6 +36,11 @@ final class PluginClientFactory */ private $stopwatch; + /** + * @param Collector $collector + * @param Formatter $formatter + * @param Stopwatch $stopwatch + */ public function __construct(Collector $collector, Formatter $formatter, Stopwatch $stopwatch) { $this->collector = $collector; @@ -48,13 +53,13 @@ public function __construct(Collector $collector, Formatter $formatter, Stopwatc * @param Plugin[] $plugins * @param array $options { * - * @return PluginClient + * @var string $client_name to give client a name which may be used when displaying client information like in + * the HTTPlugBundle profiler. + * } * * @see PluginClient constructor for PluginClient specific $options. * - * @var string $client_name to give client a name which may be used when displaying client information like in - * the HTTPlugBundle profiler. - * } + * @return PluginClient */ public function createClient($client, array $plugins = [], array $options = []) { diff --git a/src/Collector/PluginClientFactoryListener.php b/src/Collector/PluginClientFactoryListener.php index 44e0b4e0..b51e82fc 100644 --- a/src/Collector/PluginClientFactoryListener.php +++ b/src/Collector/PluginClientFactoryListener.php @@ -32,6 +32,9 @@ final class PluginClientFactoryListener implements EventSubscriberInterface */ private $factory; + /** + * @param PluginClientFactory $factory + */ public function __construct(PluginClientFactory $factory) { $this->factory = $factory; diff --git a/src/Collector/ProfileClient.php b/src/Collector/ProfileClient.php index 743da4f3..0110696e 100644 --- a/src/Collector/ProfileClient.php +++ b/src/Collector/ProfileClient.php @@ -53,8 +53,11 @@ class ProfileClient implements HttpClient, HttpAsyncClient private $eventNames = []; /** - * @param HttpClient|HttpAsyncClient $client The client to profile. Client must implement HttpClient or - * HttpAsyncClient interface. + * @param HttpClient|HttpAsyncClient $client The client to profile. Client must implement HttpClient or + * HttpAsyncClient interface. + * @param Collector $collector + * @param Formatter $formatter + * @param Stopwatch $stopwatch */ public function __construct($client, Collector $collector, Formatter $formatter, Stopwatch $stopwatch) { @@ -148,6 +151,10 @@ protected function doSendRequest(RequestInterface $request) } } + /** + * @param RequestInterface $request + * @param Stack $stack + */ private function collectRequestInformations(RequestInterface $request, Stack $stack) { $stack->setRequestTarget($request->getRequestTarget()); @@ -158,6 +165,11 @@ private function collectRequestInformations(RequestInterface $request, Stack $st $stack->setCurlCommand($this->formatter->formatAsCurlCommand($request)); } + /** + * @param ResponseInterface $response + * @param StopwatchEvent $event + * @param Stack $stack + */ private function collectResponseInformations(ResponseInterface $response, StopwatchEvent $event, Stack $stack) { $stack->setDuration($event->getDuration()); @@ -165,6 +177,11 @@ private function collectResponseInformations(ResponseInterface $response, Stopwa $stack->setClientResponse($this->formatter->formatResponse($response)); } + /** + * @param \Throwable $exception + * @param StopwatchEvent $event + * @param Stack $stack + */ private function collectExceptionInformations(\Throwable $exception, StopwatchEvent $event, Stack $stack) { if ($exception instanceof HttpException) { @@ -178,6 +195,8 @@ private function collectExceptionInformations(\Throwable $exception, StopwatchEv /** * Generates the event name. * + * @param RequestInterface $request + * * @return string */ private function getStopwatchEventName(RequestInterface $request) diff --git a/src/Collector/ProfileClientFactory.php b/src/Collector/ProfileClientFactory.php index 23d17fdc..7b5903b2 100644 --- a/src/Collector/ProfileClientFactory.php +++ b/src/Collector/ProfileClientFactory.php @@ -42,6 +42,9 @@ class ProfileClientFactory implements ClientFactory /** * @param ClientFactory|callable $factory + * @param Collector $collector + * @param Formatter $formatter + * @param Stopwatch $stopwatch */ public function __construct($factory, Collector $collector, Formatter $formatter, Stopwatch $stopwatch) { diff --git a/src/Collector/ProfilePlugin.php b/src/Collector/ProfilePlugin.php index 777e00e3..5808bfcf 100644 --- a/src/Collector/ProfilePlugin.php +++ b/src/Collector/ProfilePlugin.php @@ -36,6 +36,11 @@ class ProfilePlugin implements Plugin */ private $formatter; + /** + * @param Plugin $plugin + * @param Collector $collector + * @param Formatter $formatter + */ public function __construct(Plugin $plugin, Collector $collector, Formatter $formatter) { $this->plugin = $plugin; @@ -84,7 +89,10 @@ protected function doHandleRequest(RequestInterface $request, callable $next, ca } /** - * @param Stack $stack + * @param RequestInterface $request + * @param Profile $profile + * @param Exception $exception + * @param Stack $stack */ private function onException( RequestInterface $request, @@ -97,13 +105,20 @@ private function onException( $this->collectRequestInformation($request, $stack); } + /** + * @param RequestInterface $request + * @param Profile $profile + */ private function onOutgoingRequest(RequestInterface $request, Profile $profile) { $profile->setRequest($this->formatter->formatRequest($request)); } /** - * @param Stack $stack + * @param ResponseInterface $response + * @param Profile $profile + * @param RequestInterface $request + * @param Stack $stack */ private function onOutgoingResponse(ResponseInterface $response, Profile $profile, RequestInterface $request, Stack $stack = null) { @@ -114,6 +129,9 @@ private function onOutgoingResponse(ResponseInterface $response, Profile $profil /** * Collect request information when not already done by the HTTP client. This happens when using the CachePlugin * and the cache is hit without re-validation. + * + * @param RequestInterface $request + * @param Stack|null $stack */ private function collectRequestInformation(RequestInterface $request, Stack $stack = null) { diff --git a/src/Collector/Stack.php b/src/Collector/Stack.php index 9ce09682..da905f3a 100644 --- a/src/Collector/Stack.php +++ b/src/Collector/Stack.php @@ -127,6 +127,9 @@ public function setParent(self $parent) $this->parent = $parent; } + /** + * @param Profile $profile + */ public function addProfile(Profile $profile) { $this->profiles[] = $profile; diff --git a/src/Collector/StackPlugin.php b/src/Collector/StackPlugin.php index cb423b61..b8371fc5 100644 --- a/src/Collector/StackPlugin.php +++ b/src/Collector/StackPlugin.php @@ -37,7 +37,9 @@ class StackPlugin implements Plugin private $formatter; /** - * @param string $client + * @param Collector $collector + * @param Formatter $formatter + * @param string $client */ public function __construct(Collector $collector, Formatter $formatter, $client) { diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 1095f567..e39672fa 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -68,109 +68,113 @@ public function getConfigTreeBuilder() $rootNode ->validate() - ->ifTrue(function ($v) { - return !empty($v['classes']['client']) - || !empty($v['classes']['message_factory']) - || !empty($v['classes']['uri_factory']) - || !empty($v['classes']['stream_factory']); - }) - ->then(function ($v) { - foreach ($v['classes'] as $key => $class) { - if (null !== $class && !class_exists($class)) { - throw new InvalidConfigurationException(sprintf('Class %s specified for httplug.classes.%s does not exist.', $class, $key)); + ->ifTrue(function ($v) { + return !empty($v['classes']['client']) + || !empty($v['classes']['message_factory']) + || !empty($v['classes']['uri_factory']) + || !empty($v['classes']['stream_factory']); + }) + ->then(function ($v) { + foreach ($v['classes'] as $key => $class) { + if (null !== $class && !class_exists($class)) { + throw new InvalidConfigurationException(sprintf( + 'Class %s specified for httplug.classes.%s does not exist.', + $class, + $key + )); + } } - } - return $v; - }) + return $v; + }) ->end() ->beforeNormalization() - ->ifTrue(function ($v) { - return is_array($v) && array_key_exists('toolbar', $v) && is_array($v['toolbar']); - }) - ->then(function ($v) { - if (array_key_exists('profiling', $v)) { - throw new InvalidConfigurationException('Can\'t configure both "toolbar" and "profiling" section. The "toolbar" config is deprecated as of version 1.3.0, please only use "profiling".'); - } + ->ifTrue(function ($v) { + return is_array($v) && array_key_exists('toolbar', $v) && is_array($v['toolbar']); + }) + ->then(function ($v) { + if (array_key_exists('profiling', $v)) { + throw new InvalidConfigurationException('Can\'t configure both "toolbar" and "profiling" section. The "toolbar" config is deprecated as of version 1.3.0, please only use "profiling".'); + } - @trigger_error('"httplug.toolbar" config is deprecated since version 1.3 and will be removed in 2.0. Use "httplug.profiling" instead.', E_USER_DEPRECATED); + @trigger_error('"httplug.toolbar" config is deprecated since version 1.3 and will be removed in 2.0. Use "httplug.profiling" instead.', E_USER_DEPRECATED); - if (array_key_exists('enabled', $v['toolbar']) && 'auto' === $v['toolbar']['enabled']) { - @trigger_error('"auto" value in "httplug.toolbar" config is deprecated since version 1.3 and will be removed in 2.0. Use a boolean value instead.', E_USER_DEPRECATED); - $v['toolbar']['enabled'] = $this->debug; - } + if (array_key_exists('enabled', $v['toolbar']) && 'auto' === $v['toolbar']['enabled']) { + @trigger_error('"auto" value in "httplug.toolbar" config is deprecated since version 1.3 and will be removed in 2.0. Use a boolean value instead.', E_USER_DEPRECATED); + $v['toolbar']['enabled'] = $this->debug; + } - $v['profiling'] = $v['toolbar']; + $v['profiling'] = $v['toolbar']; - unset($v['toolbar']); + unset($v['toolbar']); - return $v; - }) + return $v; + }) ->end() ->fixXmlConfig('client') ->children() - ->booleanNode('default_client_autowiring') - ->defaultTrue() - ->info('Set to false to not autowire HttpClient and HttpAsyncClient.') - ->end() - ->arrayNode('main_alias') - ->addDefaultsIfNotSet() - ->info('Configure which service the main alias point to.') - ->children() - ->scalarNode('client')->defaultValue('httplug.client.default')->end() - ->scalarNode('message_factory')->defaultValue('httplug.message_factory.default')->end() - ->scalarNode('uri_factory')->defaultValue('httplug.uri_factory.default')->end() - ->scalarNode('stream_factory')->defaultValue('httplug.stream_factory.default')->end() - ->end() - ->end() - ->arrayNode('classes') - ->addDefaultsIfNotSet() - ->info('Overwrite a service class instead of using the discovery mechanism.') - ->children() - ->scalarNode('client')->defaultNull()->end() - ->scalarNode('message_factory')->defaultNull()->end() - ->scalarNode('uri_factory')->defaultNull()->end() - ->scalarNode('stream_factory')->defaultNull()->end() - ->end() - ->end() - ->arrayNode('profiling') - ->addDefaultsIfNotSet() - ->treatFalseLike(['enabled' => false]) - ->treatTrueLike(['enabled' => true]) - ->treatNullLike(['enabled' => $this->debug]) - ->info('Extend the debug profiler with information about requests.') - ->children() - ->booleanNode('enabled') - ->info('Turn the toolbar on or off. Defaults to kernel debug mode.') - ->defaultValue($this->debug) - ->end() - ->scalarNode('formatter')->defaultNull()->end() - ->scalarNode('captured_body_length') - ->validate() - ->ifTrue(function ($v) { - return null !== $v && !is_int($v); - }) - ->thenInvalid('The child node "captured_body_length" at path "httplug.profiling" must be an integer or null ("%s" given).') - ->end() - ->defaultValue(0) - ->info('Limit long HTTP message bodies to x characters. If set to 0 we do not read the message body. If null the body will not be truncated. Only available with the default formatter (FullHttpMessageFormatter).') - ->end() - ->end() - ->end() - ->arrayNode('discovery') - ->addDefaultsIfNotSet() - ->info('Control what clients should be found by the discovery.') - ->children() - ->scalarNode('client') - ->defaultValue('auto') - ->info('Set to "auto" to see auto discovered client in the web profiler. If provided a service id for a client then this client will be found by auto discovery.') - ->end() - ->scalarNode('async_client') - ->defaultNull() - ->info('Set to "auto" to see auto discovered client in the web profiler. If provided a service id for a client then this client will be found by auto discovery.') - ->end() - ->end() - ->end() + ->booleanNode('default_client_autowiring') + ->defaultTrue() + ->info('Set to false to not autowire HttpClient and HttpAsyncClient.') + ->end() + ->arrayNode('main_alias') + ->addDefaultsIfNotSet() + ->info('Configure which service the main alias point to.') + ->children() + ->scalarNode('client')->defaultValue('httplug.client.default')->end() + ->scalarNode('message_factory')->defaultValue('httplug.message_factory.default')->end() + ->scalarNode('uri_factory')->defaultValue('httplug.uri_factory.default')->end() + ->scalarNode('stream_factory')->defaultValue('httplug.stream_factory.default')->end() + ->end() + ->end() + ->arrayNode('classes') + ->addDefaultsIfNotSet() + ->info('Overwrite a service class instead of using the discovery mechanism.') + ->children() + ->scalarNode('client')->defaultNull()->end() + ->scalarNode('message_factory')->defaultNull()->end() + ->scalarNode('uri_factory')->defaultNull()->end() + ->scalarNode('stream_factory')->defaultNull()->end() + ->end() + ->end() + ->arrayNode('profiling') + ->addDefaultsIfNotSet() + ->treatFalseLike(['enabled' => false]) + ->treatTrueLike(['enabled' => true]) + ->treatNullLike(['enabled' => $this->debug]) + ->info('Extend the debug profiler with information about requests.') + ->children() + ->booleanNode('enabled') + ->info('Turn the toolbar on or off. Defaults to kernel debug mode.') + ->defaultValue($this->debug) + ->end() + ->scalarNode('formatter')->defaultNull()->end() + ->scalarNode('captured_body_length') + ->validate() + ->ifTrue(function ($v) { + return null !== $v && !is_int($v); + }) + ->thenInvalid('The child node "captured_body_length" at path "httplug.profiling" must be an integer or null ("%s" given).') + ->end() + ->defaultValue(0) + ->info('Limit long HTTP message bodies to x characters. If set to 0 we do not read the message body. If null the body will not be truncated. Only available with the default formatter (FullHttpMessageFormatter).') + ->end() + ->end() + ->end() + ->arrayNode('discovery') + ->addDefaultsIfNotSet() + ->info('Control what clients should be found by the discovery.') + ->children() + ->scalarNode('client') + ->defaultValue('auto') + ->info('Set to "auto" to see auto discovered client in the web profiler. If provided a service id for a client then this client will be found by auto discovery.') + ->end() + ->scalarNode('async_client') + ->defaultNull() + ->info('Set to "auto" to see auto discovered client in the web profiler. If provided a service id for a client then this client will be found by auto discovery.') + ->end() + ->end() + ->end() ->end(); return $treeBuilder; @@ -180,68 +184,72 @@ private function configureClients(ArrayNodeDefinition $root) { $root->children() ->arrayNode('clients') - ->useAttributeAsKey('name') - ->prototype('array') - ->fixXmlConfig('plugin') - ->validate() - ->ifTrue(function ($config) { - // Make sure we only allow one of these to be true - return (bool) $config['flexible_client'] + (bool) $config['http_methods_client'] + (bool) $config['batch_client'] >= 2; - }) - ->thenInvalid('A http client can\'t be decorated with several of FlexibleHttpClient, HttpMethodsClient and BatchClient. Only one of the following options can be true. ("flexible_client", "http_methods_client", "batch_client")') - ->end() - ->validate() - ->ifTrue(function ($config) { - return 'httplug.factory.auto' === $config['factory'] && !empty($config['config']); - }) - ->thenInvalid('If you want to use the "config" key you must also specify a valid "factory".') - ->end() - ->validate() - ->ifTrue(function ($config) { - return !empty($config['service']) && ('httplug.factory.auto' !== $config['factory'] || !empty($config['config'])); - }) - ->thenInvalid('If you want to use the "service" key you cannot specify "factory" or "config".') - ->end() - ->children() - ->scalarNode('factory') - ->defaultValue('httplug.factory.auto') - ->cannotBeEmpty() - ->info('The service id of a factory to use when creating the adapter.') - ->end() - ->scalarNode('service') - ->defaultNull() - ->info('The service id of the client to use.') - ->end() - ->booleanNode('public') - ->defaultNull() - ->info('Set to true if you really cannot use dependency injection and need to make the client service public.') - ->end() - ->booleanNode('flexible_client') - ->defaultFalse() - ->info('Set to true to get the client wrapped in a FlexibleHttpClient which emulates async or sync behavior.') - ->end() - ->booleanNode('http_methods_client') - ->defaultFalse() - ->info('Set to true to get the client wrapped in a HttpMethodsClient which emulates provides functions for HTTP verbs.') - ->end() - ->booleanNode('batch_client') - ->defaultFalse() - ->info('Set to true to get the client wrapped in a BatchClient which allows you to send multiple request at the same time.') - ->end() - ->variableNode('config')->defaultValue([])->end() - ->append($this->createClientPluginNode()) - ->end() - ->end() - ->end(); + ->useAttributeAsKey('name') + ->prototype('array') + ->fixXmlConfig('plugin') + ->validate() + ->ifTrue(function ($config) { + // Make sure we only allow one of these to be true + return (bool) $config['flexible_client'] + (bool) $config['http_methods_client'] + (bool) $config['batch_client'] >= 2; + }) + ->thenInvalid('A http client can\'t be decorated with several of FlexibleHttpClient, HttpMethodsClient and BatchClient. Only one of the following options can be true. ("flexible_client", "http_methods_client", "batch_client")') + ->end() + ->validate() + ->ifTrue(function ($config) { + return 'httplug.factory.auto' === $config['factory'] && !empty($config['config']); + }) + ->thenInvalid('If you want to use the "config" key you must also specify a valid "factory".') + ->end() + ->validate() + ->ifTrue(function ($config) { + return !empty($config['service']) && ('httplug.factory.auto' !== $config['factory'] || !empty($config['config'])); + }) + ->thenInvalid('If you want to use the "service" key you cannot specify "factory" or "config".') + ->end() + ->children() + ->scalarNode('factory') + ->defaultValue('httplug.factory.auto') + ->cannotBeEmpty() + ->info('The service id of a factory to use when creating the adapter.') + ->end() + ->scalarNode('service') + ->defaultNull() + ->info('The service id of the client to use.') + ->end() + ->booleanNode('public') + ->defaultNull() + ->info('Set to true if you really cannot use dependency injection and need to make the client service public.') + ->end() + ->booleanNode('flexible_client') + ->defaultFalse() + ->info('Set to true to get the client wrapped in a FlexibleHttpClient which emulates async or sync behavior.') + ->end() + ->booleanNode('http_methods_client') + ->defaultFalse() + ->info('Set to true to get the client wrapped in a HttpMethodsClient which emulates provides functions for HTTP verbs.') + ->end() + ->booleanNode('batch_client') + ->defaultFalse() + ->info('Set to true to get the client wrapped in a BatchClient which allows you to send multiple request at the same time.') + ->end() + ->variableNode('config')->defaultValue([])->end() + ->append($this->createClientPluginNode()) + ->end() + ->end() + ->end(); } + /** + * @param ArrayNodeDefinition $root + */ private function configureSharedPlugins(ArrayNodeDefinition $root) { $pluginsNode = $root ->children() - ->arrayNode('plugins') - ->info('Global plugin configuration. Plugins need to be explicitly added to clients.') - ->addDefaultsIfNotSet()// don't call end to get the plugins node + ->arrayNode('plugins') + ->info('Global plugin configuration. Plugins need to be explicitly added to clients.') + ->addDefaultsIfNotSet() + // don't call end to get the plugins node ; $this->addSharedPluginNodes($pluginsNode); } @@ -264,219 +272,222 @@ private function createClientPluginNode() /** @var ArrayNodeDefinition $pluginList */ $pluginList = $node ->info('A list of plugin service ids and client specific plugin definitions. The order is important.') - ->prototype('array'); + ->prototype('array') + ; $pluginList // support having just a service id in the list ->beforeNormalization() - ->always(function ($plugin) { - if (is_string($plugin)) { - return [ - 'reference' => [ - 'enabled' => true, - 'id' => $plugin, - ], - ]; - } - - return $plugin; - }) + ->always(function ($plugin) { + if (is_string($plugin)) { + return [ + 'reference' => [ + 'enabled' => true, + 'id' => $plugin, + ], + ]; + } + + return $plugin; + }) ->end() + ->validate() - ->always(function ($plugins) { - foreach ($plugins as $name => $definition) { - if ('authentication' === $name) { - if (!count($definition)) { - unset($plugins['authentication']); + ->always(function ($plugins) { + foreach ($plugins as $name => $definition) { + if ('authentication' === $name) { + if (!count($definition)) { + unset($plugins['authentication']); + } + } elseif (!$definition['enabled']) { + unset($plugins[$name]); } - } elseif (!$definition['enabled']) { - unset($plugins[$name]); } - } - return $plugins; - }) - ->end(); + return $plugins; + }) + ->end() + ; $this->addSharedPluginNodes($pluginList, true); $pluginList ->children() - ->arrayNode('reference') - ->canBeEnabled() - ->info('Reference to a plugin service') - ->children() - ->scalarNode('id') - ->info('Service id of a plugin') - ->isRequired() - ->cannotBeEmpty() - ->end() - ->end() - ->end() - ->arrayNode('add_host') - ->canBeEnabled() - ->addDefaultsIfNotSet() - ->info('Set scheme, host and port in the request URI.') - ->children() - ->scalarNode('host') - ->info('Host name including protocol and optionally the port number, e.g. https://api.local:8000') - ->isRequired() - ->cannotBeEmpty() - ->end() - ->scalarNode('replace') - ->info('Whether to replace the host if request already specifies one') - ->defaultValue(false) - ->end() - ->end() - ->end() - ->arrayNode('add_path') - ->canBeEnabled() - ->addDefaultsIfNotSet() - ->info('Add a base path to the request.') - ->children() - ->scalarNode('path') - ->info('Path to be added, e.g. /api/v1') - ->isRequired() - ->cannotBeEmpty() - ->end() - ->end() - ->end() - ->arrayNode('base_uri') - ->canBeEnabled() - ->addDefaultsIfNotSet() - ->info('Set a base URI to the request.') - ->children() - ->scalarNode('uri') - ->info('Base Uri including protocol, optionally the port number and prepend path, e.g. https://api.local:8000/api') - ->isRequired() - ->cannotBeEmpty() - ->end() - ->scalarNode('replace') - ->info('Whether to replace the host if request already specifies one') - ->defaultValue(false) - ->end() - ->end() - ->end() - ->arrayNode('content_type') - ->canBeEnabled() - ->info('Detect the content type of a request body and set the Content-Type header if it is not already set.') - ->children() - ->booleanNode('skip_detection') - ->info('Whether to skip detection when request body is larger than size_limit') - ->defaultFalse() - ->end() - ->scalarNode('size_limit') - ->info('Skip content type detection if request body is larger than size_limit bytes') - ->end() - ->end() - ->end() - ->arrayNode('header_append') - ->canBeEnabled() - ->info('Append headers to the request. If the header already exists the value will be appended to the current value.') - ->fixXmlConfig('header') - ->children() - ->arrayNode('headers') - ->info('Keys are the header names, values the header values') - ->normalizeKeys(false) - ->useAttributeAsKey('name') - ->prototype('scalar')->end() - ->end() - ->end() - ->end() - ->arrayNode('header_defaults') - ->canBeEnabled() - ->info('Set header to default value if it does not exist.') - ->fixXmlConfig('header') - ->children() - ->arrayNode('headers') - ->info('Keys are the header names, values the header values') - ->normalizeKeys(false) - ->useAttributeAsKey('name') - ->prototype('scalar')->end() - ->end() - ->end() - ->end() - ->arrayNode('header_set') - ->canBeEnabled() - ->info('Set headers to requests. If the header does not exist it wil be set, if the header already exists it will be replaced.') - ->fixXmlConfig('header') - ->children() - ->arrayNode('headers') - ->info('Keys are the header names, values the header values') - ->normalizeKeys(false) - ->useAttributeAsKey('name') - ->prototype('scalar')->end() - ->end() - ->end() - ->end() - ->arrayNode('header_remove') - ->canBeEnabled() - ->info('Remove headers from requests.') - ->fixXmlConfig('header') - ->children() - ->arrayNode('headers') - ->info('List of header names to remove') - ->prototype('scalar')->end() - ->end() - ->end() - ->end() - ->arrayNode('query_defaults') - ->canBeEnabled() - ->info('Sets query parameters to default value if they are not present in the request.') - ->fixXmlConfig('parameter') - ->children() - ->arrayNode('parameters') - ->info('List of query parameters. Names and values must not be url encoded as the plugin will encode them.') - ->normalizeKeys(false) - ->useAttributeAsKey('name') - ->prototype('scalar')->end() - ->end() - ->end() - ->end() - ->arrayNode('vcr') - ->canBeEnabled() - ->addDefaultsIfNotSet() - ->info('Record response to be replayed during tests or development cycle.') - ->validate() - ->ifTrue(function ($config) { - return 'filesystem' === $config['recorder'] && empty($config['fixtures_directory']); - }) - ->thenInvalid('If you want to use the "filesystem" recorder you must also specify a "fixtures_directory".') - ->end() - ->children() - ->enumNode('mode') - ->info('What should be the behavior of the plugin?') - ->values(['record', 'replay', 'replay_or_record']) - ->isRequired() - ->cannotBeEmpty() - ->end() - ->scalarNode('recorder') - ->info(sprintf('Which recorder to use. Can be "in_memory", "filesystem" or the ID of your service implementing %s and %s. When using filesystem, specify "fixtures_directory" as well.', RecorderInterface::class, PlayerInterface::class)) - ->defaultValue('filesystem') - ->cannotBeEmpty() - ->end() - ->scalarNode('naming_strategy') - ->info(sprintf('Which naming strategy to use. Add the ID of your service implementing %s to override the default one.', NamingStrategyInterface::class)) - ->defaultValue('default') - ->cannotBeEmpty() - ->end() - ->arrayNode('naming_strategy_options') - ->info('See http://docs.php-http.org/en/latest/plugins/vcr.html#the-naming-strategy for more details') - ->children() - ->arrayNode('hash_headers') - ->info('List of header(s) that make the request unique (Ex: ‘Authorization’)') - ->prototype('scalar')->end() - ->end() - ->arrayNode('hash_body_methods') - ->info('for which request methods the body makes requests distinct.') - ->prototype('scalar')->end() - ->end() - ->end() - ->end() // End naming_strategy_options - ->scalarNode('fixtures_directory') - ->info('Where the responses will be stored and replay from when using the filesystem recorder. Should be accessible to your VCS.') - ->end() - ->end() - ->end() - ->end(); + ->arrayNode('reference') + ->canBeEnabled() + ->info('Reference to a plugin service') + ->children() + ->scalarNode('id') + ->info('Service id of a plugin') + ->isRequired() + ->cannotBeEmpty() + ->end() + ->end() + ->end() + ->arrayNode('add_host') + ->canBeEnabled() + ->addDefaultsIfNotSet() + ->info('Set scheme, host and port in the request URI.') + ->children() + ->scalarNode('host') + ->info('Host name including protocol and optionally the port number, e.g. https://api.local:8000') + ->isRequired() + ->cannotBeEmpty() + ->end() + ->scalarNode('replace') + ->info('Whether to replace the host if request already specifies one') + ->defaultValue(false) + ->end() + ->end() + ->end() + ->arrayNode('add_path') + ->canBeEnabled() + ->addDefaultsIfNotSet() + ->info('Add a base path to the request.') + ->children() + ->scalarNode('path') + ->info('Path to be added, e.g. /api/v1') + ->isRequired() + ->cannotBeEmpty() + ->end() + ->end() + ->end() + ->arrayNode('base_uri') + ->canBeEnabled() + ->addDefaultsIfNotSet() + ->info('Set a base URI to the request.') + ->children() + ->scalarNode('uri') + ->info('Base Uri including protocol, optionally the port number and prepend path, e.g. https://api.local:8000/api') + ->isRequired() + ->cannotBeEmpty() + ->end() + ->scalarNode('replace') + ->info('Whether to replace the host if request already specifies one') + ->defaultValue(false) + ->end() + ->end() + ->end() + ->arrayNode('content_type') + ->canBeEnabled() + ->info('Detect the content type of a request body and set the Content-Type header if it is not already set.') + ->children() + ->booleanNode('skip_detection') + ->info('Whether to skip detection when request body is larger than size_limit') + ->defaultFalse() + ->end() + ->scalarNode('size_limit') + ->info('Skip content type detection if request body is larger than size_limit bytes') + ->end() + ->end() + ->end() + ->arrayNode('header_append') + ->canBeEnabled() + ->info('Append headers to the request. If the header already exists the value will be appended to the current value.') + ->fixXmlConfig('header') + ->children() + ->arrayNode('headers') + ->info('Keys are the header names, values the header values') + ->normalizeKeys(false) + ->useAttributeAsKey('name') + ->prototype('scalar')->end() + ->end() + ->end() + ->end() + ->arrayNode('header_defaults') + ->canBeEnabled() + ->info('Set header to default value if it does not exist.') + ->fixXmlConfig('header') + ->children() + ->arrayNode('headers') + ->info('Keys are the header names, values the header values') + ->normalizeKeys(false) + ->useAttributeAsKey('name') + ->prototype('scalar')->end() + ->end() + ->end() + ->end() + ->arrayNode('header_set') + ->canBeEnabled() + ->info('Set headers to requests. If the header does not exist it wil be set, if the header already exists it will be replaced.') + ->fixXmlConfig('header') + ->children() + ->arrayNode('headers') + ->info('Keys are the header names, values the header values') + ->normalizeKeys(false) + ->useAttributeAsKey('name') + ->prototype('scalar')->end() + ->end() + ->end() + ->end() + ->arrayNode('header_remove') + ->canBeEnabled() + ->info('Remove headers from requests.') + ->fixXmlConfig('header') + ->children() + ->arrayNode('headers') + ->info('List of header names to remove') + ->prototype('scalar')->end() + ->end() + ->end() + ->end() + ->arrayNode('query_defaults') + ->canBeEnabled() + ->info('Sets query parameters to default value if they are not present in the request.') + ->fixXmlConfig('parameter') + ->children() + ->arrayNode('parameters') + ->info('List of query parameters. Names and values must not be url encoded as the plugin will encode them.') + ->normalizeKeys(false) + ->useAttributeAsKey('name') + ->prototype('scalar')->end() + ->end() + ->end() + ->end() + ->arrayNode('vcr') + ->canBeEnabled() + ->addDefaultsIfNotSet() + ->info('Record response to be replayed during tests or development cycle.') + ->validate() + ->ifTrue(function ($config) { + return 'filesystem' === $config['recorder'] && empty($config['fixtures_directory']); + }) + ->thenInvalid('If you want to use the "filesystem" recorder you must also specify a "fixtures_directory".') + ->end() + ->children() + ->enumNode('mode') + ->info('What should be the behavior of the plugin?') + ->values(['record', 'replay', 'replay_or_record']) + ->isRequired() + ->cannotBeEmpty() + ->end() + ->scalarNode('recorder') + ->info(sprintf('Which recorder to use. Can be "in_memory", "filesystem" or the ID of your service implementing %s and %s. When using filesystem, specify "fixtures_directory" as well.', RecorderInterface::class, PlayerInterface::class)) + ->defaultValue('filesystem') + ->cannotBeEmpty() + ->end() + ->scalarNode('naming_strategy') + ->info(sprintf('Which naming strategy to use. Add the ID of your service implementing %s to override the default one.', NamingStrategyInterface::class)) + ->defaultValue('default') + ->cannotBeEmpty() + ->end() + ->arrayNode('naming_strategy_options') + ->info('See http://docs.php-http.org/en/latest/plugins/vcr.html#the-naming-strategy for more details') + ->children() + ->arrayNode('hash_headers') + ->info('List of header(s) that make the request unique (Ex: ‘Authorization’)') + ->prototype('scalar')->end() + ->end() + ->arrayNode('hash_body_methods') + ->info('for which request methods the body makes requests distinct.') + ->prototype('scalar')->end() + ->end() + ->end() + ->end() // End naming_strategy_options + ->scalarNode('fixtures_directory') + ->info('Where the responses will be stored and replay from when using the filesystem recorder. Should be accessible to your VCS.') + ->end() + ->end() + ->end() + ->end(); return $node; } @@ -496,27 +507,27 @@ private function addSharedPluginNodes(ArrayNodeDefinition $pluginNode, $disableA $children ->arrayNode('cookie') - ->canBeEnabled() - ->children() - ->scalarNode('cookie_jar') - ->info('This must be a service id to a service implementing '.CookieJar::class) - ->isRequired() - ->cannotBeEmpty() - ->end() - ->end() + ->canBeEnabled() + ->children() + ->scalarNode('cookie_jar') + ->info('This must be a service id to a service implementing '.CookieJar::class) + ->isRequired() + ->cannotBeEmpty() + ->end() + ->end() ->end(); // End cookie plugin $children ->arrayNode('history') - ->canBeEnabled() - ->children() - ->scalarNode('journal') - ->info('This must be a service id to a service implementing '.Journal::class) - ->isRequired() - ->cannotBeEmpty() - ->end() - ->end() + ->canBeEnabled() + ->children() + ->scalarNode('journal') + ->info('This must be a service id to a service implementing '.Journal::class) + ->isRequired() + ->cannotBeEmpty() + ->end() + ->end() ->end(); // End history plugin @@ -524,58 +535,58 @@ private function addSharedPluginNodes(ArrayNodeDefinition $pluginNode, $disableA $disableAll ? $decoder->canBeEnabled() : $decoder->canBeDisabled(); $decoder->addDefaultsIfNotSet() ->children() - ->scalarNode('use_content_encoding')->defaultTrue()->end() + ->scalarNode('use_content_encoding')->defaultTrue()->end() ->end() - ->end(); + ->end(); // End decoder plugin $logger = $children->arrayNode('logger'); $disableAll ? $logger->canBeEnabled() : $logger->canBeDisabled(); $logger->addDefaultsIfNotSet() ->children() - ->scalarNode('logger') - ->info('This must be a service id to a service implementing '.LoggerInterface::class) - ->defaultValue('logger') - ->cannotBeEmpty() - ->end() - ->scalarNode('formatter') - ->info('This must be a service id to a service implementing '.Formatter::class) - ->defaultNull() - ->end() - ->end() - ->end(); + ->scalarNode('logger') + ->info('This must be a service id to a service implementing '.LoggerInterface::class) + ->defaultValue('logger') + ->cannotBeEmpty() + ->end() + ->scalarNode('formatter') + ->info('This must be a service id to a service implementing '.Formatter::class) + ->defaultNull() + ->end() + ->end() + ->end(); // End logger plugin $redirect = $children->arrayNode('redirect'); $disableAll ? $redirect->canBeEnabled() : $redirect->canBeDisabled(); $redirect->addDefaultsIfNotSet() ->children() - ->scalarNode('preserve_header')->defaultTrue()->end() - ->scalarNode('use_default_for_multiple')->defaultTrue()->end() + ->scalarNode('preserve_header')->defaultTrue()->end() + ->scalarNode('use_default_for_multiple')->defaultTrue()->end() ->end() - ->end(); + ->end(); // End redirect plugin $retry = $children->arrayNode('retry'); $disableAll ? $retry->canBeEnabled() : $retry->canBeDisabled(); $retry->addDefaultsIfNotSet() ->children() - ->scalarNode('retry')->defaultValue(1)->end() // TODO: should be called retries for consistency with the class + ->scalarNode('retry')->defaultValue(1)->end() // TODO: should be called retries for consistency with the class ->end() - ->end(); + ->end(); // End retry plugin $stopwatch = $children->arrayNode('stopwatch'); $disableAll ? $stopwatch->canBeEnabled() : $stopwatch->canBeDisabled(); $stopwatch->addDefaultsIfNotSet() ->children() - ->scalarNode('stopwatch') - ->info('This must be a service id to a service extending Symfony\Component\Stopwatch\Stopwatch') - ->defaultValue('debug.stopwatch') - ->cannotBeEmpty() + ->scalarNode('stopwatch') + ->info('This must be a service id to a service extending Symfony\Component\Stopwatch\Stopwatch') + ->defaultValue('debug.stopwatch') + ->cannotBeEmpty() + ->end() ->end() - ->end() - ->end(); + ->end(); // End stopwatch plugin } @@ -597,48 +608,48 @@ private function createAuthenticationPluginNode() $node ->useAttributeAsKey('name') ->prototype('array') - ->validate() - ->always() - ->then(function ($config) { - switch ($config['type']) { - case 'basic': - $this->validateAuthenticationType(['username', 'password'], $config, 'basic'); - - break; - case 'bearer': - $this->validateAuthenticationType(['token'], $config, 'bearer'); - - break; - case 'service': - $this->validateAuthenticationType(['service'], $config, 'service'); - - break; - case 'wsse': - $this->validateAuthenticationType(['username', 'password'], $config, 'wsse'); - - break; - case 'query_param': - $this->validateAuthenticationType(['params'], $config, 'query_param'); - - break; - } + ->validate() + ->always() + ->then(function ($config) { + switch ($config['type']) { + case 'basic': + $this->validateAuthenticationType(['username', 'password'], $config, 'basic'); + + break; + case 'bearer': + $this->validateAuthenticationType(['token'], $config, 'bearer'); + + break; + case 'service': + $this->validateAuthenticationType(['service'], $config, 'service'); + + break; + case 'wsse': + $this->validateAuthenticationType(['username', 'password'], $config, 'wsse'); + + break; + case 'query_param': + $this->validateAuthenticationType(['params'], $config, 'query_param'); + + break; + } - return $config; - }) - ->end() - ->children() - ->enumNode('type') - ->values(['basic', 'bearer', 'wsse', 'service', 'query_param']) - ->isRequired() - ->cannotBeEmpty() - ->end() - ->scalarNode('username')->end() - ->scalarNode('password')->end() - ->scalarNode('token')->end() - ->scalarNode('service')->end() - ->arrayNode('params')->prototype('scalar')->end() - ->end() - ->end() + return $config; + }) + ->end() + ->children() + ->enumNode('type') + ->values(['basic', 'bearer', 'wsse', 'service', 'query_param']) + ->isRequired() + ->cannotBeEmpty() + ->end() + ->scalarNode('username')->end() + ->scalarNode('password')->end() + ->scalarNode('token')->end() + ->scalarNode('service')->end() + ->arrayNode('params')->prototype('scalar')->end() + ->end() + ->end() ->end(); // End authentication plugin return $node; @@ -668,7 +679,12 @@ private function validateAuthenticationType(array $expected, array $actual, $aut return; } - throw new InvalidConfigurationException(sprintf('Authentication "%s" requires %s but got %s', $authName, implode(', ', $expected), implode(', ', $actual))); + throw new InvalidConfigurationException(sprintf( + 'Authentication "%s" requires %s but got %s', + $authName, + implode(', ', $expected), + implode(', ', $actual) + )); } /** @@ -691,82 +707,83 @@ private function createCachePluginNode() ->fixXmlConfig('respect_response_cache_directive') ->addDefaultsIfNotSet() ->validate() - ->ifTrue(function ($config) { - // Cannot set both respect_cache_headers and respect_response_cache_directives - return isset($config['respect_cache_headers'], $config['respect_response_cache_directives']); - }) - ->thenInvalid('You can\'t provide config option "respect_cache_headers" and "respect_response_cache_directives" simultaniously. Use "respect_response_cache_directives" instead.') + ->ifTrue(function ($config) { + // Cannot set both respect_cache_headers and respect_response_cache_directives + return isset($config['respect_cache_headers'], $config['respect_response_cache_directives']); + }) + ->thenInvalid('You can\'t provide config option "respect_cache_headers" and "respect_response_cache_directives" simultaniously. Use "respect_response_cache_directives" instead.') ->end() ->children() - ->scalarNode('cache_key_generator') - ->info('This must be a service id to a service implementing '.CacheKeyGenerator::class) - ->end() - ->integerNode('cache_lifetime') - ->info('The minimum time we should store a cache item') - ->end() - ->integerNode('default_ttl') - ->info('The default max age of a Response') - ->end() - ->arrayNode('blacklisted_paths') - ->info('An array of regular expression patterns for paths not to be cached. Defaults to an empty array.') - ->defaultValue([]) - ->beforeNormalization() - ->castToArray() - ->end() - ->prototype('scalar') - ->validate() - ->ifTrue(function ($v) { - return false === @preg_match($v, ''); - }) - ->thenInvalid('Invalid regular expression for a blacklisted path: %s') - ->end() + ->scalarNode('cache_key_generator') + ->info('This must be a service id to a service implementing '.CacheKeyGenerator::class) + ->end() + ->integerNode('cache_lifetime') + ->info('The minimum time we should store a cache item') + ->end() + ->integerNode('default_ttl') + ->info('The default max age of a Response') + ->end() + ->arrayNode('blacklisted_paths') + ->info('An array of regular expression patterns for paths not to be cached. Defaults to an empty array.') + ->defaultValue([]) + ->beforeNormalization() + ->castToArray() + ->end() + ->prototype('scalar') + ->validate() + ->ifTrue(function ($v) { + return false === @preg_match($v, ''); + }) + ->thenInvalid('Invalid regular expression for a blacklisted path: %s') + ->end() + ->end() + ->end() + ->enumNode('hash_algo') + ->info('Hashing algorithm to use') + ->values(hash_algos()) + ->cannotBeEmpty() + ->end() + ->arrayNode('methods') + ->info('Which request methods to cache') + ->defaultValue(['GET', 'HEAD']) + ->prototype('scalar') + ->validate() + ->ifTrue(function ($v) { + /* RFC7230 sections 3.1.1 and 3.2.6 except limited to uppercase characters. */ + return preg_match('/[^A-Z0-9!#$%&\'*+\-.^_`|~]+/', $v); + }) + ->thenInvalid('Invalid method: %s') + ->end() + ->end() + ->end() + ->scalarNode('respect_cache_headers') + ->info('Whether we should care about cache headers or not [DEPRECATED]') + ->beforeNormalization() + ->always(function ($v) { + @trigger_error('The option "respect_cache_headers" is deprecated since version 1.3 and will be removed in 2.0. Use "respect_response_cache_directives" instead.', E_USER_DEPRECATED); + + return $v; + }) + ->end() + ->validate() + ->ifNotInArray([null, true, false]) + ->thenInvalid('Value for "respect_cache_headers" must be null or boolean') + ->end() + ->end() + ->variableNode('respect_response_cache_directives') + ->info('A list of cache directives to respect when caching responses') + ->validate() + ->always(function ($v) { + if (is_null($v) || is_array($v)) { + return $v; + } + + throw new InvalidTypeException(); + }) + ->end() + ->end() ->end() - ->end() - ->enumNode('hash_algo') - ->info('Hashing algorithm to use') - ->values(hash_algos()) - ->cannotBeEmpty() - ->end() - ->arrayNode('methods') - ->info('Which request methods to cache') - ->defaultValue(['GET', 'HEAD']) - ->prototype('scalar') - ->validate() - ->ifTrue(function ($v) { - /* RFC7230 sections 3.1.1 and 3.2.6 except limited to uppercase characters. */ - return preg_match('/[^A-Z0-9!#$%&\'*+\-.^_`|~]+/', $v); - }) - ->thenInvalid('Invalid method: %s') - ->end() - ->end() - ->end() - ->scalarNode('respect_cache_headers') - ->info('Whether we should care about cache headers or not [DEPRECATED]') - ->beforeNormalization() - ->always(function ($v) { - @trigger_error('The option "respect_cache_headers" is deprecated since version 1.3 and will be removed in 2.0. Use "respect_response_cache_directives" instead.', E_USER_DEPRECATED); - - return $v; - }) - ->end() - ->validate() - ->ifNotInArray([null, true, false]) - ->thenInvalid('Value for "respect_cache_headers" must be null or boolean') - ->end() - ->end() - ->variableNode('respect_response_cache_directives') - ->info('A list of cache directives to respect when caching responses') - ->validate() - ->always(function ($v) { - if (is_null($v) || is_array($v)) { - return $v; - } - - throw new InvalidTypeException(); - }) - ->end() - ->end() - ->end(); + ; $treeBuilder = new TreeBuilder('cache'); // Keep compatibility with symfony/config < 4.2 @@ -781,24 +798,25 @@ private function createCachePluginNode() ->info('Configure HTTP caching, requires the php-http/cache-plugin package') ->addDefaultsIfNotSet() ->validate() - ->ifTrue(function ($v) { - return !empty($v['enabled']) && !class_exists(CachePlugin::class); - }) - ->thenInvalid('To use the cache plugin, you need to require php-http/cache-plugin in your project') + ->ifTrue(function ($v) { + return !empty($v['enabled']) && !class_exists(CachePlugin::class); + }) + ->thenInvalid('To use the cache plugin, you need to require php-http/cache-plugin in your project') ->end() ->children() - ->scalarNode('cache_pool') - ->info('This must be a service id to a service implementing '.CacheItemPoolInterface::class) - ->isRequired() - ->cannotBeEmpty() - ->end() - ->scalarNode('stream_factory') - ->info('This must be a service id to a service implementing '.StreamFactory::class) - ->defaultValue('httplug.stream_factory') - ->cannotBeEmpty() - ->end() - ->end() - ->append($config); + ->scalarNode('cache_pool') + ->info('This must be a service id to a service implementing '.CacheItemPoolInterface::class) + ->isRequired() + ->cannotBeEmpty() + ->end() + ->scalarNode('stream_factory') + ->info('This must be a service id to a service implementing '.StreamFactory::class) + ->defaultValue('httplug.stream_factory') + ->cannotBeEmpty() + ->end() + ->end() + ->append($config) + ; return $cache; } diff --git a/src/DependencyInjection/HttplugExtension.php b/src/DependencyInjection/HttplugExtension.php index bbf50f8d..957a5e27 100644 --- a/src/DependencyInjection/HttplugExtension.php +++ b/src/DependencyInjection/HttplugExtension.php @@ -85,12 +85,14 @@ public function load(array $configs, ContainerBuilder $container) // Add custom formatter $container ->getDefinition('httplug.collector.formatter') - ->replaceArgument(0, new Reference($config['profiling']['formatter'])); + ->replaceArgument(0, new Reference($config['profiling']['formatter'])) + ; } $container ->getDefinition('httplug.formatter.full_http_message') - ->addArgument($config['profiling']['captured_body_length']); + ->addArgument($config['profiling']['captured_body_length']) + ; if (!class_exists(TwigEnvironment::class) && !class_exists(\Twig_Environment::class)) { $container->removeDefinition('httplug.collector.twig.http_message'); @@ -117,6 +119,9 @@ public function load(array $configs, ContainerBuilder $container) /** * Configure client services. + * + * @param ContainerBuilder $container + * @param array $config */ private function configureClients(ContainerBuilder $container, array $config) { @@ -167,6 +172,9 @@ private function configureClients(ContainerBuilder $container, array $config) /** * Configure all Httplug plugins or remove their service definition. + * + * @param ContainerBuilder $container + * @param array $config */ private function configurePlugins(ContainerBuilder $container, array $config) { @@ -187,8 +195,10 @@ private function configurePlugins(ContainerBuilder $container, array $config) /** * @param string $name - * @param ContainerBuilder $container In case we need to add additional services for this plugin - * @param string $serviceId service id of the plugin, in case we need to add additional services for this plugin + * @param Definition $definition + * @param array $config + * @param ContainerBuilder $container In case we need to add additional services for this plugin + * @param string $serviceId service id of the plugin, in case we need to add additional services for this plugin */ private function configurePluginByName($name, Definition $definition, array $config, ContainerBuilder $container, $serviceId) { @@ -309,6 +319,9 @@ private function configurePluginByName($name, Definition $definition, array $con } /** + * @param ContainerBuilder $container + * @param array $config + * * @return array list of service ids for the authentication plugins */ private function configureAuthentication(ContainerBuilder $container, array $config, $servicePrefix = 'httplug.plugin.authentication') @@ -350,7 +363,8 @@ private function configureAuthentication(ContainerBuilder $container, array $con $pluginServiceKey = $servicePrefix.'.'.$name; $container->register($pluginServiceKey, AuthenticationPlugin::class) - ->addArgument(new Reference($authServiceKey)); + ->addArgument(new Reference($authServiceKey)) + ; $pluginServices[] = $pluginServiceKey; } @@ -358,7 +372,9 @@ private function configureAuthentication(ContainerBuilder $container, array $con } /** - * @param string $clientName + * @param ContainerBuilder $container + * @param string $clientName + * @param array $arguments */ private function configureClient(ContainerBuilder $container, $clientName, array $arguments) { @@ -411,7 +427,8 @@ function ($id) { ->addArgument([ 'client_name' => $clientName, ]) - ->addTag(self::HTTPLUG_CLIENT_TAG); + ->addTag(self::HTTPLUG_CLIENT_TAG) + ; if (is_bool($arguments['public'])) { $definition->setPublic($arguments['public']); @@ -425,7 +442,8 @@ function ($id) { ->register($serviceId.'.flexible', FlexibleHttpClient::class) ->addArgument(new Reference($serviceId.'.flexible.inner')) ->setPublic($arguments['public'] ? true : false) - ->setDecoratedService($serviceId); + ->setDecoratedService($serviceId) + ; } if ($arguments['http_methods_client']) { @@ -433,7 +451,8 @@ function ($id) { ->register($serviceId.'.http_methods', HttpMethodsClient::class) ->setArguments([new Reference($serviceId.'.http_methods.inner'), new Reference('httplug.message_factory')]) ->setPublic($arguments['public'] ? true : false) - ->setDecoratedService($serviceId); + ->setDecoratedService($serviceId) + ; } if ($arguments['batch_client']) { @@ -441,15 +460,17 @@ function ($id) { ->register($serviceId.'.batch_client', BatchClient::class) ->setArguments([new Reference($serviceId.'.batch_client.inner')]) ->setPublic($arguments['public'] ? true : false) - ->setDecoratedService($serviceId); + ->setDecoratedService($serviceId) + ; } } /** * Create a URI object with the default URI factory. * - * @param string $serviceId Name of the private service to create - * @param string $uri String representation of the URI + * @param ContainerBuilder $container + * @param string $serviceId Name of the private service to create + * @param string $uri String representation of the URI */ private function createUri(ContainerBuilder $container, $serviceId, $uri) { @@ -457,12 +478,16 @@ private function createUri(ContainerBuilder $container, $serviceId, $uri) ->register($serviceId, UriInterface::class) ->setPublic(false) ->setFactory([new Reference('httplug.uri_factory'), 'createUri']) - ->addArgument($uri); + ->addArgument($uri) + ; } /** * Make the user can select what client is used for auto discovery. If none is provided, a service will be created * by finding a client using auto discovery. + * + * @param ContainerBuilder $container + * @param array $config */ private function configureAutoDiscoveryClients(ContainerBuilder $container, array $config) { @@ -506,8 +531,10 @@ public function getConfiguration(array $config, ContainerBuilder $container) /** * Configure a plugin using the parent definition from plugins.xml. * - * @param string $serviceId - * @param string $pluginName + * @param ContainerBuilder $container + * @param string $serviceId + * @param string $pluginName + * @param array $pluginConfig * * @return string configured service id */ diff --git a/src/Discovery/ConfiguredClientsStrategy.php b/src/Discovery/ConfiguredClientsStrategy.php index 67336fd8..add66ac6 100644 --- a/src/Discovery/ConfiguredClientsStrategy.php +++ b/src/Discovery/ConfiguredClientsStrategy.php @@ -4,8 +4,8 @@ namespace Http\HttplugBundle\Discovery; -use Http\Client\HttpAsyncClient; use Http\Client\HttpClient; +use Http\Client\HttpAsyncClient; use Http\Discovery\HttpClientDiscovery; use Http\Discovery\Strategy\DiscoveryStrategy; use Symfony\Component\EventDispatcher\Event as LegacyEvent; From 075fa257fa79cc14b40a23a00de4b72281cf1e59 Mon Sep 17 00:00:00 2001 From: Mponos George Date: Mon, 6 Jan 2020 12:47:06 +0200 Subject: [PATCH 5/5] Fix codestyle issues --- src/ClientFactory/SymfonyFactory.php | 2 ++ tests/Unit/ClientFactory/SymfonyFactoryTest.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/ClientFactory/SymfonyFactory.php b/src/ClientFactory/SymfonyFactory.php index 14a26225..21f1b529 100644 --- a/src/ClientFactory/SymfonyFactory.php +++ b/src/ClientFactory/SymfonyFactory.php @@ -1,5 +1,7 @@