1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace EightPoints\Bundle\GuzzleBundle\DependencyInjection; |
4
|
|
|
|
5
|
|
|
use Symfony\Component\DependencyInjection\ContainerBuilder; |
6
|
|
|
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; |
7
|
|
|
use Symfony\Component\DependencyInjection\Reference; |
8
|
|
|
use Symfony\Component\DependencyInjection\Definition; |
9
|
|
|
use Symfony\Component\Config\FileLocator; |
10
|
|
|
use Symfony\Component\HttpKernel\DependencyInjection\Extension; |
11
|
|
|
use Symfony\Component\ExpressionLanguage\Expression; |
12
|
|
|
use GuzzleHttp\HandlerStack; |
13
|
|
|
|
14
|
|
|
class EightPointsGuzzleExtension extends Extension |
15
|
|
|
{ |
16
|
|
|
/** @var \EightPoints\Bundle\GuzzleBundle\EightPointsGuzzleBundlePlugin[] */ |
17
|
|
|
protected $plugins; |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* @param \EightPoints\Bundle\GuzzleBundle\EightPointsGuzzleBundlePlugin[] $plugins |
21
|
|
|
*/ |
22
|
|
|
public function __construct(array $plugins = []) |
23
|
|
|
{ |
24
|
|
|
$this->plugins = $plugins; |
25
|
|
|
} |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* {@inheritdoc} |
29
|
|
|
*/ |
30
|
|
|
public function getConfiguration(array $config, ContainerBuilder $container) : Configuration |
31
|
|
|
{ |
32
|
|
|
return new Configuration($this->getAlias(), $container->getParameter('kernel.debug'), $this->plugins); |
33
|
|
|
} |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* Loads the Guzzle configuration. |
37
|
|
|
* |
38
|
|
|
* @param array $configs an array of configuration settings |
39
|
|
|
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container a ContainerBuilder instance |
40
|
|
|
* |
41
|
|
|
* @throws \InvalidArgumentException |
42
|
|
|
* @throws \Symfony\Component\DependencyInjection\Exception\BadMethodCallException |
43
|
|
|
* @throws \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException |
44
|
|
|
* @throws \Exception |
45
|
|
|
* |
46
|
|
|
* @return void |
47
|
|
|
*/ |
48
|
|
|
public function load(array $configs, ContainerBuilder $container) |
49
|
|
|
{ |
50
|
|
|
$configPath = implode(DIRECTORY_SEPARATOR, [__DIR__, '..', 'Resources', 'config']); |
51
|
|
|
$loader = new XmlFileLoader($container, new FileLocator($configPath)); |
52
|
|
|
|
53
|
|
|
$loader->load('services.xml'); |
54
|
|
|
|
55
|
|
|
$configuration = new Configuration($this->getAlias(), $container->getParameter('kernel.debug'), $this->plugins); |
56
|
|
|
$config = $this->processConfiguration($configuration, $configs); |
57
|
|
|
$logging = $config['logging'] === true; |
58
|
|
|
|
59
|
|
|
foreach ($this->plugins as $plugin) { |
60
|
|
|
$container->addObjectResource(new \ReflectionClass(get_class($plugin))); |
61
|
|
|
$plugin->load($config, $container); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
if ($logging) { |
65
|
|
|
$this->defineLogger($container); |
66
|
|
|
$this->defineDataCollector($container); |
67
|
|
|
$this->defineFormatter($container); |
68
|
|
|
$this->defineSymfonyLogFormatter($container); |
69
|
|
|
$this->defineSymfonyLogMiddleware($container); |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
foreach ($config['clients'] as $name => $options) { |
73
|
|
|
$argument = [ |
74
|
|
|
'base_uri' => $options['base_url'], |
75
|
|
|
'handler' => $this->createHandler($container, $name, $options, $logging) |
76
|
|
|
]; |
77
|
|
|
|
78
|
|
|
// if present, add default options to the constructor argument for the Guzzle client |
79
|
|
|
if (isset($options['options']) && is_array($options['options'])) { |
80
|
|
|
foreach ($options['options'] as $key => $value) { |
81
|
|
|
if ($value === null || (is_array($value) && count($value) === 0)) { |
82
|
|
|
continue; |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
$argument[$key] = $value; |
86
|
|
|
} |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
$client = new Definition($options['class']); |
90
|
|
|
$client->addArgument($argument); |
91
|
|
|
$client->setPublic(true); |
92
|
|
|
|
93
|
|
|
// set service name based on client name |
94
|
|
|
$serviceName = sprintf('%s.client.%s', $this->getAlias(), $name); |
95
|
|
|
$container->setDefinition($serviceName, $client); |
96
|
|
|
} |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container |
101
|
|
|
* @param string $clientName |
102
|
|
|
* @param array $options |
103
|
|
|
* @param bool $logging |
104
|
|
|
* |
105
|
|
|
* @throws \Symfony\Component\DependencyInjection\Exception\BadMethodCallException |
106
|
|
|
* @throws \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException |
107
|
|
|
* |
108
|
|
|
* @return \Symfony\Component\DependencyInjection\Definition |
109
|
|
|
*/ |
110
|
|
|
protected function createHandler(ContainerBuilder $container, string $clientName, array $options, bool $logging) : Definition |
111
|
|
|
{ |
112
|
|
|
// Event Dispatching service |
113
|
|
|
$eventServiceName = sprintf('eight_points_guzzle.middleware.event_dispatch.%s', $clientName); |
114
|
|
|
$eventService = $this->createEventMiddleware($clientName); |
115
|
|
|
$container->setDefinition($eventServiceName, $eventService); |
116
|
|
|
|
117
|
|
|
// Create the event Dispatch Middleware |
118
|
|
|
$eventExpression = new Expression(sprintf("service('%s').dispatchEvent()", $eventServiceName)); |
119
|
|
|
|
120
|
|
|
$handler = new Definition(HandlerStack::class); |
121
|
|
|
$handler->setFactory([HandlerStack::class, 'create']); |
122
|
|
|
$handler->setPublic(true); |
123
|
|
|
|
124
|
|
|
if ($logging) { |
125
|
|
|
$this->defineLogMiddleware($container, $handler, $clientName); |
126
|
|
|
$this->defineRequestTimeMiddleware($container, $handler, $clientName); |
127
|
|
|
$this->attachSymfonyLogMiddlewareToHandler($handler); |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
foreach ($this->plugins as $plugin) { |
131
|
|
|
$plugin->loadForClient($options['plugin'][$plugin->getPluginName()], $container, $clientName, $handler); |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
// goes on the end of the stack. |
135
|
|
|
$handler->addMethodCall('unshift', [$eventExpression, 'events']); |
136
|
|
|
|
137
|
|
|
return $handler; |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
/** |
141
|
|
|
* Define Logger |
142
|
|
|
* |
143
|
|
|
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container |
144
|
|
|
* |
145
|
|
|
* @throws \Symfony\Component\DependencyInjection\Exception\BadMethodCallException |
146
|
|
|
* |
147
|
|
|
* @return void |
148
|
|
|
*/ |
149
|
|
|
protected function defineLogger(ContainerBuilder $container) |
150
|
|
|
{ |
151
|
|
|
$loggerDefinition = new Definition('%eight_points_guzzle.logger.class%'); |
152
|
|
|
$loggerDefinition->setPublic(true); |
153
|
|
|
$container->setDefinition('eight_points_guzzle.logger', $loggerDefinition); |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
/** |
157
|
|
|
* Define Data Collector |
158
|
|
|
* |
159
|
|
|
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container |
160
|
|
|
* |
161
|
|
|
* @throws \Symfony\Component\DependencyInjection\Exception\BadMethodCallException |
162
|
|
|
* |
163
|
|
|
* @return void |
164
|
|
|
*/ |
165
|
|
View Code Duplication |
protected function defineDataCollector(ContainerBuilder $container) |
|
|
|
|
166
|
|
|
{ |
167
|
|
|
$dataCollectorDefinition = new Definition('%eight_points_guzzle.data_collector.class%'); |
168
|
|
|
$dataCollectorDefinition->addArgument(new Reference('eight_points_guzzle.logger')); |
169
|
|
|
$dataCollectorDefinition->setPublic(false); |
170
|
|
|
$dataCollectorDefinition->addTag('data_collector', [ |
171
|
|
|
'id' => 'eight_points_guzzle', |
172
|
|
|
'template' => '@EightPointsGuzzle/debug.html.twig', |
173
|
|
|
]); |
174
|
|
|
$container->setDefinition('eight_points_guzzle.data_collector', $dataCollectorDefinition); |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
/** |
178
|
|
|
* Define Formatter |
179
|
|
|
* |
180
|
|
|
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container |
181
|
|
|
* |
182
|
|
|
* @throws \Symfony\Component\DependencyInjection\Exception\BadMethodCallException |
183
|
|
|
* |
184
|
|
|
* @return void |
185
|
|
|
*/ |
186
|
|
|
protected function defineFormatter(ContainerBuilder $container) |
187
|
|
|
{ |
188
|
|
|
$formatterDefinition = new Definition('%eight_points_guzzle.formatter.class%'); |
189
|
|
|
$formatterDefinition->setPublic(true); |
190
|
|
|
$container->setDefinition('eight_points_guzzle.formatter', $formatterDefinition); |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
/** |
194
|
|
|
* Define Request Time Middleware |
195
|
|
|
* |
196
|
|
|
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container |
197
|
|
|
* @param \Symfony\Component\DependencyInjection\Definition $handler |
198
|
|
|
* @param string $clientName |
199
|
|
|
* |
200
|
|
|
* @return void |
201
|
|
|
*/ |
202
|
|
View Code Duplication |
protected function defineRequestTimeMiddleware(ContainerBuilder $container, Definition $handler, string $clientName) |
|
|
|
|
203
|
|
|
{ |
204
|
|
|
$requestTimeMiddlewareDefinitionName = sprintf('eight_points_guzzle.middleware.request_time.%s', $clientName); |
205
|
|
|
$requestTimeMiddlewareDefinition = new Definition('%eight_points_guzzle.middleware.request_time.class%'); |
206
|
|
|
$requestTimeMiddlewareDefinition->addArgument(new Reference('eight_points_guzzle.data_collector')); |
207
|
|
|
$requestTimeMiddlewareDefinition->setPublic(false); |
208
|
|
|
$container->setDefinition($requestTimeMiddlewareDefinitionName, $requestTimeMiddlewareDefinition); |
209
|
|
|
|
210
|
|
|
$requestTimeExpression = new Expression(sprintf("service('%s')", $requestTimeMiddlewareDefinitionName)); |
211
|
|
|
$handler->addMethodCall('push', [$requestTimeExpression, 'request_time']); |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
/** |
215
|
|
|
* Define Log Middleware for client |
216
|
|
|
* |
217
|
|
|
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container |
218
|
|
|
* @param \Symfony\Component\DependencyInjection\Definition $handler |
219
|
|
|
* @param string $clientName |
220
|
|
|
* |
221
|
|
|
* @return void |
222
|
|
|
*/ |
223
|
|
View Code Duplication |
protected function defineLogMiddleware(ContainerBuilder $container, Definition $handler, string $clientName) |
|
|
|
|
224
|
|
|
{ |
225
|
|
|
$logMiddlewareDefinitionName = sprintf('eight_points_guzzle.middleware.log.%s', $clientName); |
226
|
|
|
$logMiddlewareDefinition = new Definition('%eight_points_guzzle.middleware.log.class%'); |
227
|
|
|
$logMiddlewareDefinition->addArgument(new Reference('eight_points_guzzle.logger')); |
228
|
|
|
$logMiddlewareDefinition->addArgument(new Reference('eight_points_guzzle.formatter')); |
229
|
|
|
$logMiddlewareDefinition->setPublic(true); |
230
|
|
|
$container->setDefinition($logMiddlewareDefinitionName, $logMiddlewareDefinition); |
231
|
|
|
|
232
|
|
|
$logExpression = new Expression(sprintf("service('%s').log()", $logMiddlewareDefinitionName)); |
233
|
|
|
$handler->addMethodCall('push', [$logExpression, 'log']); |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
/** |
237
|
|
|
* @param \Symfony\Component\DependencyInjection\Definition $handler |
238
|
|
|
* |
239
|
|
|
* @return void |
240
|
|
|
*/ |
241
|
|
|
protected function attachSymfonyLogMiddlewareToHandler(Definition $handler) |
242
|
|
|
{ |
243
|
|
|
$logExpression = new Expression(sprintf("service('%s')", 'eight_points_guzzle.middleware.symfony_log')); |
244
|
|
|
$handler->addMethodCall('push', [$logExpression, 'symfony_log']); |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
/** |
248
|
|
|
* Create Middleware For dispatching events |
249
|
|
|
* |
250
|
|
|
* @param string $name |
251
|
|
|
* |
252
|
|
|
* @return \Symfony\Component\DependencyInjection\Definition |
253
|
|
|
*/ |
254
|
|
|
protected function createEventMiddleware(string $name) : Definition |
255
|
|
|
{ |
256
|
|
|
$eventMiddleWare = new Definition('%eight_points_guzzle.middleware.event_dispatcher.class%'); |
257
|
|
|
$eventMiddleWare->addArgument(new Reference('event_dispatcher')); |
258
|
|
|
$eventMiddleWare->addArgument($name); |
259
|
|
|
$eventMiddleWare->setPublic(true); |
260
|
|
|
|
261
|
|
|
return $eventMiddleWare; |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
/** |
265
|
|
|
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container |
266
|
|
|
* |
267
|
|
|
* @return void |
268
|
|
|
*/ |
269
|
|
|
protected function defineSymfonyLogFormatter(ContainerBuilder $container) |
270
|
|
|
{ |
271
|
|
|
$formatterDefinition = new Definition('%eight_points_guzzle.symfony_log_formatter.class%'); |
272
|
|
|
$formatterDefinition->setArguments(['%eight_points_guzzle.symfony_log_formatter.pattern%']); |
273
|
|
|
$formatterDefinition->setPublic(true); |
274
|
|
|
$container->setDefinition('eight_points_guzzle.symfony_log_formatter', $formatterDefinition); |
275
|
|
|
} |
276
|
|
|
|
277
|
|
|
/** |
278
|
|
|
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container |
279
|
|
|
* |
280
|
|
|
* @return void |
281
|
|
|
*/ |
282
|
|
View Code Duplication |
protected function defineSymfonyLogMiddleware(ContainerBuilder $container) |
|
|
|
|
283
|
|
|
{ |
284
|
|
|
$logMiddlewareDefinition = new Definition('%eight_points_guzzle.middleware.symfony_log.class%'); |
285
|
|
|
$logMiddlewareDefinition->addArgument(new Reference('logger')); |
286
|
|
|
$logMiddlewareDefinition->addArgument(new Reference('eight_points_guzzle.symfony_log_formatter')); |
287
|
|
|
$logMiddlewareDefinition->setPublic(true); |
288
|
|
|
$logMiddlewareDefinition->addTag('monolog.logger', ['channel' => 'eight_points_guzzle']); |
289
|
|
|
$container->setDefinition('eight_points_guzzle.middleware.symfony_log', $logMiddlewareDefinition); |
290
|
|
|
} |
291
|
|
|
|
292
|
|
|
/** |
293
|
|
|
* Returns alias of extension |
294
|
|
|
* |
295
|
|
|
* @return string |
296
|
|
|
*/ |
297
|
|
|
public function getAlias() : string |
298
|
|
|
{ |
299
|
|
|
return 'eight_points_guzzle'; |
300
|
|
|
} |
301
|
|
|
} |
302
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.