Completed
Pull Request — master (#47)
by Mateusz
07:52 queued 04:50
created

CacheManagerImpl::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 8
c 0
b 0
f 0
ccs 7
cts 7
cp 1
rs 9.4285
cc 1
eloc 6
nc 1
nop 3
crap 1
1
<?php
2
3
/*
4
 * This file is part of the puli/manager package.
5
 *
6
 * (c) Bernhard Schussek <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Puli\Manager\Cache;
13
14
use Puli\Manager\Api\Cache\CacheFile;
15
use Puli\Manager\Api\Cache\CacheManager;
16
use Puli\Manager\Api\Config\Config;
17
use Puli\Manager\Api\Context\ProjectContext;
18
use Puli\Manager\Api\Module\Module;
19
use Puli\Manager\Api\Module\ModuleFile;
20
use Puli\Manager\Api\Module\ModuleList;
21
use Puli\Manager\Api\Module\ModuleManager;
22
use Puli\Manager\Api\Module\RootModule;
23
use Puli\Manager\Api\Module\RootModuleFile;
24
use Puli\Manager\Assert\Assert;
25
use Puli\Manager\Json\JsonStorage;
26
use Webmozart\Expression\Expr;
27
use Webmozart\Expression\Expression;
28
use Webmozart\PathUtil\Path;
29
30
/**
31
 * Manages cached Modules information.
32
 *
33
 * @since  1.0
34
 *
35
 * @author Mateusz Sojda <[email protected]>
36
 */
37
class CacheManagerImpl implements CacheManager
38
{
39
    /**
40
     * @var CacheFile
41
     */
42
    private $cacheFile;
43
44
    /**
45
     * @var ModuleManager
46
     */
47
    private $moduleManager;
48
49
    /**
50
     * @var JsonStorage
51
     */
52
    private $storage;
53
54
    /**
55
     * @var ProjectContext
56
     */
57
    private $context;
58
59
    /**
60
     * @var string
61
     */
62
    private $rootDir;
63
64
    /**
65
     * @var RootModuleFile
66
     */
67
    private $rootModuleFile;
68
69
    /**
70
     * @var ModuleList
71
     */
72
    private $modules;
73
74
    /**
75
     * Creates new cache manager.
76
     *
77
     * @param ModuleManager  $moduleManager The module manager.
78
     * @param JsonStorage    $storage       The file storage.
79
     * @param ProjectContext $context       Project context.
80
     */
81 29
    public function __construct(ModuleManager $moduleManager, JsonStorage $storage, ProjectContext $context)
82
    {
83 29
        $this->moduleManager = $moduleManager;
84 29
        $this->storage = $storage;
85 29
        $this->context = $context;
86 29
        $this->rootDir = $context->getRootDirectory();
87 29
        $this->rootModuleFile = $context->getRootModuleFile();
88 29
    }
89
90
    /**
91
     * {@inheritdoc}
92
     */
93 27
    public function getContext()
94
    {
95 27
        return $this->context;
96
    }
97
98
    /**
99
     * {@inheritdoc}
100
     */
101 23
    public function getCacheFile()
102
    {
103 23
        $path = $this->getContext()->getConfig()->get(Config::CACHE_FILE);
104 23
        $path = Path::makeAbsolute($path, $this->rootDir);
105
106 23
        if (!$this->storage->fileExists($path)) {
107 22
            $this->refreshCacheFile();
108
        }
109
110 23
        if (false === $this->cacheFile instanceof CacheFile) {
111 23
            $this->cacheFile = $this->storage->loadCacheFile($path);
112
        }
113
114 23
        return $this->cacheFile;
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     */
120 26
    public function refreshCacheFile()
121
    {
122 26
        $path = $this->getContext()->getConfig()->get(Config::CACHE_FILE);
123 26
        $path = Path::makeAbsolute($path, $this->rootDir);
124
125 26
        if ($this->storage->fileExists($path) && !$this->isRootModuleFileModified()) {
126 1
            return;
127
        }
128
129 25
        $cacheFile = new CacheFile(Path::makeAbsolute($path, $this->rootDir));
130
131 25
        foreach ($this->getInstalledModules() as $module) {
132 25
            $moduleFile = $module->getModuleFile();
133 25
            if (!$moduleFile instanceof ModuleFile) {
134
                continue;
135
            }
136
137 25
            $cacheFile->addModuleFile($moduleFile);
138
139 25
            $installInfo = $module->getInstallInfo();
140 25
            $cacheFile->addInstallInfo($installInfo);
141
        }
142
143 25
        $this->storage->saveCacheFile($cacheFile);
144
145 25
        $this->cacheFile = null;
146 25
    }
147
148
    /**
149
     * {@inheritdoc}
150
     */
151 2
    public function getModule($name)
152
    {
153 2
        Assert::string($name, 'The module name must be a string. Got: %s');
154
155 1
        $this->assertModulesLoaded();
156
157 1
        return $this->modules->get($name);
158
    }
159
160
    /**
161
     * {@inheritdoc}
162
     */
163 1
    public function getRootModule()
164
    {
165 1
        $this->assertModulesLoaded();
166
167 1
        return $this->modules->getRootModule();
168
    }
169
170
    /**
171
     * {@inheritdoc}
172
     */
173 16
    public function getModules()
174
    {
175 16
        $this->assertModulesLoaded();
176
177 16
        return clone $this->modules;
178
    }
179
180
    /**
181
     * {@inheritdoc}
182
     */
183 4 View Code Duplication
    public function findModules(Expression $expr)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
184
    {
185 4
        $this->assertModulesLoaded();
186
187 4
        $modules = new ModuleList();
188
189 4
        foreach ($this->modules as $module) {
190 4
            if ($expr->evaluate($module)) {
191 4
                $modules->add($module);
192
            }
193
        }
194
195 4
        return $modules;
196
    }
197
198
    /**
199
     * {@inheritdoc}
200
     */
201 2
    public function hasModule($name)
202
    {
203 2
        Assert::string($name, 'The module name must be a string. Got: %s');
204
205 1
        $this->assertModulesLoaded();
206
207 1
        return $this->modules->contains($name);
208
    }
209
210
    /**
211
     * {@inheritdoc}
212
     */
213 1 View Code Duplication
    public function hasModules(Expression $expr = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
214
    {
215 1
        $this->assertModulesLoaded();
216
217 1
        if (!$expr) {
218 1
            return !$this->modules->isEmpty();
219
        }
220
221 1
        foreach ($this->modules as $module) {
222 1
            if ($expr->evaluate($module)) {
223 1
                return true;
224
            }
225
        }
226
227 1
        return false;
228
    }
229
230 21
    private function assertModulesLoaded()
231
    {
232 21
        if (!$this->modules) {
233 21
            $this->loadModules();
234
        }
235 21
    }
236
237 21
    private function loadModules()
238
    {
239 21
        $cacheFile = $this->getCacheFile();
240
241 21
        $this->modules = new ModuleList();
242 21
        $this->modules->add(new RootModule($this->rootModuleFile, $this->rootDir));
243
244 21
        foreach ($cacheFile->getModuleFiles() as $moduleFile) {
245 21
            $this->modules->add($this->buildModule($moduleFile, $cacheFile));
246
        }
247 21
    }
248
249 25
    private function getInstalledModules()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
250
    {
251 25
        $modules = $this->moduleManager->findModules(Expr::true());
252
253 25
        return $modules->getInstalledModules();
254
    }
255
256 21
    private function buildModule(ModuleFile $moduleFile, CacheFile $cacheFile)
257
    {
258 21
        $installInfo = $cacheFile->getInstallInfo($moduleFile->getModuleName());
259 21
        $installPath = Path::makeAbsolute($installInfo->getInstallPath(), $this->rootDir);
260
261 21
        return new Module($moduleFile, $installPath, $installInfo);
262
    }
263
264 3
    private function isRootModuleFileModified()
265
    {
266 3
        $cacheFilePath = $this->getContext()->getConfig()->get(Config::CACHE_FILE);
267 3
        $cacheFilePath = Path::makeAbsolute($cacheFilePath, $this->rootDir);
268
269 3
        clearstatcache(true, $cacheFilePath);
270 3
        $cacheFileMtime = filemtime($cacheFilePath);
271
272 3
        $rootModuleFilePath = $this->rootModuleFile->getPath();
273
274 3
        if (false === $this->storage->fileExists($rootModuleFilePath)) {
275 1
            return true;
276
        }
277
278 2
        clearstatcache(true, $rootModuleFilePath);
279 2
        $rootModuleFileMtime = filemtime($rootModuleFilePath);
280
281 2
        if ($rootModuleFileMtime > $cacheFileMtime) {
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return $rootModuleFileMtime > $cacheFileMtime;.
Loading history...
282 1
            return true;
283
        }
284
285 1
        return false;
286
    }
287
}
288