Passed
Push — master ( 671601...c4a055 )
by Andreas
16:47
created

midcom_services_cache_module_nap::put_leaves()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 2
eloc 6
c 3
b 0
f 0
nc 2
nop 2
dl 0
loc 9
ccs 7
cts 7
cp 1
crap 2
rs 10
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
     * Initialization event handler.
36
     *
37
     * It will load the cache backends for the current MidCOM topic.
38
     *
39
     * Initializes the backend configuration.
40
     */
41
    public function __construct(midcom_config $config)
42
    {
43
        parent::__construct();
44
        if ($driver = $config->get('cache_module_memcache_backend')) {
45
            $backend_config = $config->get('cache_module_memcache_backend_config');
46
            $backend_config['driver'] = $driver;
47
            $this->backend = $this->_create_backend('module_nap', $backend_config);
0 ignored issues
show
Bug introduced by
It seems like $backend_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

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