summaryrefslogtreecommitdiff
path: root/vendor/symfony/cache/DependencyInjection
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/symfony/cache/DependencyInjection')
-rw-r--r--vendor/symfony/cache/DependencyInjection/CacheCollectorPass.php75
-rw-r--r--vendor/symfony/cache/DependencyInjection/CachePoolClearerPass.php38
-rw-r--r--vendor/symfony/cache/DependencyInjection/CachePoolPass.php243
-rw-r--r--vendor/symfony/cache/DependencyInjection/CachePoolPrunerPass.php48
4 files changed, 404 insertions, 0 deletions
diff --git a/vendor/symfony/cache/DependencyInjection/CacheCollectorPass.php b/vendor/symfony/cache/DependencyInjection/CacheCollectorPass.php
new file mode 100644
index 0000000..ed95740
--- /dev/null
+++ b/vendor/symfony/cache/DependencyInjection/CacheCollectorPass.php
@@ -0,0 +1,75 @@
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\TagAwareAdapterInterface;
15use Symfony\Component\Cache\Adapter\TraceableAdapter;
16use Symfony\Component\Cache\Adapter\TraceableTagAwareAdapter;
17use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
18use Symfony\Component\DependencyInjection\ContainerBuilder;
19use Symfony\Component\DependencyInjection\Definition;
20use Symfony\Component\DependencyInjection\Reference;
21
22/**
23 * Inject a data collector to all the cache services to be able to get detailed statistics.
24 *
25 * @author Tobias Nyholm <tobias.nyholm@gmail.com>
26 */
27class CacheCollectorPass implements CompilerPassInterface
28{
29 public function process(ContainerBuilder $container): void
30 {
31 if (!$container->hasDefinition('data_collector.cache')) {
32 return;
33 }
34
35 foreach ($container->findTaggedServiceIds('cache.pool') as $id => $attributes) {
36 $poolName = $attributes[0]['name'] ?? $id;
37
38 $this->addToCollector($id, $poolName, $container);
39 }
40 }
41
42 private function addToCollector(string $id, string $name, ContainerBuilder $container): void
43 {
44 $definition = $container->getDefinition($id);
45 if ($definition->isAbstract()) {
46 return;
47 }
48
49 $collectorDefinition = $container->getDefinition('data_collector.cache');
50 $recorder = new Definition(is_subclass_of($definition->getClass(), TagAwareAdapterInterface::class) ? TraceableTagAwareAdapter::class : TraceableAdapter::class);
51 $recorder->setTags($definition->getTags());
52 if (!$definition->isPublic() || !$definition->isPrivate()) {
53 $recorder->setPublic($definition->isPublic());
54 }
55 $recorder->setArguments([new Reference($innerId = $id.'.recorder_inner')]);
56
57 foreach ($definition->getMethodCalls() as [$method, $args]) {
58 if ('setCallbackWrapper' !== $method || !$args[0] instanceof Definition || !($args[0]->getArguments()[2] ?? null) instanceof Definition) {
59 continue;
60 }
61 if ([new Reference($id), 'setCallbackWrapper'] == $args[0]->getArguments()[2]->getFactory()) {
62 $args[0]->getArguments()[2]->setFactory([new Reference($innerId), 'setCallbackWrapper']);
63 }
64 }
65
66 $definition->setTags([]);
67 $definition->setPublic(false);
68
69 $container->setDefinition($innerId, $definition);
70 $container->setDefinition($id, $recorder);
71
72 // Tell the collector to add the new instance
73 $collectorDefinition->addMethodCall('addInstance', [$name, new Reference($id)]);
74 }
75}
diff --git a/vendor/symfony/cache/DependencyInjection/CachePoolClearerPass.php b/vendor/symfony/cache/DependencyInjection/CachePoolClearerPass.php
new file mode 100644
index 0000000..5449720
--- /dev/null
+++ b/vendor/symfony/cache/DependencyInjection/CachePoolClearerPass.php
@@ -0,0 +1,38 @@
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\DependencyInjection\Compiler\CompilerPassInterface;
15use Symfony\Component\DependencyInjection\ContainerBuilder;
16use Symfony\Component\DependencyInjection\Reference;
17
18/**
19 * @author Nicolas Grekas <p@tchwork.com>
20 */
21class CachePoolClearerPass implements CompilerPassInterface
22{
23 public function process(ContainerBuilder $container): void
24 {
25 $container->getParameterBag()->remove('cache.prefix.seed');
26
27 foreach ($container->findTaggedServiceIds('cache.pool.clearer') as $id => $attr) {
28 $clearer = $container->getDefinition($id);
29 $pools = [];
30 foreach ($clearer->getArgument(0) as $name => $ref) {
31 if ($container->hasDefinition($ref)) {
32 $pools[$name] = new Reference($ref);
33 }
34 }
35 $clearer->replaceArgument(0, $pools);
36 }
37 }
38}
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}
diff --git a/vendor/symfony/cache/DependencyInjection/CachePoolPrunerPass.php b/vendor/symfony/cache/DependencyInjection/CachePoolPrunerPass.php
new file mode 100644
index 0000000..69b69fb
--- /dev/null
+++ b/vendor/symfony/cache/DependencyInjection/CachePoolPrunerPass.php
@@ -0,0 +1,48 @@
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\PruneableInterface;
15use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
16use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
17use Symfony\Component\DependencyInjection\ContainerBuilder;
18use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
19use Symfony\Component\DependencyInjection\Reference;
20
21/**
22 * @author Rob Frawley 2nd <rmf@src.run>
23 */
24class CachePoolPrunerPass implements CompilerPassInterface
25{
26 public function process(ContainerBuilder $container): void
27 {
28 if (!$container->hasDefinition('console.command.cache_pool_prune')) {
29 return;
30 }
31
32 $services = [];
33
34 foreach ($container->findTaggedServiceIds('cache.pool') as $id => $tags) {
35 $class = $container->getParameterBag()->resolveValue($container->getDefinition($id)->getClass());
36
37 if (!$reflection = $container->getReflectionClass($class)) {
38 throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
39 }
40
41 if ($reflection->implementsInterface(PruneableInterface::class)) {
42 $services[$id] = new Reference($id);
43 }
44 }
45
46 $container->getDefinition('console.command.cache_pool_prune')->replaceArgument(0, new IteratorArgument($services));
47 }
48}