summaryrefslogtreecommitdiff
path: root/vendor/symfony/cache/DependencyInjection/CachePoolPass.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/symfony/cache/DependencyInjection/CachePoolPass.php')
-rw-r--r--vendor/symfony/cache/DependencyInjection/CachePoolPass.php243
1 files changed, 243 insertions, 0 deletions
diff --git a/vendor/symfony/cache/DependencyInjection/CachePoolPass.php b/vendor/symfony/cache/DependencyInjection/CachePoolPass.php
new file mode 100644
index 0000000..081d82c
--- /dev/null
+++ b/vendor/symfony/cache/DependencyInjection/CachePoolPass.php
@@ -0,0 +1,243 @@
1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Cache\DependencyInjection;
13
14use Symfony\Component\Cache\Adapter\AbstractAdapter;
15use Symfony\Component\Cache\Adapter\ArrayAdapter;
16use Symfony\Component\Cache\Adapter\ChainAdapter;
17use Symfony\Component\Cache\Adapter\NullAdapter;
18use Symfony\Component\Cache\Adapter\ParameterNormalizer;
19use Symfony\Component\Cache\Messenger\EarlyExpirationDispatcher;
20use Symfony\Component\DependencyInjection\ChildDefinition;
21use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
22use Symfony\Component\DependencyInjection\ContainerBuilder;
23use Symfony\Component\DependencyInjection\Definition;
24use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
25use Symfony\Component\DependencyInjection\Reference;
26
27/**
28 * @author Nicolas Grekas <p@tchwork.com>
29 */
30class CachePoolPass implements CompilerPassInterface
31{
32 public function process(ContainerBuilder $container): void
33 {
34 if ($container->hasParameter('cache.prefix.seed')) {
35 $seed = $container->getParameterBag()->resolveValue($container->getParameter('cache.prefix.seed'));
36 } else {
37 $seed = '_'.$container->getParameter('kernel.project_dir');
38 $seed .= '.'.$container->getParameter('kernel.container_class');
39 }
40
41 $needsMessageHandler = false;
42 $allPools = [];
43 $clearers = [];
44 $attributes = [
45 'provider',
46 'name',
47 'namespace',
48 'default_lifetime',
49 'early_expiration_message_bus',
50 'reset',
51 ];
52 foreach ($container->findTaggedServiceIds('cache.pool') as $id => $tags) {
53 $adapter = $pool = $container->getDefinition($id);
54 if ($pool->isAbstract()) {
55 continue;
56 }
57 $class = $adapter->getClass();
58 while ($adapter instanceof ChildDefinition) {
59 $adapter = $container->findDefinition($adapter->getParent());
60 $class = $class ?: $adapter->getClass();
61 if ($t = $adapter->getTag('cache.pool')) {
62 $tags[0] += $t[0];
63 }
64 }
65 $name = $tags[0]['name'] ?? $id;
66 if (!isset($tags[0]['namespace'])) {
67 $namespaceSeed = $seed;
68 if (null !== $class) {
69 $namespaceSeed .= '.'.$class;
70 }
71
72 $tags[0]['namespace'] = $this->getNamespace($namespaceSeed, $name);
73 }
74 if (isset($tags[0]['clearer'])) {
75 $clearer = $tags[0]['clearer'];
76 while ($container->hasAlias($clearer)) {
77 $clearer = (string) $container->getAlias($clearer);
78 }
79 } else {
80 $clearer = null;
81 }
82 unset($tags[0]['clearer'], $tags[0]['name']);
83
84 if (isset($tags[0]['provider'])) {
85 $tags[0]['provider'] = new Reference(static::getServiceProvider($container, $tags[0]['provider']));
86 }
87
88 if (ChainAdapter::class === $class) {
89 $adapters = [];
90 foreach ($adapter->getArgument(0) as $provider => $adapter) {
91 if ($adapter instanceof ChildDefinition) {
92 $chainedPool = $adapter;
93 } else {
94 $chainedPool = $adapter = new ChildDefinition($adapter);
95 }
96
97 $chainedTags = [\is_int($provider) ? [] : ['provider' => $provider]];
98 $chainedClass = '';
99
100 while ($adapter instanceof ChildDefinition) {
101 $adapter = $container->findDefinition($adapter->getParent());
102 $chainedClass = $chainedClass ?: $adapter->getClass();
103 if ($t = $adapter->getTag('cache.pool')) {
104 $chainedTags[0] += $t[0];
105 }
106 }
107
108 if (ChainAdapter::class === $chainedClass) {
109 throw new InvalidArgumentException(sprintf('Invalid service "%s": chain of adapters cannot reference another chain, found "%s".', $id, $chainedPool->getParent()));
110 }
111
112 $i = 0;
113
114 if (isset($chainedTags[0]['provider'])) {
115 $chainedPool->replaceArgument($i++, new Reference(static::getServiceProvider($container, $chainedTags[0]['provider'])));
116 }
117
118 if (isset($tags[0]['namespace']) && !\in_array($adapter->getClass(), [ArrayAdapter::class, NullAdapter::class], true)) {
119 $chainedPool->replaceArgument($i++, $tags[0]['namespace']);
120 }
121
122 if (isset($tags[0]['default_lifetime'])) {
123 $chainedPool->replaceArgument($i++, $tags[0]['default_lifetime']);
124 }
125
126 $adapters[] = $chainedPool;
127 }
128
129 $pool->replaceArgument(0, $adapters);
130 unset($tags[0]['provider'], $tags[0]['namespace']);
131 $i = 1;
132 } else {
133 $i = 0;
134 }
135
136 foreach ($attributes as $attr) {
137 if (!isset($tags[0][$attr])) {
138 // no-op
139 } elseif ('reset' === $attr) {
140 if ($tags[0][$attr]) {
141 $pool->addTag('kernel.reset', ['method' => $tags[0][$attr]]);
142 }
143 } elseif ('early_expiration_message_bus' === $attr) {
144 $needsMessageHandler = true;
145 $pool->addMethodCall('setCallbackWrapper', [(new Definition(EarlyExpirationDispatcher::class))
146 ->addArgument(new Reference($tags[0]['early_expiration_message_bus']))
147 ->addArgument(new Reference('reverse_container'))
148 ->addArgument((new Definition('callable'))
149 ->setFactory([new Reference($id), 'setCallbackWrapper'])
150 ->addArgument(null)
151 ),
152 ]);
153 $pool->addTag('container.reversible');
154 } elseif ('namespace' !== $attr || !\in_array($class, [ArrayAdapter::class, NullAdapter::class], true)) {
155 $argument = $tags[0][$attr];
156
157 if ('default_lifetime' === $attr && !is_numeric($argument)) {
158 $argument = (new Definition('int', [$argument]))
159 ->setFactory([ParameterNormalizer::class, 'normalizeDuration']);
160 }
161
162 $pool->replaceArgument($i++, $argument);
163 }
164 unset($tags[0][$attr]);
165 }
166 if (!empty($tags[0])) {
167 throw new InvalidArgumentException(sprintf('Invalid "cache.pool" tag for service "%s": accepted attributes are "clearer", "provider", "name", "namespace", "default_lifetime", "early_expiration_message_bus" and "reset", found "%s".', $id, implode('", "', array_keys($tags[0]))));
168 }
169
170 if (null !== $clearer) {
171 $clearers[$clearer][$name] = new Reference($id, $container::IGNORE_ON_UNINITIALIZED_REFERENCE);
172 }
173
174 $allPools[$name] = new Reference($id, $container::IGNORE_ON_UNINITIALIZED_REFERENCE);
175 }
176
177 if (!$needsMessageHandler) {
178 $container->removeDefinition('cache.early_expiration_handler');
179 }
180
181 $notAliasedCacheClearerId = 'cache.global_clearer';
182 while ($container->hasAlias($notAliasedCacheClearerId)) {
183 $notAliasedCacheClearerId = (string) $container->getAlias($notAliasedCacheClearerId);
184 }
185 if ($container->hasDefinition($notAliasedCacheClearerId)) {
186 $clearers[$notAliasedCacheClearerId] = $allPools;
187 }
188
189 foreach ($clearers as $id => $pools) {
190 $clearer = $container->getDefinition($id);
191 if ($clearer instanceof ChildDefinition) {
192 $clearer->replaceArgument(0, $pools);
193 } else {
194 $clearer->setArgument(0, $pools);
195 }
196 $clearer->addTag('cache.pool.clearer');
197
198 if ('cache.system_clearer' === $id) {
199 $clearer->addTag('kernel.cache_clearer');
200 }
201 }
202
203 $allPoolsKeys = array_keys($allPools);
204
205 if ($container->hasDefinition('console.command.cache_pool_list')) {
206 $container->getDefinition('console.command.cache_pool_list')->replaceArgument(0, $allPoolsKeys);
207 }
208
209 if ($container->hasDefinition('console.command.cache_pool_clear')) {
210 $container->getDefinition('console.command.cache_pool_clear')->addArgument($allPoolsKeys);
211 }
212
213 if ($container->hasDefinition('console.command.cache_pool_delete')) {
214 $container->getDefinition('console.command.cache_pool_delete')->addArgument($allPoolsKeys);
215 }
216 }
217
218 private function getNamespace(string $seed, string $id): string
219 {
220 return substr(str_replace('/', '-', base64_encode(hash('xxh128', $id.$seed, true))), 0, 10);
221 }
222
223 /**
224 * @internal
225 */
226 public static function getServiceProvider(ContainerBuilder $container, string $name): string
227 {
228 $container->resolveEnvPlaceholders($name, null, $usedEnvs);
229
230 if ($usedEnvs || preg_match('#^[a-z]++:#', $name)) {
231 $dsn = $name;
232
233 if (!$container->hasDefinition($name = '.cache_connection.'.ContainerBuilder::hash($dsn))) {
234 $definition = new Definition(AbstractAdapter::class);
235 $definition->setFactory([AbstractAdapter::class, 'createConnection']);
236 $definition->setArguments([$dsn, ['lazy' => true]]);
237 $container->setDefinition($name, $definition);
238 }
239 }
240
241 return $name;
242 }
243}