Passed
Push — master ( 2bc9d0...c77363 )
by Andreas
10:41
created

parameters   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 244
Duplicated Lines 0 %

Test Coverage

Coverage 85.37%

Importance

Changes 0
Metric Value
eloc 81
dl 0
loc 244
ccs 70
cts 82
cp 0.8537
rs 10
c 0
b 0
f 0
wmc 30

6 Methods

Rating   Name   Duplication   Size   Complexity  
A list_parameters() 0 12 3
A list_parameters_domain() 0 23 4
A list_parameters_all() 0 30 5
A get_parameter() 0 17 4
A delete_parameter() 0 28 6
B set_parameter() 0 31 8
1
<?php
2
/**
3
 * @package midcom.dba
4
 * @author CONTENT CONTROL http://www.contentcontrol-berlin.de/
5
 * @copyright CONTENT CONTROL http://www.contentcontrol-berlin.de/
6
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License
7
 */
8
9
namespace midcom\dba;
10
11
use midcom_connection;
12
use midgard_parameter;
13
use midcom;
14
use midcom\events\dbaevent;
15
16
/**
17
 * midcom parameter support
18
 *
19
 * @package midcom.dba
20
 */
21
trait parameters
22
{
23
    private static $parameter_cache = [];
24
    private static $parameter_all = [];
25
26
    /**
27
     * Return a parameter from the database.
28
     *
29
     * No event handlers are called here yet.
30
     *
31
     * @return ?string The parameter value or false otherwise (remember typesafe comparisons to protect against '' strings).
32
     */
33 190
    public function get_parameter(string $domain, string $name)
34
    {
35 190
        if (!$this->guid) {
36 20
            debug_add('Cannot retrieve information on a non-persistent object.', MIDCOM_LOG_INFO);
37 20
            return false;
38
        }
39
40 170
        if (isset(self::$parameter_cache[$this->guid][$domain])) {
41
            // We have this domain in cache already thanks to some parameter listing
42 2
            if (!isset(self::$parameter_cache[$this->guid][$domain][$name])) {
43 2
                return null;
44
            }
45
            return self::$parameter_cache[$this->guid][$domain][$name];
46
        }
47
48
        // Not in cache, query from MgdSchema API directly
49 168
        return $this->__object->get_parameter($domain, $name);
50
    }
51
52
    /**
53
     * List the parameters of an object. This will either list the parameters of
54
     * a single domain or the complete set of parameters, depending on the value
55
     * of $domain.
56
     *
57
     * It delegates the actual execution to two separate helper functions.
58
     *
59
     * No event handlers are called here yet.
60
     *
61
     * In case of a complete query, the result will be an associative array indexed
62
     * by the domain name and containing another array with parameter name/value pairs.
63
     * For example:
64
     *
65
     * <pre>
66
     * Array
67
     * (
68
     *     [Asgard] => Array
69
     *     (
70
     *         [lang] => en_US
71
     *         [act] => view
72
     *         [actloc] => tree
73
     *     )
74
     *     [AsgardTreeHost] => Array
75
     *     (
76
     *         [selected] => host0
77
     *     )
78
     * )
79
     * </pre>
80
     *
81
     * If you query only a single domain, the result will be a single associative
82
     * array containing the parameter name/value pairs. For example:
83
     *
84
     * <pre>
85
     * Array
86
     * (
87
     *     [lang] => en_US
88
     *     [act] => view
89
     *     [actloc] => tree
90
     * )
91
     * </pre>
92
     *
93
     * In both cases an empty Array will indicate that no parameter was found, while
94
     * false will indicate a failure while querying the database.
95
     *
96
     * @param string $domain The parameter domain to query, this may be null to indicate a full listing.
97
     */
98 406
    public function list_parameters(string $domain = null) : array
99
    {
100 406
        if (!$this->guid) {
101 7
            debug_add('Cannot retrieve information on a non-persistent object.', MIDCOM_LOG_INFO);
102 7
            return [];
103
        }
104
105 402
        if ($domain !== null) {
106 401
            return $this->list_parameters_domain($domain);
107
        }
108
109 2
        return $this->list_parameters_all();
110
    }
111
112
    /**
113
     * List the parameters of a single domain of an object.
114
     *
115
     * No event handlers are called here yet.
116
     *
117
     * @see list_parameters()
118
     */
119 401
    private function list_parameters_domain(string $domain) : array
120
    {
121 401
        if (!isset(self::$parameter_cache[$this->guid])) {
122 111
            self::$parameter_cache[$this->guid] = [];
123
        }
124
125 401
        if (isset(self::$parameter_cache[$this->guid][$domain])) {
126 377
            return self::$parameter_cache[$this->guid][$domain];
127
        }
128
129 114
        self::$parameter_cache[$this->guid][$domain] = [];
130
131 114
        $mc = midgard_parameter::new_collector('parentguid', $this->guid);
132 114
        $mc->set_key_property('name');
133 114
        $mc->add_value_property('value');
134 114
        $mc->add_constraint('domain', '=', $domain);
135 114
        $mc->execute();
136
137 114
        foreach ($mc->list_keys() as $name => $values) {
138 6
            self::$parameter_cache[$this->guid][$domain][$name] = $mc->get_subkey($name, 'value');
139
        }
140
141 114
        return self::$parameter_cache[$this->guid][$domain];
142
    }
143
144
    /**
145
     * List all parameters of an object.
146
     *
147
     * No event handlers are called here yet.
148
     *
149
     * @see list_parameters()
150
     */
151 2
    private function list_parameters_all() : array
152
    {
153 2
        if (!isset(self::$parameter_cache[$this->guid])) {
154 1
            self::$parameter_cache[$this->guid] = [];
155
        }
156
157 2
        if (!isset(self::$parameter_all[$this->guid])) {
158 2
            $mc = midgard_parameter::new_collector('parentguid', $this->guid);
159 2
            $mc->set_key_property('guid');
160 2
            $mc->add_value_property('domain');
161 2
            $mc->add_value_property('name');
162 2
            $mc->add_value_property('value');
163 2
            $mc->execute();
164
165 2
            foreach ($mc->list_keys() as $guid => $values) {
166 1
                $name = $mc->get_subkey($guid, 'name');
167 1
                $domain = $mc->get_subkey($guid, 'domain');
168
169 1
                if (!isset(self::$parameter_cache[$this->guid][$domain])) {
170 1
                    self::$parameter_cache[$this->guid][$domain] = [];
171
                }
172
173 1
                self::$parameter_cache[$this->guid][$domain][$name] = $mc->get_subkey($guid, 'value');
174
            }
175
176
            // Flag that we have queried all domains for this object
177 2
            self::$parameter_all[$this->guid] = true;
178
        }
179
        // Clean up empty arrays
180 2
        return array_filter(self::$parameter_cache[$this->guid], 'count');
181
    }
182
183
    /**
184
     * Set a parameter to the value specified.
185
     *
186
     * This is either a create or an update operation depending on whether there was
187
     * already a parameter of that domain/name present, or not.
188
     *
189
     * The user needs both update and parameter manipulation permission on the parent object for updates.
190
     *
191
     * @param string $value The Parameter value. If this is empty, the corresponding parameter is deleted.
192
     */
193 66
    public function set_parameter(string $domain, string $name, $value) : bool
194
    {
195 66
        if (!$this->guid) {
196
            debug_add('Cannot set parameters on a non-persistent object.', MIDCOM_LOG_WARN);
197
            return false;
198
        }
199 66
        if (empty($domain) || empty($name)) {
200
            debug_add('Parameter domain and name must be non-empty strings', MIDCOM_LOG_WARN);
201
            return false;
202
        }
203
204 66
        if (   !$this->can_do('midgard:update')
0 ignored issues
show
Bug introduced by
It seems like can_do() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

204
        if (   !$this->/** @scrutinizer ignore-call */ can_do('midgard:update')
Loading history...
205 66
            || !$this->can_do('midgard:parameters')) {
206 2
            debug_add("Failed to set parameters, midgard:update or midgard:parameters on " . static::class . " {$this->guid} not granted for the current user.",
207
                  MIDCOM_LOG_ERROR);
208 2
            midcom_connection::set_error(MGD_ERR_ACCESS_DENIED);
209 2
            return false;
210
        }
211
212
        // Set via MgdSchema API directly
213 64
        if (!$this->__object->set_parameter($domain, $name, (string) $value)) {
214 4
            return false;
215
        }
216
217 62
        if (isset(self::$parameter_cache[$this->guid][$domain])) {
218 9
            self::$parameter_cache[$this->guid][$domain][$name] = $value;
219
        }
220
221 62
        midcom::get()->dispatcher->dispatch(new dbaevent($this), dbaevent::PARAMETER);
222
223 62
        return true;
224
    }
225
226
    /**
227
     * Delete a parameter.
228
     *
229
     * Current implementation note: Deletion is not yet implemented in MgdSchema.
230
     * Therefore we set the parameters to an empty string for now, which should
231
     * have almost the same effect for most cases and thus is good enough for now.
232
     * Note, that empty string parameters are filtered in the getter methods until
233
     * this matter is resolved.
234
     *
235
     * The user needs both update and parameter manipulation permission on the parent object for updates.
236
     */
237 4
    public function delete_parameter(string $domain, string $name) : bool
238
    {
239 4
        if (!$this->guid) {
240
            debug_add('Cannot delete parameters on a non-persistent object.', MIDCOM_LOG_WARN);
241
            return false;
242
        }
243 4
        if (empty($domain) || empty($name)) {
244
            debug_add('Parameter domain and name must be non-empty strings', MIDCOM_LOG_WARN);
245
            return false;
246
        }
247
248 4
        if (   !$this->can_do('midgard:update')
249 4
            || !$this->can_do('midgard:parameters')) {
250
            debug_add("Failed to delete parameters, midgard:update or midgard:parameters on " . static::class . " {$this->guid} not granted for the current user.",
251
                  MIDCOM_LOG_ERROR);
252
            midcom_connection::set_error(MGD_ERR_ACCESS_DENIED);
253
            return false;
254
        }
255
256
        // Invalidate run-time cache
257 4
        unset(self::$parameter_cache[$this->guid][$domain]);
258
259
        // Unset via MgdSchema API directly
260 4
        $result = $this->__object->set_parameter($domain, $name, '');
261
262 4
        midcom::get()->dispatcher->dispatch(new dbaevent($this), dbaevent::PARAMETER);
263
264 4
        return $result;
265
    }
266
}
267