Completed
Pull Request — 2.x (#1258)
by
unknown
01:48
created

CacheWarmer::clearWarmed()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.8333
c 0
b 0
f 0
cc 4
nc 4
nop 2
1
<?php
2
3
/*
4
 * This file is part of the `liip/LiipImagineBundle` project.
5
 *
6
 * (c) https://github.com/liip/LiipImagineBundle/graphs/contributors
7
 *
8
 * For the full copyright and license information, please view the LICENSE.md
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Liip\ImagineBundle\Imagine\Cache;
13
14
use InvalidArgumentException;
15
use Liip\ImagineBundle\Imagine\Cache\Warmer\WarmerInterface;
16
use Liip\ImagineBundle\Imagine\Data\DataManager;
17
use Liip\ImagineBundle\Imagine\Filter\FilterManager;
18
19
class CacheWarmer
20
{
21
    /**
22
     * @var WarmerInterface[]
23
     */
24
    protected $warmers = [];
25
26
    /**
27
     * Chunk size to query warmer in one step
28
     *
29
     * @var int
30
     */
31
    protected $chunkSize = 100;
32
33
    /**
34
     * @var CacheManager
35
     */
36
    protected $cacheManager;
37
38
    /**
39
     * @var DataManager
40
     */
41
    protected $dataManager;
42
43
    /**
44
     * @var FilterManager
45
     */
46
    protected $filterManager;
47
48
    /**
49
     * @var callable
50
     */
51
    protected $loggerClosure;
52
53
    /**
54
     * CacheWarmer constructor.
55
     */
56
    public function __construct(DataManager $dataManager, FilterManager $filterManager)
57
    {
58
        $this->dataManager = $dataManager;
59
        $this->filterManager = $filterManager;
60
    }
61
62
    /**
63
     * @return CacheWarmer
64
     */
65
    public function setChunkSize(int $chunkSize): self
66
    {
67
        $this->chunkSize = $chunkSize;
68
69
        return $this;
70
    }
71
72
    /**
73
     * Sets logger closure - a callable which will be passed verbose messages
74
     *
75
     * @param callable $loggerClosure
76
     *
77
     * @return CacheWarmer
78
     */
79
    public function setLoggerClosure($loggerClosure): self
80
    {
81
        $this->loggerClosure = $loggerClosure;
82
83
        return $this;
84
    }
85
86
    /**
87
     * @return CacheWarmer
88
     */
89
    public function setCacheManager(CacheManager $cacheManager): self
90
    {
91
        $this->cacheManager = $cacheManager;
92
93
        return $this;
94
    }
95
96
    public function addWarmer(string $name, WarmerInterface $warmer)
97
    {
98
        $this->warmers[$name] = $warmer;
99
    }
100
101
    /**
102
     * @param bool       $force           If set to true, cache is warmed up for paths already stored in cached (regenerate thumbs)
103
     * @param array|null $selectedWarmers An optional array of warmers to process, if null - all warmers will be processed
104
     *
105
     * @throws InvalidArgumentException
106
     *
107
     * @return void
108
     */
109
    public function warm($force = false, $selectedWarmers = null)
110
    {
111
        $filtersByWarmer = $this->getFiltersByWarmers();
112
        if (!$filtersByWarmer) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $filtersByWarmer of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
113
            $this->log('No warmers are configured - add some as `warmers` param in your filter sets');
114
115
            return;
116
        }
117
118
        foreach ($filtersByWarmer as $warmerName => $filters) {
119
            if (isset($selectedWarmers) && !empty($selectedWarmers) && !in_array($warmerName, $selectedWarmers, true)) {
120
                $this->log(
121
                    sprintf(
122
                        'Skipping warmer %s as it\'s not listed in selected warmers: [%s]',
123
                        $warmerName,
124
                        implode(', ', $selectedWarmers)
125
                    )
126
                );
127
                continue;
128
            }
129
            if (!isset($this->warmers[$warmerName])) {
130
                throw new InvalidArgumentException(sprintf('Could not find warmer "%s"', $warmerName));
131
            }
132
133
            $this->log(sprintf('Processing warmer "%s"', $warmerName));
134
            $start = 0;
135
            $warmer = $this->warmers[$warmerName];
136
            while ($paths = $warmer->getPaths($start, $this->chunkSize)) {
137
                $this->log(
138
                    sprintf(
139
                        'Processing chunk %d - %d for warmer "%s"',
140
                        $start,
141
                        $start + $this->chunkSize,
142
                        $warmerName
143
                    )
144
                );
145
                $warmedPaths = $this->warmPaths($paths, $filters, $force);
146
                $warmer->setWarmed($warmedPaths);
147
                $start += count($paths) - count($warmedPaths);
148
            }
149
            $this->log(sprintf('Finished processing warmer "%s"', $warmerName));
150
        }
151
    }
