Completed
Pull Request — master (#4264)
by Craig
06:09
created

CacheClearer::doClear()   B

Complexity

Conditions 8
Paths 13

Size

Total Lines 28
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 14
c 0
b 0
f 0
nc 13
nop 0
dl 0
loc 28
rs 8.4444
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Zikula package.
7
 *
8
 * Copyright Zikula - https://ziku.la/
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Zikula\Bundle\CoreBundle;
15
16
use FilesystemIterator;
17
use FOS\JsRoutingBundle\Extractor\ExposedRoutesExtractorInterface;
18
use Psr\Log\LoggerInterface;
19
use Symfony\Component\Filesystem\Filesystem;
20
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
21
22
class CacheClearer
23
{
24
    /**
25
     * @var LoggerInterface
26
     */
27
    private $logger;
28
29
    /**
30
     * @var ExposedRoutesExtractorInterface
31
     */
32
    private $fosJsRoutesExtractor;
33
34
    /**
35
     * @var string
36
     */
37
    private $cacheDir;
38
39
    /**
40
     * @var string
41
     */
42
    private $kernelContainerClass;
43
44
    /**
45
     * @var bool
46
     */
47
    private $installed;
48
49
    /**
50
     * @var array
51
     */
52
    private $routingLocales = [];
53
54
    /**
55
     * @var array
56
     */
57
    private $cacheTypes = [];
58
59
    /**
60
     * @var Filesystem
61
     */
62
    private $fileSystem;
63
64
    /**
65
     * @var CacheWarmerInterface
66
     */
67
    private $warmer;
68
69
    /**
70
     * @var array
71
     */
72
    private $cachesToClear;
73
74
    public function __construct(
75
        LoggerInterface $zikulaLogger,
76
        CacheWarmerInterface $warmer,
77
        ExposedRoutesExtractorInterface $fosJsRoutesExtractor,
78
        string $cacheDir,
79
        string $kernelContainerClass,
80
        string $installed,
81
        array $routingLocales = []
82
    ) {
83
        $this->logger = $zikulaLogger;
84
        $this->warmer = $warmer;
85
        $this->fosJsRoutesExtractor = $fosJsRoutesExtractor;
86
        $this->cacheDir = $cacheDir;
87
        $this->kernelContainerClass = $kernelContainerClass;
88
        $this->installed = '0.0.0' !== $installed;
89
        $this->routingLocales = $routingLocales;
90
        $this->fileSystem = new Filesystem();
91
        $this->cachesToClear = [];
92
    }
93
94
    /**
95
     * The cache is not cleared on demand.
96
     * Calling 'clear' will store caches to clear
97
     * This ensures no duplication and defers actual clearing
98
     * until kernel.terminate event
99
     * @see \Zikula\Bundle\CoreBundle\EventListener\CacheClearListener::doClearCache
100
     */
101
    public function clear(string $type): void
102
    {
103
        if (!isset($this->cachesToClear[$type])) {
104
            foreach ($this->cachesToClear as $value) {
105
                if (0 === mb_strpos($type, $value)) {
106
                    return;
107
                }
108
            }
109
            $this->cachesToClear[$type] = $type;
110
        }
111
    }
112
113
    /**
114
     * @internal
115
     * This is not a public api
116
     */
117
    public function doClear(): void
118
    {
119
        if (empty($this->cachesToClear)) {
120
            return;
121
        }
122
123
        if (!count($this->cacheTypes)) {
124
            $this->initialiseCacheTypeMap();
125
        }
126
        foreach ($this->cachesToClear as $type) {
127
            foreach ($this->cacheTypes as $cacheType => $files) {
128
                if (0 !== mb_strpos($cacheType, $type)) {
129
                    continue;
130
                }
131
                foreach ($files as $file) {
132
                    if (is_dir($file)) {
133
                        // Do not delete the folder itself, but all files in it.
134
                        // Otherwise Symfony somehow can't create the folder anymore.
135
                        $file = new FilesystemIterator($file);
136
                    }
137
                    // This silently ignores non existing files.
138
                    $this->fileSystem->remove($file);
139
                }
140
                $this->logger->notice(sprintf('Cache cleared: %s', $cacheType));
141
            }
142
        }
143
        // the cache must be warmed after deleting files
144
        $this->warmer->warmUp($this->cacheDir);
145
    }
146
147
    private function initialiseCacheTypeMap()
148
    {
149
        $fosJsRoutingFiles = [];
150
        if ($this->installed) {
151
            // avoid accessing FOS extractor before/during installation
152
            // because this requires request context
153
154
            foreach ($this->routingLocales as $locale) {
155
                $fosJsRoutingFiles[] = $this->fosJsRoutesExtractor->getCachePath($locale);
156
            }
157
        }
158
159
        $cacheFolder = $this->cacheDir . DIRECTORY_SEPARATOR;
160
161
        $this->cacheTypes = [
162
            'symfony.routing.generator' => [
163
                $cacheFolder . 'url_generating_routes.php',
164
                $cacheFolder . 'url_generating_routes.php.meta'
165
            ],
166
            'symfony.routing.matcher' => [
167
                $cacheFolder . 'url_matching_routes.php',
168
                $cacheFolder . 'url_matching_routes.php.meta'
169
            ],
170
            'symfony.routing.fosjs' => $fosJsRoutingFiles,
171
            'symfony.config' => [
172
                // clearing the container class will force all other container files
173
                // to be rebuilt so there is no need to delete all of them
174
                // nor a need to delete the container directory
175
                $cacheFolder . $this->kernelContainerClass . '.php',
176
            ],
177
            'symfony.translations' => [
178
                $cacheFolder . '/translations'
179
            ],
180
            'twig' => [
181
                $cacheFolder . 'twig'
182
            ],
183
            'purifier' => [
184
                $cacheFolder . 'purifier'
185
            ],
186
            'assets' => [
187
                $cacheFolder . 'assets'
188
            ]
189
        ];
190
    }
191
}
192