Completed
Push — master ( af7add...6e606c )
by Karsten
02:11
created

CachedEntityConfigLookUp   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 140
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 14
lcom 1
cbo 2
dl 0
loc 140
ccs 41
cts 41
cp 1
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A saveToCache() 0 11 3
A __construct() 0 7 1
A getEntityConfig() 0 15 1
A loadOrCreate() 0 16 3
A fetchFromCache() 0 13 4
A isCacheFresh() 0 12 2
1
<?php
2
/**
3
 * File was created 06.10.2015 06:25
4
 */
5
6
namespace PeekAndPoke\Component\Slumber\Core\LookUp;
7
8
use Doctrine\Common\Cache\Cache;
9
10
/**
11
 * @author Karsten J. Gerber <[email protected]>
12
 */
13
class CachedEntityConfigLookUp implements EntityConfigReader
14
{
15
    /** @var EntityConfigReader */
16
    private $delegate;
17
    /** @var Cache */
18
    private $cache;
19
    /** @var string */
20
    private $prefix;
21
    /** @var bool */
22
    private $debug;
23
24
    /**
25
     * We have another level of caching here
26
     *
27
     * @var array
28
     */
29
    private $known = [];
30
31
    /**
32
     * @param EntityConfigReader $delegate
33
     * @param Cache              $cache
34
     * @param string             $prefix
35
     * @param bool               $debug
36
     */
37 4
    public function __construct(EntityConfigReader $delegate, Cache $cache, $prefix = '[Slumber]@', $debug = false)
38
    {
39 4
        $this->delegate = $delegate;
40 4
        $this->cache    = $cache;
41 4
        $this->prefix   = $prefix;
42 4
        $this->debug    = $debug;
43 4
    }
44
45
    /**
46
     * @param \ReflectionClass $cls
47
     *
48
     * @return PropertyMarkedForSlumber[]
49
     */
50 4
    public function getEntityConfig(\ReflectionClass $cls)
51
    {
52 4
        $cacheKey = $this->prefix . $cls->name;
53
54 4
        return $this->loadOrCreate(
55 4
            $cacheKey,
56 4
            function () use ($cacheKey, $cls) {
57 4
                return $this->fetchFromCache($cacheKey, $cls);
58 4
            },
59 4
            function () use ($cls) {
60 4
                return $this->delegate->getEntityConfig($cls);
61 4
            },
62 4
            $cls
63
        );
64
    }
65
66
    /**
67
     * @param string           $cacheKey
68
     * @param \Closure         $fetcher
69
     * @param \Closure         $creator
70
     * @param \ReflectionClass $class
71
     *
72
     * @return mixed
73
     */
74 4
    private function loadOrCreate($cacheKey, \Closure $fetcher, \Closure $creator, \ReflectionClass $class)
75
    {
76 4
        if (isset($this->known[$cacheKey])) {
77 1
            return $this->known[$cacheKey];
78
        }
79
80
        /** @var EntityConfig $cacheData */
81 4
        $cacheData = $fetcher();
82
83 4
        if (false === $cacheData) {
84 4
            $cacheData = $creator();
85 4
            $this->saveToCache($cacheKey, $cacheData, $class);
86
        }
87
88 4
        return $this->known[$cacheKey] = $cacheData;
89
    }
90
91
    /**
92
     * Fetches a value from the cache.
93
     *
94
     * @param string           $rawCacheKey The cache key.
95
     * @param \ReflectionClass $class       The related class.
96
     *
97
     * @return mixed The cached value or false when the value is not in cache.
98
     */
99 4
    private function fetchFromCache($rawCacheKey, \ReflectionClass $class)
100
    {
101 4
        $cacheKey = $this->prefix . $rawCacheKey;
102
103 4
        if (($data = $this->cache->fetch($cacheKey)) !== false) {
104
            /** @noinspection NestedPositiveIfStatementsInspection */
105 2
            if (! $this->debug || $this->isCacheFresh($cacheKey, $class)) {
106 2
                return $data;
107
            }
108
        }
109
110 4
        return false;
111
    }
112
113
    /**
114
     * Saves a value to the cache.
115
     *
116
     * @param string           $rawCacheKey The cache key.
117
     * @param mixed            $value       The value.
118
     * @param \ReflectionClass $class
119
     */
120 4
    private function saveToCache($rawCacheKey, $value, \ReflectionClass $class)
121
    {
122 4
        $cacheKey = $this->prefix . $rawCacheKey;
123 4
        $this->cache->save($cacheKey, $value);
124
125
        // in debug mode record the creation time of the entry
126 4
        if ($this->debug && false !== $filename = $class->getFileName()) {
127
128 3
            $this->cache->save('[C]' . $cacheKey, filemtime($filename));
129
        }
130 4
    }
131
132
    /**
133
     * Checks if the cache is fresh.
134
     *
135
     * @param string           $cacheKey
136
     * @param \ReflectionClass $class
137
     *
138
     * @return boolean
139
     */
140 2
    private function isCacheFresh($cacheKey, \ReflectionClass $class)
141
    {
142
        // built in classes have no filename
143 2
        if (false === $filename = $class->getFileName()) {
144 1
            return true;
145
        }
146
147
//        echo $cacheKey . " " . $this->cache->fetch('[C]'.$cacheKey) . " " . filemtime($filename) . " " . ($this->cache->fetch('[C]'.$cacheKey) >= filemtime($filename)) . "\n";
0 ignored issues
show
Unused Code Comprehensibility introduced by
46% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
148
149
        // When we have the creation time (debug mode) and it is less than the current file time, the cache is also not fresh
150 1
        return $this->cache->fetch('[C]' . $cacheKey) >= filemtime($filename);
151
    }
152
}
153