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

midcom_services_cache_module_memcache   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 99
Duplicated Lines 0 %

Test Coverage

Coverage 71.88%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 25
dl 0
loc 99
ccs 23
cts 32
cp 0.7188
rs 10
c 2
b 0
f 0
wmc 11

7 Methods

Rating   Name   Duplication   Size   Complexity  
A prepare_memcached() 0 10 2
A lookup_parent_data() 0 3 1
A __construct() 0 4 1
A invalidate() 0 8 3
A update_parent_data() 0 3 1
A put() 0 10 2
A get() 0 3 1
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
use Doctrine\Common\Cache\CacheProvider;
10
11
/**
12
 * The Memory caching system is geared to hold needed information available quickly.
13
 * There are a number of limitations you have to deal with, when working with the
14
 * Memory Cache.
15
 *
16
 * Number One, you cannot put arbitrary keys into the cache. Since the memcached
17
 * php extension does not support key listings, you are bound to use MidCOM object
18
 * GUIDs as cache keys, whatever you do. To allow for different subsystems of the
19
 * Framework to share the cache, I have introduce "Data groups", which are suffixes
20
 * for the actual cache information. Thus, all keys in the cache follow a
21
 * "{$datagroup}-{$guid}" naming scheme. These groups need to be registered in the
22
 * MidCOM configuration key <i>cache_module_memcache_data_groups</i>.
23
 *
24
 * Number Two, it is entirely possible (as it is the default), that the memcache
25
 * is actually not available, as no memcache daemon has been found.  This is
26
 * controlled by the <i>cache_module_memcache_backend</i> configuration option,
27
 * which tries to auto-detect a sensible default. If it is set to the name of a caching module
28
 * it will actually start caching. Otherwise it will silently ignore
29
 * put requests, and reports all keys as not existent.
30
 *
31
 * Number Three, as at least memcache's contains() check isn't working on some machines, key
32
 * values of false are forbidden, as they are used to check a keys existence
33
 * during the get cycle. You should also avoid null and 0 members, if possible,
34
 * they could naturally be error prone if you start forgetting about the typed
35
 * comparisons.
36
 *
37
 * <b>Special functionality</b>
38
 *
39
 * - Interface to the PARENT caching group, has a few simple shortcuts to the
40
 *   access the available information.
41
 *
42
 * @package midcom.services
43
 */
44
class midcom_services_cache_module_memcache extends midcom_services_cache_module
45
{
46
    /**
47
     * List of known data groups. See the class introduction for details.
48
     *
49
     * @var Array
50
     */
51
    private $_data_groups = [];
52
53 2
    public static function prepare_memcached(array $config) : ?Memcached
54
    {
55 2
        $host = $config['host'] ?? 'localhost';
56 2
        $port = $config['port'] ?? 11211;
57 2
        $memcached = new Memcached;
58 2
        if (!$memcached->addServer($host, $port)) {
59
            return null;
60
        }
61
62 2
        return $memcached;
63
    }
64
65
    public function __construct(midcom_config $config, CacheProvider $backend)
66
    {
67
        parent::__construct($backend);
68
        $this->_data_groups = $config->get('cache_module_memcache_data_groups');
69
    }
70
71
    /**
72
     * {@inheritDoc}
73
     */
74 288
    public function invalidate($guid, $object = null)
75
    {
76 288
        foreach ($this->_data_groups as $group) {
77 288
            if ($group == 'ACL') {
78 288
                $this->backend->delete("{$group}-SELF::{$guid}");
79 288
                $this->backend->delete("{$group}-CONTENT::{$guid}");
80
            } else {
81 288
                $this->backend->delete("{$group}-{$guid}");
82
            }
83
        }
84 288
    }
85
86
    /**
87
     * Looks up a value in the cache and returns it. Not existent
88
     * keys are caught in this call as well
89
     *
90
     * @param string $data_group The Data Group to look in.
91
     * @param string $key The key to look up.
92
     * @return mixed The cached value on success, false on failure.
93
     */
94 301
    public function get($data_group, $key)
95
    {
96 301
        return $this->backend->fetch("{$data_group}-{$key}");
97
    }
98
99
    /**
100
     * Sets a given key in the cache. If the data group is unknown, a Warning-Level error
101
     * is logged and putting is denied.
102
     *
103
     * @param string $data_group The Data Group to look in.
104
     * @param string $key The key to look up.
105
     * @param mixed $data The data to store.
106
     * @param int $timeout how long the data should live in the cache.
107
     */
108 300
    public function put($data_group, $key, $data, $timeout = 0)
109
    {
110 300
        if (!in_array($data_group, $this->_data_groups)) {
111
            debug_add("Tried to add data to the unknown data group {$data_group}, cannot do that.", MIDCOM_LOG_WARN);
112
            debug_print_r('Known data groups:', $this->_data_groups);
113
            debug_print_function_stack('We were called from here:');
114
            return;
115
        }
116
117 300
        $this->backend->save("{$data_group}-{$key}", $data, $timeout);
118 300
    }
119
120
    /**
121
     * This is a little helper that tries to look up a GUID in the memory
122
     * cache's PARENT data group. If it is not found, false is returned.
123
     * If the object has no parent, the array value is null
124
     *
125
     * @param string $guid The guid of which a parent is searched.
126
     * @return array|false The classname => GUID pair or false when nothing is in cache
127
     */
128 284
    public function lookup_parent_data($guid)
129
    {
130 284
        return $this->get('PARENT', $guid);
131
    }
132
133
    /**
134
     * This is a little helper that saves a parent GUID and class in the memory
135
     * cache's PARENT data group.
136
     *
137
     * @param string $object_guid The guid of which a parent is saved.
138
     * @param array $parent_data The guid and classname of the parent which is saved.
139
     */
140 284
    public function update_parent_data($object_guid, array $parent_data)
141
    {
142 284
        $this->put('PARENT', $object_guid, $parent_data);
143 284
    }
144
}
145