Passed
Push — master ( 67760a...0ff2cc )
by Andreas
17:17
created

midcom_services_cache_module_nap::get_leaves()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4.0218

Importance

Changes 0
Metric Value
cc 4
eloc 8
nc 3
nop 1
dl 0
loc 14
ccs 8
cts 9
cp 0.8889
crap 4.0218
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @package midcom.services
4
 * @author The Midgard Project, http://www.midgard-project.org
5
 * @copyright The Midgard Project, http://www.midgard-project.org
6
 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
7
 */
8
9
/**
10
 * This is the NAP caching module. It provides the basic management functionality
11
 * for the various backend databases which will be created based on the root topic of the
12
 * NAP trees.
13
 *
14
 * The actual handling of the various dbs is done with Doctrine Cache, this
15
 * class is responsible for the creation of backend instances and invalidation for NAP
16
 * cache objects. (Which implies that it is fully aware of the data structures
17
 * stored in the cache.)
18
 *
19
 * All entries are indexed by their Midgard Object GUID. The entries in the NAP cache
20
 * basically resemble the arrays within the NAP backend node/leaf cache
21
 *
22
 * NAP caches can be shared over multiple sites, as all site specific data (like
23
 * site prefixes) are evaluated during runtime.
24
 *
25
 * Most of the cache update work is done in midcom_helper_nav_backend,
26
 * so you should look there for details about the caching strategy.
27
 *
28
 * @see midcom_helper_nav_backend
29
 *
30
 * @package midcom.services
31
 */
