Completed
Push — develop ( 71fd61...bbac44 )
by Jaap
06:03 queued 02:27
created

Descriptor/Cache/ProjectDescriptorMapper.php (1 issue)

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-2014 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 Zend\Cache\Storage\IterableInterface;
15
use Zend\Cache\Storage\IteratorInterface;
16
use Zend\Cache\Storage\OptimizableInterface;
17
use Zend\Cache\Storage\StorageInterface;
18
use phpDocumentor\Descriptor\FileDescriptor;
19
use phpDocumentor\Descriptor\ProjectDescriptor;
20
use phpDocumentor\Descriptor\ProjectDescriptor\Settings;
21
use phpDocumentor\Fileset\Collection;
22
23
/**
24
 * Maps a projectDescriptor to and from a cache instance.
25
 */
26
class ProjectDescriptorMapper
27
{
28
    const FILE_PREFIX = 'file_';
29
30
    const KEY_SETTINGS = 'settings';
31
32
    /** @var StorageInterface|IterableInterface */
33
    protected $cache;
34
35
    /**
36
     * Initializes this mapper with the given cache instance.
37
     * @param StorageInterface $cache
38
     */
39
    public function __construct(StorageInterface $cache)
40
    {
41
        $this->cache = $cache;
42
    }
43
44
    /**
45
     * Returns the Cache instance for this Mapper.
46
     *
47
     * @return IterableInterface|StorageInterface
48
     */
49
    public function getCache()
50
    {
51
        return $this->cache;
52
    }
53
54
    /**
55
     * Returns the Project Descriptor from the cache.
56
     *
57
     * @param ProjectDescriptor $projectDescriptor
58
     *
59
     * @return void
60
     */
61
    public function populate(ProjectDescriptor $projectDescriptor)
62
    {
63
        /** @var IteratorInterface $iteratorInterface */
64
        $iteratorInterface = $this->getCache()->getIterator();
65
66
        // load the settings object
67
        try {
68
            $settings = $this->getCache()->getItem(self::KEY_SETTINGS);
69
        } catch (\Exception $e) {
70
            $settings = $this->igBinaryCompatibleCacheClear(self::KEY_SETTINGS, $e);
71
        }
72
73
        if ($settings instanceof Settings) {
74
            $projectDescriptor->setSettings($settings);
75
        }
76
77
        // FIXME: Workaround for: https://github.com/zendframework/zf2/pull/4154
78
        if ($iteratorInterface->valid()) {
79
            foreach ($this->getCache() as $key) {
80
                try {
81
                    $item = $this->getCache()->getItem($key);
82
                } catch (\Exception $e) {
83
                    $this->igBinaryCompatibleCacheClear($key, $e);
84
                }
85
86
                if ($item instanceof FileDescriptor) {
87
                    $projectDescriptor->getFiles()->set($item->getPath(), $item);
88
                }
89
            }
90
        }
91
    }
92
93
    /**
94
     * Clears the cache if a serialization exception was thrown
95
     *
96
     * @param string $key
97
     * @param \Exception $e
98
     *
99
     * @throws \Exception Rethrows exception if nessesary
100
     *
101
     * @return void
102
     */
103
    protected function igBinaryCompatibleCacheClear($key, $e)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $e. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
104
    {
105
        if (extension_loaded('igbinary')) {
106
            $this->getCache()->removeItem($key);
107
        } else {
108
            throw $e;
109
        }
110
    }
111
112
    /**
113
     * Stores a Project Descriptor in the Cache.
114
     *
115
     * @param ProjectDescriptor $projectDescriptor
116
     *
117
     * @return void
118
     */
119
    public function save(ProjectDescriptor $projectDescriptor)
120
    {
121
        $keys  = array();
122
        $cache = $this->getCache();
123
124
        /** @var IteratorInterface $iteratorInterface  */
125
        $iteratorInterface = $cache->getIterator();
126
127
        // FIXME: Workaround for: https://github.com/zendframework/zf2/pull/4154
128
        if ($iteratorInterface->valid()) {
129
            foreach ($cache as $key) {
130
                $keys[] = $key;
131
            }
132
        }
133
134
        // store the settings for this Project Descriptor
135
        $cache->setItem(self::KEY_SETTINGS, $projectDescriptor->getSettings());
136
137
        // store cache items
138
        $usedKeys = array(self::KEY_SETTINGS);
139
        foreach ($projectDescriptor->getFiles() as $file) {
140
            $key        = self::FILE_PREFIX . md5($file->getPath());
141
            $usedKeys[] = $key;
142
            $cache->setItem($key, $file);
143
        }
144
145
        // remove any keys that are no longer used.
146
        $invalidatedKeys = array_diff($keys, $usedKeys);
147
        if ($invalidatedKeys) {
148
            $cache->removeItems($invalidatedKeys);
149
        }
150
151
        if ($cache instanceof OptimizableInterface) {
152
            $cache->optimize();
153
        }
154
    }
155
156
    /**
157
     * Removes all files in cache that do not occur in the given FileSet Collection.
158
     *
159
     * @param Collection $collection
160
     *
161
     * @return void
162
     */
163
    public function garbageCollect(Collection $collection)
164
    {
165
        $projectRoot = $collection->getProjectRoot();
166
        $filenames   = $collection->getFilenames();
167
168
        foreach ($filenames as &$name) {
169
            // the cache key contains a path relative to the project root; here we expect absolute paths.
170
            $name = self::FILE_PREFIX . md5(substr($name, strlen($projectRoot)));
171
        }
172
173
        /** @var IteratorInterface $iteratorInterface  */
174
        $iteratorInterface = $this->getCache()->getIterator();
175
176
        // FIXME: Workaround for: https://github.com/zendframework/zf2/pull/4154
177
        if ($iteratorInterface->valid()) {
178
            foreach ($this->getCache() as $item) {
179
                if (substr($item, 0, strlen(self::FILE_PREFIX)) === self::FILE_PREFIX && !in_array($item, $filenames)) {
180
                    $this->getCache()->removeItem($item);
181
                }
182
            }
183
        }
184
    }
185
}
186