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

midcom_services_cache_module_nap::invalidate()   C

Complexity

Conditions 14
Paths 25

Size

Total Lines 59
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 14.1472

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 14
eloc 33
c 3
b 0
f 0
nc 25
nop 2
dl 0
loc 59
ccs 30
cts 33
cp 0.9091
crap 14.1472
rs 6.2666

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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