32
class midcom_services_cache_module_nap extends midcom_services_cache_module
33
{
34
    /**
35
     * The cache backend instance to use.
36
     *
37
     * @var Doctrine\Common\Cache\CacheProvider
38
     */
39
    private $_cache;
40
41
    /**
42
     * Initialization event handler.
43
     *
44
     * It will load the cache backends for the current MidCOM topic.
45
     *
46
     * Initializes the backend configuration.
47
     */
48
    public function _on_initialize()
49
    {
50
        if ($driver = midcom::get()->config->get('cache_module_memcache_backend')) {
51
            $config = midcom::get()->config->get('cache_module_memcache_backend_config');
52
            $config['driver'] = $driver;
53
            $this->_cache = $this->_create_backend('module_nap', $config);
0 ignored issues
show
Bug introduced by
It seems like $config can also be of type null; however, parameter $config of midcom_services_cache_module::_create_backend() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

53
            $this->_cache = $this->_create_backend('module_nap', /** @scrutinizer ignore-type */ $config);
Loading history...
54
        }
55
    }
56
57
    /**
58
     * {@inheritDoc}
59
     */
60 287
    public function invalidate($guid, $object = null)
61
    {
62 287
        $napobject = $this->get_guid($guid);
63
64 287
        if (!$napobject) {
65
            // The object itself is not in cache, but it still might have a parent that
66
            // needs invalidating (f.x. if it is newly-created or was moved from outside the tree)
67 286
            $napobject = $this->_load_from_guid($guid, $object);
68 286
            if (!$napobject) {
69
                // We couldn't load the object (because it's deleted f.x.) or it is not in NAP.
70
                // Either way, there is nothing more we can do here.
71 261
                return;
72
            }
73
        }
74
75 98
        if ($napobject[MIDCOM_NAV_TYPE] == 'leaf') {
76 2
            $cached_node_id = $napobject[MIDCOM_NAV_NODEID];
77
            // Get parent from DB and compare to catch moves
78 2
            if ($parent = $napobject[MIDCOM_NAV_OBJECT]->get_parent()) {
79 2
                $parent_entry = $this->get_guid($parent->guid);
80 2
                if (   $parent_entry
81 2
                    && $parent_entry[MIDCOM_NAV_ID] != $cached_node_id) {
82
                    $this->_cache->delete($this->_prefix . '-' . $parent_entry[MIDCOM_NAV_ID] . '-leaves');
83
                }
84
            }
85 2
            if (!empty($napobject[MIDCOM_NAV_GUID])) {
86 2
                $this->_cache->delete($this->_prefix . '-' . $napobject[MIDCOM_NAV_GUID]);
87
            }
88
        } else {
89 98
            $cached_node_id = $napobject[MIDCOM_NAV_ID];
90
91
            //Invalidate subnode cache for the (cached) parent
92 98
            $parent_id = $napobject[MIDCOM_NAV_NODEID];
93 98
            $parent_entry = $this->get_node($parent_id);
94
95 98
            if (   $parent_entry
96 98
                && array_key_exists(MIDCOM_NAV_SUBNODES, $parent_entry)) {
97 2
                unset($parent_entry[MIDCOM_NAV_SUBNODES]);
98 2
                $this->put_node($parent_id, $parent_entry);
99
            }
100
101
            //Cross-check parent value from object to detect topic moves
102 98
            if ($parent = $napobject[MIDCOM_NAV_OBJECT]->get_parent()) {
103 24
                $parent_entry_from_object = $this->get_guid($parent->guid);
104
105 24
                if (    !empty($parent_entry_from_object[MIDCOM_NAV_ID])
106 24
                     && !empty($parent_entry[MIDCOM_NAV_ID])
107 24
                     && $parent_entry_from_object[MIDCOM_NAV_ID] != $parent_entry[MIDCOM_NAV_ID]) {
108
                    unset($parent_entry_from_object[MIDCOM_NAV_SUBNODES]);
109
                    $this->put_node($parent_entry_from_object[MIDCOM_NAV_ID], $parent_entry_from_object);
110
                }
111
            }
112
        }
113
114 98
        $leaves_key = "{$cached_node_id}-leaves";
115
116 98
        $this->_cache->delete("{$this->_prefix}-{$cached_node_id}");
117 98
        $this->_cache->delete($this->_prefix . '-' . $napobject[MIDCOM_NAV_GUID]);
118 98
        $this->_cache->delete("{$this->_prefix}-{$leaves_key}");
119 98
    }
120
121 286
    private function _load_from_guid(string $guid, $object)
122
    {
123 286
        $napobject = false;
124
        try {
125 286
            if (!is_object($object)) {
126 118
                $object = midcom::get()->dbfactory->get_object_by_guid($guid);
127
            }
128 286
            $nav = new midcom_helper_nav;
129 286
            if ($object instanceof midcom_db_topic) {
130 93
                $napobject = $nav->get_node($object->id);
131 244
            } elseif (   ($node = $nav->find_closest_topic($object))
132 244
                      && $nodeobject = $nav->get_node($node->id)) {
133 286
                $napobject = $nav->get_leaf($nodeobject[MIDCOM_NAV_ID] . '-' . $object->id);
134
            }
135
        } catch (midcom_error $e) {
136
            $e->log();
137
        }
138 286
        return $napobject;
139
    }
140
141
    /**
142
     * Looks up a node in the cache and returns it. Not existent
143
     * keys are caught in this call as well, so you do not need
144
     * to call exists first.
145
     *
146
     * @param string $key The key to look up.
147
     * @return mixed The cached value on success, false on failure.
148
     */
149 143
    public function get_node($key)
150
    {
151 143
        if ($this->_cache === null) {
152
            return false;
153
        }
154 143
        $lang_id = midcom::get()->i18n->get_current_language();
155 143
        $result = $this->_cache->fetch("{$this->_prefix}-{$key}");
156 143
        if (   !is_array($result)
157 143
            || !isset($result[$lang_id])) {
158 127
            return false;
159
        }
160
161 70
        return $result[$lang_id];
162
    }
163
164
    /**
165
     * Looks up a node in the cache and returns it. Not existent
166
     * keys are caught in this call as well, so you do not need
167
     * to call exists first.
168
     *
169
     * @param string $key The key to look up.
170
     * @return mixed The cached value on success, false on failure.
171
     */
172 40
    public function get_leaves($key)
173
    {
174 40
        if ($this->_cache === null) {
175
            return false;
176
        }
177
178 40
        $lang_id = midcom::get()->i18n->get_current_language();
179 40
        $result = $this->_cache->fetch("{$this->_prefix}-{$key}");
180 40
        if (   !is_array($result)
181 40
            || !isset($result[$lang_id])) {
182 37
            return false;
183
        }
184
185 4
        return $result[$lang_id];
186
    }
187
188
    /**
189
     * Sets a given node key in the cache.
190
     *
191
     * @param string $key The key to look up.
192
     * @param mixed $data The data to store.
193
     */
194 111
    public function put_node($key, $data)
195
    {
196 111
        if ($this->_cache === null) {
197
            return;
198
        }
199
200 111
        $lang_id = midcom::get()->i18n->get_current_language();
201 111
        $result = $this->_cache->fetch("{$this->_prefix}-{$key}");
202 111
        if (!is_array($result)) {
203 109
            $result = [];
204
        }
205 111
        $result[$lang_id] = $data;
206 111
        $this->_cache->save("{$this->_prefix}-{$key}", $result);
207 111
        $this->_cache->save($this->_prefix . '-' . $data[MIDCOM_NAV_GUID], $result);
208 111
    }
209
210
    /**
211
     * Save a given array by GUID in the cache.
212
     *
213
     * @param string $guid The key to store.
214
     * @param mixed $data The data to store.
215
     */
216 1
    public function put_guid($guid, $data)
217
    {
218 1
        if ($this->_cache === null) {
219
            return;
220
        }
221
222 1
        $lang_id = midcom::get()->i18n->get_current_language();
223 1
        $result = $this->_cache->fetch("{$this->_prefix}-{$guid}");
224 1
        if (!is_array($result)) {
225 1
            $result = [];
226
        }
227 1
        $result[$lang_id] = $data;
228 1
        $this->_cache->save($this->_prefix . '-' . $guid, $result);
229 1
    }
230
231
    /**
232
     * Get a given array by GUID from the cache.
233
     *
234
     * @param string $guid The key to look up.
235
     */
236 294
    public function get_guid($guid)
237
    {
238 294
        if ($this->_cache === null) {
239
            return;
240
        }
241
242 294
        $lang_id = midcom::get()->i18n->get_current_language();
243 294
        $result = $this->_cache->fetch("{$this->_prefix}-{$guid}");
244 294
        if (   !is_array($result)
245 294
            || !isset($result[$lang_id])) {
246 293
            return false;
247
        }
248 56
        return $result[$lang_id];
249
    }
250
251
    /**
252
     * Sets a given leave key in the cache
253
     *
254
     * @param string $key The key to look up.
255
     * @param mixed $data The data to store.
256
     */
257 13
    public function put_leaves($key, $data)
258
    {
259 13
        if ($this->_cache === null) {
260
            return;
261
        }
262
263 13
        $lang_id = midcom::get()->i18n->get_current_language();
264 13
        $result = $this->_cache->fetch("{$this->_prefix}-{$key}");
265 13
        if (!is_array($result)) {
266 13
            $result = [];
267
        }
268 13
        $result[$lang_id] = $data;
269 13
        $this->_cache->save("{$this->_prefix}-{$key}", $result);
270 13
    }
271
}
272