Completed
Push — master ( 89223c...9f8254 )
by Andreas
51:18 queued 05:30
created

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