152
153
    public function clearWarmed(array $paths, array $filters)
154
    {
155
        $filtersByWarmer = $this->getFiltersByWarmers();
156
        foreach ($filtersByWarmer as $warmerName => $warmerFilters) {
157
            if (array_intersect($filters, $warmerFilters)) {
158
                if (!isset($this->warmers[$warmerName])) {
159
                    throw new InvalidArgumentException(sprintf('Could not find warmer "%s"', $warmerName));
160
                }
161
                $warmer = $this->warmers[$warmerName];
162
                $warmer->clearWarmed($paths);
163
            }
164
        }
165
    }
166
167
    protected function getFiltersByWarmers(): array
168
    {
169
        $all = $this->filterManager->getFilterConfiguration()->all();
170
        $warmers = [];
171
        foreach ($all as $filterSet => $config) {
172
            if (isset($config['warmers']) && $config['warmers']) {
173
                foreach ($config['warmers'] as $warmer) {
174
                    if (!isset($warmers[$warmer])) {
175
                        $warmers[$warmer] = [$filterSet];
176
                    } else {
177
                        $warmers[$warmer][] = $filterSet;
178
                    }
179
                }
180
            }
181
        }
182
183
        return $warmers;
184
    }
185
186
    protected function warmPaths(array $paths, array $filters, bool $force): array
187
    {
188
        $successfulWarmedPaths = [];
189
        foreach ($paths as $pathData) {
190
            $aPath = $pathData['path'];
191
            $binaries = [];
192
            foreach ($filters as $filter) {
193
                $this->log(sprintf('Warming up path "%s" for filter "%s"', $aPath, $filter));
194
195
                $isStored = $this->cacheManager->isStored($aPath, $filter);
196
                if ($force || !$isStored) {
197
                    // this is to avoid loading binary with the same loader for multiple filters
198
                    $loader = $this->dataManager->getLoader($filter);
199
                    $isStored = false;
200
201
                    try {
202
                        $hash = spl_object_hash($loader);
203
                        if (!isset($binaries[$hash])) {
204
                            // if NotLoadable is thrown - it will just bubble up
205
                            // everything returned by Warmer should be loadable
206
                            $binaries[$hash] = $this->dataManager->find($filter, $aPath);
207
                        }
208
                        $this->cacheManager->store(
209
                            $this->filterManager->applyFilter($binaries[$hash], $filter),
210
                            $aPath,
211
                            $filter
212
                        );
213
214
                        $isStored = true;
215
                    } catch (\RuntimeException $e) {
216
                        $message = sprintf('Unable to warm cache for filter "%s", due to - "%s"',
217
                            $filter, $e->getMessage());
218
                        $this->log($message, 'error');
219
                    }
220
                }
221
222
                if ($isStored) {
223
                    $successfulWarmedPaths[] = $pathData;
224
                }
225
            }
226
        }
227
228
        return $successfulWarmedPaths;
229
    }
230
231
    /**
232
     * @param string $type
233
     */
234
    protected function log(string $message, $type = 'info')
235
    {
236
        if (is_callable($this->loggerClosure)) {
237
            $loggerClosure = $this->loggerClosure;
238
            $loggerClosure($message, $type);
239
        }
240
    }
241
}
242