Passed
Push — master ( 8a140a...6eed6d )
by Andreas
26:05
created

midcom_services_cache_module_nap::put_guid()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 2
eloc 5
nc 1
nop 2
dl 0
loc 7
ccs 6
cts 6
cp 1
crap 2
rs 10
c 2
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
     * {@inheritDoc}
36
     */
37 303
    public function invalidate(string $guid, $object = null)
38
    {
39 303
        $napobject = $this->get_guid($guid);
40
41 303
        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 302
            $napobject = $this->_load_from_guid($guid, $object);
45 302
            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 276
                return;
49
            }
50
        }
51
52 108
        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');
0 ignored issues
show
Bug introduced by
The method delete() does not exist on Symfony\Component\Cache\Adapter\AdapterInterface. Did you maybe mean deleteItem()? ( Ignorable by Annotation )

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

59
                    $this->backend->/** @scrutinizer ignore-call */ 
60
                                    delete($parent_entry[MIDCOM_NAV_ID] . '-leaves');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
60
                }
61
            }
62 2
            if (!empty($napobject[MIDCOM_NAV_GUID])) {
63 2
                $this->backend->delete($napobject[MIDCOM_NAV_GUID]);
64
            }
65
        } else {
66 108
            $cached_node_id = $napobject[MIDCOM_NAV_ID];
67
68
            //Invalidate subnode cache for the (cached) parent
69 108
            $parent_id = $napobject[MIDCOM_NAV_NODEID];
70 108
            $parent_entry = $this->get_node($parent_id);
71
72 108
            if (   $parent_entry
73 108
                && array_key_exists(MIDCOM_NAV_SUBNODES, $parent_entry)) {
74 1
                unset($parent_entry[MIDCOM_NAV_SUBNODES]);
75 1
                $this->put_node($parent_id, $parent_entry);
76
            }
77
78
            //Cross-check parent value from object to detect topic moves
79 108
            if ($parent = $napobject[MIDCOM_NAV_OBJECT]->get_parent()) {
80 25
                $parent_entry_from_object = $this->get_guid($parent->guid);
81
82 25
                if (    !empty($parent_entry_from_object[MIDCOM_NAV_ID])
83 25
                     && !empty($parent_entry[MIDCOM_NAV_ID])
84 25
                     && $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 108
        $leaves_key = "{$cached_node_id}-leaves";
92
93 108
        $this->backend->delete($cached_node_id);
94 108
        $this->backend->delete($napobject[MIDCOM_NAV_GUID]);
95 108
        $this->backend->delete($leaves_key);
96 108
    }
97
98 302
    private function _load_from_guid(string $guid, ?object $object) : ?array
99
    {
100 302
        $napobject = null;
101
        try {
102 302
            if (!$object) {
103 120
                $object = midcom::get()->dbfactory->get_object_by_guid($guid);
104
            }
105 302
            $nav = new midcom_helper_nav;
106 302
            if ($object instanceof midcom_db_topic) {
107 99
                $napobject = $nav->get_node($object->id);
108 256
            } elseif (   ($node = $nav->find_closest_topic($object))
109 256
                      && $nodeobject = $nav->get_node($node->id)) {
110 302
                $napobject = $nav->get_leaf($nodeobject[MIDCOM_NAV_ID] . '-' . $object->id);
111
            }
112
        } catch (midcom_error $e) {
113
            $e->log();
114
        }
115 302
        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 161
    public function get_node(string $key) : ?array
124
    {
125 161
        $lang_id = midcom::get()->i18n->get_current_language();
126 161
        return $this->backend->getItem($key)->get()[$lang_id] ?? null;
127
    }
128
129
    /**
130
     * Looks up a node in the cache and returns it. Not existent
131
     * keys are caught in this call as well, so you do not need
132
     * to call exists first.
133
     */
134 43
    public function get_leaves(string $key) : ?array
135
    {
136 43
        $lang_id = midcom::get()->i18n->get_current_language();
137 43
        return $this->backend->getItem($key)->get()[$lang_id] ?? null;
138
    }
139
140
    /**
141
     * Sets a given node key in the cache.
142
     *
143
     * @param mixed $data The data to store.
144
     */
145 121
    public function put_node(string $key, $data)
146
    {
147 121
        $item = $this->backend->getItem($key);
148 121
        $lang_id = midcom::get()->i18n->get_current_language();
149 121
        $result = $item->get() ?: [];
150 121
        $result[$lang_id] = $data;
151 121
        $this->backend->save($item->set($result));
152
        // symfony cache doesn't like empty cache keys
153 121
        if ($data[MIDCOM_NAV_GUID]) {
154 120
            $guid_item = $this->backend->getItem($data[MIDCOM_NAV_GUID]);
155 120
            $this->backend->save($guid_item->set($result));
156
        }
157 121
    }
158
159
    /**
160
     * Save a given array by GUID in the cache.
161
     *
162
     * @param mixed $data The data to store.
163
     */
164 1
    public function put_guid(string $guid, $data)
165
    {
166 1
        $lang_id = midcom::get()->i18n->get_current_language();
167 1
        $item = $this->backend->getItem($guid);
168 1
        $result = $item->get() ?: [];
169 1
        $result[$lang_id] = $data;
170 1
        $this->backend->save($item->set($result));
171 1
    }
172
173
    /**
174
     * Get a given array by GUID from the cache.
175
     */
176 310
    public function get_guid(string $guid) : ?array
177
    {
178 310
        $lang_id = midcom::get()->i18n->get_current_language();
179 310
        return $this->backend->getItem($guid)->get()[$lang_id] ?? null;
180
    }
181
182
    /**
183
     * Sets a given leave key in the cache
184
     *
185
     * @param mixed $data The data to store.
186
     */
187 8
    public function put_leaves(string $key, $data)
188
    {
189 8
        $lang_id = midcom::get()->i18n->get_current_language();
190 8
        $item = $this->backend->getItem($key);
191 8
        $result = $item->get() ?: [];
192 8
        $result[$lang_id] = $data;
193 8
        $this->backend->save($item->set($result));
194 8
    }
195
}
196