Completed
Push — develop ( 8fda15...dbbcf5 )
by Jaap
14s
created

Descriptor/Cache/ProjectDescriptorMapper.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * phpDocumentor
4
 *
5
 * PHP Version 5.3
6
 *
7
 * @copyright 2010-2018 Mike van Riel / Naenius (http://www.naenius.com)
8
 * @license   http://www.opensource.org/licenses/mit-license.php MIT
9
 * @link      http://phpdoc.org
10
 */
11
12
namespace phpDocumentor\Descriptor\Cache;
13
14
use phpDocumentor\Descriptor\FileDescriptor;
15
use phpDocumentor\Descriptor\ProjectDescriptor;
16
use phpDocumentor\Descriptor\ProjectDescriptor\Settings;
17
use phpDocumentor\Fileset\Collection;
18
use Zend\Cache\Storage\IterableInterface;
19
use Zend\Cache\Storage\OptimizableInterface;
20
use Zend\Cache\Storage\StorageInterface;
21
22
/**
23
 * Maps a projectDescriptor to and from a cache instance.
24
 */
25
final class ProjectDescriptorMapper
26
{
27
    const FILE_PREFIX = 'file_';
28
29
    const KEY_SETTINGS = 'settings';
30
31
    /** @var StorageInterface|IterableInterface */
32
    private $cache;
33
34
    /**
35
     * Initializes this mapper with the given cache instance.
36
     */
37
    public function __construct(StorageInterface $cache)
38
    {
39
        if (!$cache instanceof IterableInterface) {
40
            throw new \InvalidArgumentException('ProjectDescriptorMapper should also be an iterable Storage type');
41
        }
42
43
        $this->cache = $cache;
44
    }
45
46
    /**
47
     * Returns the Cache instance for this Mapper.
48
     */
49
    public function getCache(): StorageInterface
50
    {
51
        return $this->cache;
52
    }
53
54
    /**
55
     * Returns the Project Descriptor from the cache.
56
     */
57
    public function populate(ProjectDescriptor $projectDescriptor)
58
    {
59
        $this->loadCacheItemAsSettings($projectDescriptor, self::KEY_SETTINGS);
60
61
        foreach ($this->getCache() as $key) {
62
            $this->loadCacheItemAsFile($projectDescriptor, $key);
63
        }
64
    }
65
66
    /**
67
     * Stores a Project Descriptor in the Cache.
68
     */
69
    public function save(ProjectDescriptor $projectDescriptor)
70
    {
71
        $keys = [];
72
        $cache = $this->getCache();
73
74
        foreach ($cache as $key) {
75
            $keys[] = $key;
76
        }
77
78
        // store the settings for this Project Descriptor
79
        $cache->setItem(self::KEY_SETTINGS, $projectDescriptor->getSettings());
80
81
        // store cache items
82
        $usedKeys = [self::KEY_SETTINGS];
83
        foreach ($projectDescriptor->getFiles() as $file) {
84
            $key = self::FILE_PREFIX . md5($file->getPath());
85
            $usedKeys[] = $key;
86
            $cache->setItem($key, $file);
87
        }
88
89
        // remove any keys that are no longer used.
90
        $invalidatedKeys = array_diff($keys, $usedKeys);
91
        if ($invalidatedKeys) {
92
            $cache->removeItems($invalidatedKeys);
93
        }
94
95
        if ($cache instanceof OptimizableInterface) {
96
            $cache->optimize();
97
        }
98
    }
99
100
    /**
101
     * Removes all files in cache that do not occur in the given FileSet Collection.
102
     */
103
    public function garbageCollect(Collection $collection)
104
    {
105
        $projectRoot = $collection->getProjectRoot();
106
        $filenames = $collection->getFilenames();
107
108
        foreach ($filenames as &$name) {
109
            // the cache key contains a path relative to the project root; here we expect absolute paths.
110
            $name = self::FILE_PREFIX . md5(substr($name, strlen($projectRoot)));
111
        }
112
113
        foreach ($this->getCache() as $item) {
0 ignored issues
show
The expression $this->getCache() of type object<Zend\Cache\Storage\StorageInterface> is not traversable.
Loading history...
114
            if (substr($item, 0, strlen(self::FILE_PREFIX)) === self::FILE_PREFIX && !in_array($item, $filenames, true)) {
115
                $this->getCache()->removeItem($item);
116
            }
117
        }
118
    }
119
120
    private function loadCacheItemAsFile(ProjectDescriptor $projectDescriptor, string $key)
121
    {
122
        $item = $this->getCache()->getItem($key);
123
124
        if ($item instanceof FileDescriptor) {
125
            $projectDescriptor->getFiles()->set($item->getPath(), $item);
126
        }
127
    }
128
129
    private function loadCacheItemAsSettings(ProjectDescriptor $projectDescriptor, string $key)
130
    {
131
        $item = $this->getCache()->getItem($key);
132
133
        if ($item instanceof Settings) {
134
            $projectDescriptor->setSettings($item);
135
        }
136
    }
137
}
138