1<?php
2
3/*
4 * This file is part of the CsaGuzzleBundle package
5 *
6 * (c) Charles Sarrazin <charles@sarraz.in>
7 * (c) PrestaShop and Contributors
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code
11 */
12
13namespace Csa\Bundle\GuzzleBundle\DependencyInjection;
14
15use Csa\Bundle\GuzzleBundle\DependencyInjection\CompilerPass\SubscriberPass;
16use Symfony\Component\Config\FileLocator;
17use Symfony\Component\DependencyInjection\ContainerBuilder;
18use Symfony\Component\DependencyInjection\Definition;
19use Symfony\Component\DependencyInjection\DefinitionDecorator;
20use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
21use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
22use Symfony\Component\DependencyInjection\Reference;
23use Symfony\Component\ExpressionLanguage\Expression;
24use Symfony\Component\HttpKernel\DependencyInjection\Extension;
25
26/**
27 * Csa Guzzle Extension.
28 *
29 * @author Charles Sarrazin <charles@sarraz.in>
30 */
31class CsaGuzzleExtension extends Extension
32{
33    public function load(array $configs, ContainerBuilder $container)
34    {
35        $config = $this->processConfiguration(new Configuration(), $configs);
36
37        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
38
39        $loader->load('subscribers.xml');
40        $loader->load('collector.xml');
41        $loader->load('twig.xml');
42        $loader->load('factory.xml');
43        $loader->load('services.xml');
44
45        $descriptionFactory = $container->getDefinition('csa_guzzle.description_factory');
46
47        $dataCollector = $container->getDefinition('csa_guzzle.data_collector.guzzle');
48        $dataCollector->addArgument($config['profiler']['max_body_size']);
49
50        if (!$config['profiler']['enabled']) {
51            $container->removeDefinition('csa_guzzle.subscriber.debug');
52            $container->removeDefinition('csa_guzzle.subscriber.stopwatch');
53            $container->removeDefinition('csa_guzzle.data_collector.guzzle');
54            $container->removeDefinition('csa_guzzle.twig.extension');
55        }
56
57        $loggerDefinition = $container->getDefinition('csa_guzzle.subscriber.logger');
58
59        if ($config['logger']['service']) {
60            $loggerDefinition->replaceArgument(0, new Reference($config['logger']['service']));
61        }
62
63        if ($config['logger']['format']) {
64            $loggerDefinition->replaceArgument(1, $config['logger']['format']);
65        }
66
67        if (!$config['logger']['enabled']) {
68            $container->removeDefinition('csa_guzzle.subscriber.logger');
69        }
70
71        $this->processCacheConfiguration($config['cache'], $container);
72
73        $definition = $container->getDefinition('csa_guzzle.client_factory');
74        $definition->replaceArgument(0, $config['factory_class']);
75
76        $this->processClientsConfiguration($config, $container, $descriptionFactory);
77    }
78
79    private function processCacheConfiguration(array $config, ContainerBuilder $container)
80    {
81        if (!$config['enabled']) {
82            $container->removeDefinition('csa_guzzle.cache.adapter.doctrine');
83            $container->removeDefinition('csa_guzzle.subscriber.cache');
84
85            return;
86        }
87
88        $adapterId = $config['adapter']['service'];
89
90        if ('doctrine' === $config['adapter']['type']) {
91            $adapterId = 'csa_guzzle.cache.adapter.doctrine';
92
93            $adapter = $container->getDefinition($adapterId);
94            $adapter->addArgument(new Reference($config['service']));
95        }
96
97        $container->setAlias('csa_guzzle.default_cache_adapter', $adapterId);
98    }
99
100    private function processClientsConfiguration(array $config, ContainerBuilder $container, Definition $descriptionFactory)
101    {
102        foreach ($config['clients'] as $name => $options) {
103            $client = new Definition($options['class']);
104
105            if (isset($options['config'])) {
106                if (!is_array($options['config'])) {
107                    throw new InvalidArgumentException(sprintf(
108                        'Config for "csa_guzzle.client.%s" should be an array, but got %s',
109                        $name,
110                        gettype($options['config'])
111                    ));
112                }
113                $client->addArgument($this->buildGuzzleConfig($options['config']));
114            }
115
116            $subscribers = $this->findSubscriberIds($options['subscribers']);
117
118            $client->addTag(
119                SubscriberPass::CLIENT_TAG,
120                count($subscribers) ? ['subscribers' => implode(',', $subscribers)] : []
121            );
122
123            $clientServiceId = sprintf('csa_guzzle.client.%s', $name);
124            $container->setDefinition($clientServiceId, $client);
125
126            if (isset($options['description'])) {
127                $descriptionFactory->addMethodCall('addResource', [$name, $options['description']]);
128
129                $serviceDefinition = new DefinitionDecorator('csa_guzzle.service.abstract');
130                $serviceDefinition->addArgument(new Reference($clientServiceId));
131                $serviceDefinition->addArgument(new Expression(sprintf(
132                    'service("csa_guzzle.description_factory").getDescription("%s")',
133                    $name
134                )));
135                $container->setDefinition(sprintf('csa_guzzle.service.%s', $name), $serviceDefinition);
136            }
137
138            if (isset($options['alias'])) {
139                $container->setAlias($options['alias'], $clientServiceId);
140            }
141        }
142    }
143
144    private function findSubscriberIds(array $explicitlyConfiguredIds)
145    {
146        return array_filter(array_keys($explicitlyConfiguredIds), function ($key) use ($explicitlyConfiguredIds) {
147            return isset($explicitlyConfiguredIds[$key]) && $explicitlyConfiguredIds[$key];
148        });
149    }
150
151    private function buildGuzzleConfig(array $config)
152    {
153        foreach (['message_factory', 'fsm', 'adapter', 'handler'] as $service) {
154            if (isset($config[$service])) {
155                $config[$service] = new Reference($config[$service]);
156            }
157        }
158
159        return $config;
160    }
161}
162