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

prepare_memcached()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2.0625

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 7
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 10
ccs 6
cts 8
cp 0.75
crap 2.0625
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
 * The Memory caching system is geared to hold needed information available quickly.
11
 * There are a number of limitations you have to deal with, when working with the
12
 * Memory Cache.
13
 *
14
 * Number One, you cannot put arbitrary keys into the cache. Since the memcached
15
 * php extension does not support key listings, you are bound to use MidCOM object
16
 * GUIDs as cache keys, whatever you do. To allow for different subsystems of the
17
 * Framework to share the cache, I have introduce "Data groups", which are suffixes
18
 * for the actual cache information. Thus, all keys in the cache follow a
19
 * "{$datagroup}-{$guid}" naming scheme. These groups need to be registered in the
20
 * MidCOM configuration key <i>cache_module_memcache_data_groups</i>.
21
 *
22
 * Number Two, it is entirely possible (as it is the default), that the memcache
23
 * is actually not available, as no memcache daemon has been found.  This is
24
 * controlled by the <i>cache_module_memcache_backend</i> configuration option,
25
 * which tries to auto-detect a sensible default. If it is set to the name of a caching module
26
 * it will actually start caching. Otherwise it will silently ignore
27
 * put requests, and reports all keys as not existent.
28
 *
29
 * Number Three, as at least memcache's contains() check isn't working on some machines, key
30
 * values of false are forbidden, as they are used to check a keys existence
31
 * during the get cycle. You should also avoid null and 0 members, if possible,
32
 * they could naturally be error prone if you start forgetting about the typed
33
 * comparisons.
34
 *
35
 * <b>Special functionality</b>
36
 *
37
 * - Interface to the PARENT caching group, has a few simple shortcuts to the
38
 *   access the available information.
39
 *
40
 * @package midcom.services
41
 */
42
class midcom_services_cache_module_memcache extends midcom_services_cache_module
43
{
44
    /**
45
     * List of known data groups. See the class introduction for details.
46
     *
47
     * @var Array
48
     */
49
    private $_data_groups = [];
50
51 2
    public static function prepare_memcached(array $config) : ?Memcached
52
    {
53 2
        $host = $config['host'] ?? 'localhost';
54 2
        $port = $config['port'] ?? 11211;
55 2
        $memcached = new Memcached;
56 2
        if (!$memcached->addServer($host, $port)) {
57
            midcom::get()->debug->log_php_error(MIDCOM_LOG_ERROR);
58
            return null;
59
        }
60 2
        return $memcached;
61
    }
62
63
    /**
64
     * Initialization event handler.
65
     *
66
     * It will load the cache backend.
67
     *
68
     * Initializes the backend configuration.
69
     */
70
    public function __construct(midcom_config $config)
71
    {
72
        parent::__construct();
73
        $this->_data_groups = $config->get('cache_module_memcache_data_groups');
74
        if ($driver = $config->get('cache_module_memcache_backend')) {
75
            $backend_config = $config->get('cache_module_memcache_backend_config');
76
            $backend_config['driver'] = $driver;
77
            $this->backend = $this->_create_backend('module_memcache', $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

77
            $this->backend = $this->_create_backend('module_memcache', /** @scrutinizer ignore-type */ $backend_config);
Loading history...
78
        }
79
    }
80
81
    /**
82
     * {@inheritDoc}
83
     */
84 288
    public function invalidate($guid, $object = null)
85
    {
86 288
        foreach ($this->_data_groups as $group) {
87 288
            if ($group == 'ACL') {
88 288
                $this->backend->delete("{$group}-SELF::{$guid}");
89 288
                $this->backend->delete("{$group}-CONTENT::{$guid}");
90
            } else {
91 288
                $this->backend->delete("{$group}-{$guid}");
92
            }
93
        }
94 288
    }
95
96
    /**
97
     * Looks up a value in the cache and returns it. Not existent
98
     * keys are caught in this call as well
99
     *
100
     * @param string $data_group The Data Group to look in.
101
     * @param string $key The key to look up.
102
     * @return mixed The cached value on success, false on failure.
103
     */
104 301
    public function get($data_group, $key)
105
    {
106 301
        return $this->backend->fetch("{$data_group}-{$key}");
107
    }
108
109
    /**
110
     * Sets a given key in the cache. If the data group is unknown, a Warning-Level error
111
     * is logged and putting is denied.
112
     *
113
     * @param string $data_group The Data Group to look in.
114
     * @param string $key The key to look up.
115
     * @param mixed $data The data to store.
116
     * @param int $timeout how long the data should live in the cache.
117
     */
118 300
    public function put($data_group, $key, $data, $timeout = 0)
119
    {
120 300
        if (!in_array($data_group, $this->_data_groups)) {
121
            debug_add("Tried to add data to the unknown data group {$data_group}, cannot do that.", MIDCOM_LOG_WARN);
122
            debug_print_r('Known data groups:', $this->_data_groups);
123
            debug_print_function_stack('We were called from here:');
124
            return;
125
        }
126
127 300
        $this->backend->save("{$data_group}-{$key}", $data, $timeout);
128 300
    }
129
130
    /**
131
     * This is a little helper that tries to look up a GUID in the memory
132
     * cache's PARENT data group. If it is not found, false is returned.
133
     * If the object has no parent, the array value is null
134
     *
135
     * @param string $guid The guid of which a parent is searched.
136
     * @return array|false The classname => GUID pair or false when nothing is in cache
137
     */
138 284
    public function lookup_parent_data($guid)
139
    {
140 284
        return $this->get('PARENT', $guid);
141
    }
142
143
    /**
144
     * This is a little helper that saves a parent GUID and class in the memory
145
     * cache's PARENT data group.
146
     *
147
     * @param string $object_guid The guid of which a parent is saved.
148
     * @param array $parent_data The guid and classname of the parent which is saved.
149
     */
150 284
    public function update_parent_data($object_guid, array $parent_data)
151
    {
152 284
        $this->put('PARENT', $object_guid, $parent_data);
153 284
    }
154
}
155