Passed
Pull Request — develop (#5)
by ANTHONIUS
10:30
created

Cache::setCoverage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the doyo/behat-coverage-extension project.
5
 *
6
 * (c) Anthonius Munthi <[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
declare(strict_types=1);
13
14
namespace Doyo\Behat\Coverage\Bridge\CodeCoverage;
15
16
use SebastianBergmann\CodeCoverage\CodeCoverage;
17
use SebastianBergmann\CodeCoverage\Filter;
18
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
19
20
class Cache implements \Serializable
21
{
22
    const CACHE_KEY = 'subject';
23
24
    /**
25
     * @var string|null
26
     */
27
    private $namespace;
28
29
    /**
30
     * @var string|null
31
     */
32
    private $coverageId;
33
34
    /**
35
     * @var FilesystemAdapter|null
36
     */
37
    private $adapter;
38
39
    /**
40
     * @var array
41
     */
42
    private $coverage = [];
43
44
    /**
45
     * @var array
46
     */
47
    private $filter = [];
48
49
    /**
50
     * @var CodeCoverage
51
     */
52
    private $codeCoverage;
53
54
    /**
55
     * @var array
56
     */
57
    private $codeCoverageOptions = [];
58
59
    /**
60
     * @var \Exception[]
61
     */
62
    private $exceptions = [];
63
64
    public function __construct($namespace)
65
    {
66
        $dir             = sys_get_temp_dir().'/doyo/behat-coverage-extension';
67
        $adapter         = new FilesystemAdapter($namespace, 0, $dir);
68
        $this->adapter   = $adapter;
69
        $this->namespace = $namespace;
70
71
        $this->readCache();
72
    }
73
74
    public function reset()
75
    {
76
        $this->coverageId = null;
77
        $this->coverage   = [];
78
        $this->exceptions = [];
79
80
        $this->save();
81
    }
82
83
    public function serialize()
84
    {
85
        $data = [
86
            $this->coverageId,
87
            $this->coverage,
88
        ];
89
90
        return serialize($data);
91
    }
92
93
    public function unserialize($serialized)
94
    {
95
        list($this->coverageId, $this->coverage) = unserialize($serialized);
96
    }
97
98
    /**
99
     * @return string|null
100
     */
101
    public function getNamespace()
102
    {
103
        return $this->namespace;
104
    }
105
106
    /**
107
     * @return string|null
108
     */
109
    public function getCoverageId()
110
    {
111
        return $this->coverageId;
112
    }
113
114
    /**
115
     * @param string|null $coverageId
116
     *
117
     * @return Cache
118
     */
119
    public function setCoverageId(string $coverageId): self
120
    {
121
        $this->coverageId = $coverageId;
122
123
        return $this;
124
    }
125
126
    /**
127
     * @return FilesystemAdapter|null
128
     */
129
    public function getAdapter(): FilesystemAdapter
130
    {
131
        return $this->adapter;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->adapter could return the type null which is incompatible with the type-hinted return Symfony\Component\Cache\Adapter\FilesystemAdapter. Consider adding an additional type-check to rule them out.
Loading history...
132
    }
133
134
    /**
135
     * @param FilesystemAdapter|null $adapter
136
     *
137
     * @return Cache
138
     */
139
    public function setAdapter(FilesystemAdapter $adapter): self
140
    {
141
        $this->adapter = $adapter;
142
143
        return $this;
144
    }
145
146
    /**
147
     * @return array
148
     */
149
    public function getCoverage(): array
150
    {
151
        return $this->coverage;
152
    }
153
154
    /**
155
     * @param array $coverage
156
     *
157
     * @return Cache
158
     */
159
    public function setCoverage(array $coverage): self
160
    {
161
        $this->coverage = $coverage;
162
163
        return $this;
164
    }
165
166
    /**
167
     * @return array
168
     */
169
    public function getCodeCoverageOptions(): array
170
    {
171
        return $this->codeCoverageOptions;
172
    }
173
174
    /**
175
     * @param array $codeCoverageOptions
176
     *
177
     * @return Cache
178
     */
179
    public function setCodeCoverageOptions(array $codeCoverageOptions): self
180
    {
181
        $this->codeCoverageOptions = $codeCoverageOptions;
182
183
        return $this;
184
    }
185
186
    public function getFilter(): array
187
    {
188
        return $this->filter;
189
    }
190
191
    /**
192
     * @param Filter|array $filter
193
     *
194
     * @return $this
195
     */
196
    public function setFilter($filter)
197
    {
198
        if ($filter instanceof Filter) {
199
            $whitelistedFiles              = $filter->getWhitelistedFiles();
200
            $filter                        = [];
201
            $filter['addFilesToWhitelist'] = $whitelistedFiles;
202
        }
203
204
        $this->filter = $filter;
205
206
        return $this;
207
    }
208
209
    public function save()
210
    {
211
        $adapter = $this->adapter;
212
        $item    = $adapter->getItem(static::CACHE_KEY);
0 ignored issues
show
Bug introduced by
The method getItem() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

212
        /** @scrutinizer ignore-call */ 
213
        $item    = $adapter->getItem(static::CACHE_KEY);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
213
214
        $item->set($this);
215
        $adapter->save($item);
216
    }
217
218
    public function readCache()
219
    {
220
        $adapter = $this->adapter;
221
        $cached  = $adapter->get(static::CACHE_KEY, function () {
222
            return false;
223
        });
224
225
        if ($cached instanceof self) {
226
            $this->coverageId = $cached->getCoverageId();
227
            $this->coverage   = $cached->getCoverage();
228
        }
229
    }
230
231
    /**
232
     * @return Filter
233
     */
234
    public function createFilter()
235
    {
236
        $config = $this->filter;
237
        $filter = new Filter();
238
        foreach ($config as $method => $value) {
239
            \call_user_func_array([$filter, $method], [$value]);
240
        }
241
242
        return $filter;
243
    }
244
245
    public function startCoverage($driver = null)
246
    {
247
        if (null === $this->coverageId) {
248
            return;
249
        }
250
        try {
251
            $coverage           = $this->createCodeCoverage($driver);
252
            $this->codeCoverage = $coverage;
253
254
            $coverage->start($this->getCoverageId());
255
            register_shutdown_function([$this, 'shutdown']);
256
        } catch (\Exception $e) {
257
            $this->exceptions[] = sprintf(
258
                "Can not start coverage in namespace: %s :\n%s",
259
                $this->namespace,
260
                $e->getMessage()
261
            );
262
        }
263
    }
264
265
    public function shutdown()
266
    {
267
        $codeCoverage = $this->codeCoverage;
268
269
        if (null === $codeCoverage) {
270
            return;
271
        }
272
273
        $data               = $codeCoverage->stop();
274
        $this->coverage     = $data;
275
        $this->codeCoverage = null;
276
277
        $this->save();
278
    }
279
280
    /**
281
     * @param mixed|null $driver
282
     *
283
     * @return CodeCoverage
284
     */
285
    private function createCodeCoverage($driver = null)
286
    {
287
        $filter   = $this->createFilter();
288
        $options  = $this->codeCoverageOptions;
289
        $coverage = new CodeCoverage($driver, $filter);
290
291
        foreach ($options as $method => $option) {
292
            if (method_exists($coverage, $option)) {
293
                \call_user_func_array([$coverage, $method], [$option]);
294
            }
295
        }
296
297
        return $coverage;
298
    }
299
}
300