Passed
Push — master ( 2d3809...30cd5d )
by Andreas
34:09
created

midcom_helper__styleloader::show()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4.25

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 11
c 1
b 0
f 0
nc 4
nop 1
dl 0
loc 21
ccs 9
cts 12
cp 0.75
crap 4.25
rs 9.9
1
<?php
2
/**
3
 * @package midcom.helper
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 class is responsible for all style management. It is instantiated by the MidCOM framework
11
 * and accessible through the midcom::get()->style object.
12
 *
13
 * The method <code>show($style)</code> returns the style element $style for the current
14
 * component:
15
 *
16
 * It checks whether a style path is defined for the current component.
17
 *
18
 * - If there is a user defined style path, the element named $style in
19
 *   this path is returned,
20
 * - otherwise the element "$style" is taken from the default style of the
21
 *   current component (/path/to/component/style/$path).
22
 *
23
 * (The default fallback is always the default style, e.g. if $style
24
 * is not in the user defined style path)
25
 *
26
 * To enable cross-style referencing and provide the opportunity to access
27
 * any style element, "show" can be called with a full qualified style
28
 * path (like "/mystyle/element1", while the current page's style may be set
29
 * to "/yourstyle").
30
 *
31
 * Note: To make sure sub-styles and elements included in styles are handled
32
 * correctly, use:
33
 *
34
 * <code>
35
 * <?php midcom_show_style ("elementname"); ?>
36
 * </code>
37
 *
38
 * Style Inheritance
39
 *
40
 * The basic path the styleloader follows to find a style element is:
41
 * 1. Topic style -> if the current topic has a style set
42
 * 2. Inherited topic style -> if the topic inherits a style from another topic.
43
 * 3. Site-wide per-component default style -> if defined in MidCOM configuration key styleengine_default_styles
44
 * 4. Theme style -> the style of the MidCOM component.
45
 * 5. The file style. This is usually the elements found in the component's style directory.
46
 *
47
 * Regarding nr. 4:
48
 * It is possible to add extra file styles if so is needed for example by a portal component.
49
 * This is done either using the append/prepend component_style functions or by setting it
50
 * to another directory by calling (append|prepend)_styledir directly.
51
 *
52
 * NB: You cannot change this in another style element or in a _show() function in a component.
53
 *
54
 * @package midcom.helper
55
 */
56
class midcom_helper__styleloader
57
{
58
    /**
59
     * Current style scope
60
     *
61
     * @var array
62
     */
63
    private $_scope = [];
64
65
    /**
66
     * Current topic
67
     *
68
     * @var midcom_db_topic
69
     */
70
    private $_topic;
71
72
    /**
73
     * Default style path
74
     *
75
     * @var string
76
     */
77
    private $_snippetdir;
78
79
    /**
80
     * Context stack
81
     *
82
     * @var midcom_core_context[]
83
     */
84
    private $_context = [];
85
86
    /**
87
     * Default style element cache
88
     *
89
     * @var array
90
     */
91
    private $_snippets = [];
92
93
    /**
94
     * List of styledirs to handle after componentstyle
95
     *
96
     * @var array
97
     */
98
    private $_styledirs_append = [];
99
100
    /**
101
     * List of styledirs to handle before componentstyle
102
     *
103
     * @var array
104
     */
105
    private $_styledirs_prepend = [];
106
107
    /**
108
     * The stack of directories to check for styles.
109
     */
110
    private $_styledirs = [];
111
112
    /**
113
     * Data to pass to the style
114
     *
115
     * @var array
116
     */
117
    public $data;
118
119
    /**
120
     * Returns the path of the style described by $id.
121
     *
122
     * @param int $id    Style id to look up path for
123
     */
124
    public function get_style_path_from_id($id) : string
125
    {
126
        static $path_cache = [];
127
        if (isset($path_cache[$id])) {
128
            return $path_cache[$id];
129
        }
130
        // Construct the path
131
        $path_parts = [];
132
        $original_id = $id;
133
134
        try {
135
            while (($style = new midcom_db_style($id))) {
136
                $path_parts[] = $style->name;
137
                $id = $style->up;
138
139
                if ($style->up == 0) {
140
                    // Toplevel style
141
                    break;
142
                }
143
            }
144
        } catch (midcom_error $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
145
        }
146
147
        $path_parts = array_reverse($path_parts);
148
149
        $path_cache[$original_id] = '/' . implode('/', $path_parts);
150
151
        return $path_cache[$original_id];
152
    }
153
154
    /**
155
     * Returns the id of the style described by $path.
156
     *
157
     * Note: $path already includes the element name, so $path looks like
158
     * "/rootstyle/style/style/element".
159
     *
160
     * @todo complete documentation
161
     * @param string $path      The path to retrieve
162
     * @param int $rootstyle    ???
163
     * @return    int ID of the matching style or false
164
     */
165
    public function get_style_id_from_path($path, $rootstyle = 0)
166
    {
167
        static $cached = [];
168
169
        $cache_key = $rootstyle . '::' . $path;
170
171
        if (array_key_exists($cache_key, $cached)) {
172
            return $cached[$cache_key];
173
        }
174
175
        $path = preg_replace("/^\/(.*)/", "$1", $path); // leading "/"
176
        $cached[$cache_key] = false;
177
        $current_style = 0;
178
179
        $path_array = array_filter(explode('/', $path));
180
        if (!empty($path_array)) {
181
            $current_style = $rootstyle;
182
        }
183
184
        foreach ($path_array as $path_item) {
185
            $mc = midgard_style::new_collector('up', $current_style);
186
            $mc->set_key_property('guid');
187
            $mc->add_value_property('id');
188
            $mc->add_constraint('name', '=', $path_item);
189
            $mc->execute();
190
            $styles = $mc->list_keys();
191
192
            foreach (array_keys($styles) as $style_guid) {
193
                $current_style = $mc->get_subkey($style_guid, 'id');
194
                midcom::get()->cache->content->register($style_guid);
195
            }
196
        }
197
198
        if ($current_style != 0) {
199
            $cached[$cache_key] = $current_style;
200
        }
201
202
        return $cached[$cache_key];
203
    }
204
205
    /**
206
     * Returns a style element that matches $name and is in style $id.
207
     * It also returns an element if it is not in the given style,
208
     * but in one of its parent styles.
209
     *
210
     * @param int $id        The style id to search in.
211
     * @param string $name    The element to locate.
212
     * @return string    Value of the found element, or false on failure.
213
     */
214
    private function _get_element_in_styletree($id, string $name) : ?string
215
    {
216
        static $cached = [];
217
        $cache_key = $id . '::' . $name;
218
219
        if (array_key_exists($cache_key, $cached)) {
220
            return $cached[$cache_key];
221
        }
222
223
        $element_mc = midgard_element::new_collector('style', $id);
224
        $element_mc->set_key_property('guid');
225
        $element_mc->add_value_property('value');
226
        $element_mc->add_constraint('name', '=', $name);
227
        $element_mc->execute();
228
229
        if ($keys = $element_mc->list_keys()) {
230
            $element_guid = key($keys);
231
            $cached[$cache_key] = $element_mc->get_subkey($element_guid, 'value');
232
            midcom::get()->cache->content->register($element_guid);
233
            return $cached[$cache_key];
234
        }
235
236
        // No such element on this level, check parents
237
        $style_mc = midgard_style::new_collector('id', $id);
238
        $style_mc->set_key_property('guid');
239
        $style_mc->add_value_property('up');
240
        $style_mc->add_constraint('up', '>', 0);
241
        $style_mc->execute();
242
243
        if ($keys = $style_mc->list_keys()) {
244
            $style_guid = key($keys);
245
            midcom::get()->cache->content->register($style_guid);
246
            $up = $style_mc->get_subkey($style_guid, 'up');
247
            return $this->_get_element_in_styletree($up, $name);
0 ignored issues
show
Bug introduced by
It seems like $up can also be of type false; however, parameter $id of midcom_helper__styleload..._element_in_styletree() does only seem to accept integer, 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

247
            return $this->_get_element_in_styletree(/** @scrutinizer ignore-type */ $up, $name);
Loading history...
248
        }
249
250
        $cached[$cache_key] = null;
251
        return $cached[$cache_key];
252
    }
253
254
    /**
255
     * Looks for a style element matching $path (either in a user defined style
256
     * or the default style snippetdir) and displays/evaluates it.
257
     *
258
     * @param string $path    The style element to show.
259
     * @return boolean            True on success, false otherwise.
260
     */
261 202
    public function show($path) : bool
262
    {
263 202
        if ($this->_context === []) {
264
            debug_add("Trying to show '{$path}' but there is no context set", MIDCOM_LOG_INFO);
265
            return false;
266
        }
267
268 202
        $style = $this->load($path);
269
270 202
        if ($style === false) {
271 24
            if ($path == 'ROOT') {
272
                // Go to fallback ROOT instead of displaying a blank page
273
                return $this->show_midcom($path);
274
            }
275
276 24
            debug_add("The element '{$path}' could not be found.", MIDCOM_LOG_INFO);
277 24
            return false;
278
        }
279 201
        $this->render($style, $path);
280
281 201
        return true;
282
    }
283
284
    /**
285
     * Load style element content
286
     *
287
     * @param string $path The element name
288
     * @return false|string
289
     */
290 202
    public function load($path)
291
    {
292 202
        $element = $path;
293
        // we have full qualified path to element
294 202
        if (preg_match("|(.*)/(.*)|", $path, $matches)) {
295
            $stylepath = $matches[1];
296
            $element = $matches[2];
297
        }
298
299 202
        if (   isset($stylepath)
300 202
            && $styleid = $this->get_style_id_from_path($stylepath)) {
301
            array_unshift($this->_scope, $styleid);
302
        }
303
304 202
        if (!empty($this->_scope[0])) {
305
            $style = $this->_get_element_in_styletree($this->_scope[0], $element);
306
        }
307
308 202
        if (!empty($styleid)) {
309
            array_shift($this->_scope);
310
        }
311
312 202
        if (empty($style)) {
313 202
            $style = $this->_get_element_from_snippet($element);
314
        }
315 202
        return $style;
316
    }
317
318
    /**
319
     * Renders the style element with current request data
320
     *
321
     * @param string $style The style element content
322
     * @param string $path the element's name
323
     * @throws midcom_error
324
     */
325 201
    private function render(string $style, string $path)
326
    {
327 201
        if (midcom::get()->config->get('wrap_style_show_with_name')) {
328
            $style = "\n<!-- Start of style '{$path}' -->\n" . $style;
329
            $style .= "\n<!-- End of style '{$path}' -->\n";
330
        }
331
332
        // This is a bit of a hack to allow &(); tags
333 201
        $preparsed = midcom_helper_misc::preparse($style);
334 201
        if (midcom_core_context::get()->has_custom_key('request_data')) {
335 201
            $data =& midcom_core_context::get()->get_custom_key('request_data');
0 ignored issues
show
Bug introduced by
'request_data' of type string is incompatible with the type integer expected by parameter $key of midcom_core_context::get_custom_key(). ( Ignorable by Annotation )

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

335
            $data =& midcom_core_context::get()->get_custom_key(/** @scrutinizer ignore-type */ 'request_data');
Loading history...
Unused Code introduced by
The assignment to $data is dead and can be removed.
Loading history...
336
        }
337
338 201
        if (eval('?>' . $preparsed) === false) {
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
339
            // Note that src detection will be semi-reliable, as it depends on all errors being
340
            // found before caching kicks in.
341
            throw new midcom_error("Failed to parse style element '{$path}', see above for PHP errors.");
342
        }
343 201
    }
344
345
    /**
346
     * Looks for a midcom core style element matching $path and displays/evaluates it.
347
     * This offers a bit reduced functionality and will only look in the DB root style,
348
     * the theme directory and midcom's style directory, because it has to work even when
349
     * midcom is not yet fully initialized
350
     *
351
     * @param string $path    The style element to show.
352
     * @return boolean            True on success, false otherwise.
353
     */
354 1
    public function show_midcom($path) : bool
355
    {
356 1
        $_element = $path;
357 1
        $_style = false;
358
359 1
        $context = midcom_core_context::get();
360
361
        try {
362 1
            $root_topic = $context->get_key(MIDCOM_CONTEXT_ROOTTOPIC);
363 1
            if (   $root_topic->style
364 1
                && $db_style = $this->get_style_id_from_path($root_topic->style)) {
365 1
                $_style = $this->_get_element_in_styletree($db_style, $_element);
366
            }
367
        } catch (midcom_error_forbidden $e) {
368
            $e->log();
369
        }
370
371 1
        if ($_style === false) {
372 1
            if (isset($this->_styledirs[$context->id])) {
373 1
                $styledirs_backup = $this->_styledirs;
374
            }
375 1
            $this->_snippetdir = MIDCOM_ROOT . '/midcom/style';
376 1
            $this->_styledirs[$context->id][0] = $this->_snippetdir;
377
378 1
            $_style = $this->_get_element_from_snippet($_element);
379
380 1
            if (isset($styledirs_backup)) {
381 1
                $this->_styledirs = $styledirs_backup;
382
            }
383
        }
384
385 1
        if ($_style !== false) {
386 1
            $this->render($_style, $path);
387 1
            return true;
388
        }
389
        debug_add("The element '{$path}' could not be found.", MIDCOM_LOG_INFO);
390
        return false;
391
    }
392
393
    /**
394
     * Try to get element from default style snippet
395
     */
396 202
    private function _get_element_from_snippet(string $_element)
397
    {
398 202
        $src = "{$this->_snippetdir}/{$_element}";
399 202
        if (array_key_exists($src, $this->_snippets)) {
400 14
            return $this->_snippets[$src];
401
        }
402 202
        if (   midcom::get()->config->get('theme')
403 202
            && $content = midcom_helper_misc::get_element_content($_element)) {
404 6
            $this->_snippets[$src] = $content;
405 6
            return $content;
406
        }
407
408 202
        $current_context = midcom_core_context::get()->id;
409 202
        foreach ($this->_styledirs[$current_context] as $path) {
410 202
            $filename = $path . "/{$_element}.php";
411 202
            if (file_exists($filename)) {
412 192
                if (!array_key_exists($filename, $this->_snippets)) {
413 147
                    $this->_snippets[$filename] = file_get_contents($filename);
414
                }
415 192
                return $this->_snippets[$filename];
416
            }
417
        }
418 24
        return false;
419
    }
420
421
    /**
422
     * Gets the component style.
423
     *
424
     * @todo Document
425
     *
426
     * @return int Database ID if the style to use in current view or false
427
     */
428 268
    private function _get_component_style()
429
    {
430 268
        $_st = false;
431 268
        if (!$this->_topic) {
432 1
            return $_st;
433
        }
434
        // get user defined style for component
435
        // style inheritance
436
        // should this be cached somehow?
437 268
        if ($style = $this->_topic->style ?: midcom_core_context::get()->get_inherited_style()) {
438
            if (substr($style, 0, 6) === 'theme:') {
439
                $theme_dir = OPENPSA2_THEME_ROOT . midcom::get()->config->get('theme') . '/style';
440
                $parts = explode('/', str_replace('theme:/', '', $style));
441
442
                foreach ($parts as &$part) {
443
                    $theme_dir .= '/' . $part;
444
                    $part = $theme_dir;
445
                }
446
                foreach (array_reverse(array_filter($parts, 'is_dir')) as $dirname) {
447
                    $this->prepend_styledir($dirname);
448
                }
449
            } else {
450
                $_st = $this->get_style_id_from_path($style);
451
            }
452
        } else {
453
            // Get style from sitewide per-component defaults.
454 268
            $styleengine_default_styles = midcom::get()->config->get('styleengine_default_styles');
455 268
            if (isset($styleengine_default_styles[$this->_topic->component])) {
456
                $_st = $this->get_style_id_from_path($styleengine_default_styles[$this->_topic->component]);
457
            }
458
        }
459
460 268
        if ($_st) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $_st of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
461
            $substyle = midcom_core_context::get()->get_key(MIDCOM_CONTEXT_SUBSTYLE);
462
463
            if (is_string($substyle)) {
464
                $chain = explode('/', $substyle);
465
                foreach ($chain as $stylename) {
466
                    if ($_subst_id = $this->get_style_id_from_path($stylename, $_st)) {
467
                        $_st = $_subst_id;
468
                    }
469
                }
470
            }
471
        }
472 268
        return $_st;
473
    }
474
475
    /**
476
     * Gets the component styledir associated with the topic's component.
477
     *
478
     * @return mixed the path to the component's style directory.
479
     */
480 268
    private function _get_component_snippetdir()
481
    {
482
        // get component's snippetdir (for default styles)
483 268
        $loader = midcom::get()->componentloader;
484 268
        if (empty($this->_topic->component)) {
485 1
            return null;
486
        }
487 268
        return $loader->path_to_snippetpath($this->_topic->component) . "/style";
488
    }
489
490
    /**
491
     * Adds an extra style directory to check for style elements at
492
     * the end of the styledir queue.
493
     *
494
     * @param string $dirname path of style directory within midcom.
495
     * @throws midcom_error exception if directory does not exist.
496
     */
497 73
    function append_styledir($dirname)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
498
    {
499 73
        if (!file_exists($dirname)) {
500
            throw new midcom_error("Style directory $dirname does not exist!");
501
        }
502 73
        $this->_styledirs_append[midcom_core_context::get()->id][] = $dirname;
503 73
    }
504
505
    /**
506
     * Function prepend styledir
507
     *
508
     * @param string $dirname path of styledirectory within midcom.
509
     * @return boolean true if directory appended
510
     * @throws midcom_error if directory does not exist.
511
     */
512 81
    function prepend_styledir($dirname)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
513
    {
514 81
        if (!file_exists($dirname)) {
515
            throw new midcom_error("Style directory {$dirname} does not exist.");
516
        }
517 81
        $this->_styledirs_prepend[midcom_core_context::get()->id][] = $dirname;
518 81
        return true;
519
    }
520
521
    /**
522
     * Append the styledir of a component to the queue of styledirs.
523
     *
524
     * @param string $component Component name
525
     * @throws midcom_error exception if directory does not exist.
526
     */
527
    function append_component_styledir($component)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
528
    {
529
        $loader = midcom::get()->componentloader;
530
        $path = $loader->path_to_snippetpath($component) . "/style";
531
        $this->append_styledir($path);
532
    }
533
534
    /**
535
     * Prepend the styledir of a component
536
     *
537
     * @param string $component component name
538
     */
539 81
    public function prepend_component_styledir($component)
540
    {
541 81
        $loader = midcom::get()->componentloader;
542 81
        $path = $loader->path_to_snippetpath($component) . "/style";
543 81
        $this->prepend_styledir($path);
544 81
    }
545
546
    /**
547
     * Appends a substyle after the currently selected component style.
548
     *
549
     * Enables a depth of more than one style during substyle selection.
550
     *
551
     * @param string $newsub The substyle to append.
552
     */
553 31
    public function append_substyle($newsub)
554
    {
555
        // Make sure try to use only the first argument if we get space separated list, fixes #1788
556 31
        if (strpos($newsub, ' ') !== false) {
557
            $newsub = preg_replace('/^(.+?) .+/', '$1', $newsub);
558
        }
559
560 31
        $context = midcom_core_context::get();
561 31
        $current_style = $context->get_key(MIDCOM_CONTEXT_SUBSTYLE);
562
563 31
        if (!empty($current_style)) {
564
            $newsub = $current_style . '/' . $newsub;
565
        }
566
567 31
        $context->set_key(MIDCOM_CONTEXT_SUBSTYLE, $newsub);
568 31
    }
569
570
    /**
571
     * Prepends a substyle before the currently selected component style.
572
     *
573
     * Enables a depth of more than one style during substyle selection.
574
     *
575
     * @param string $newsub The substyle to prepend.
576
     */
577
    function prepend_substyle($newsub)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
578
    {
579
        $context = midcom_core_context::get();
580
        $current_style = $context->get_key(MIDCOM_CONTEXT_SUBSTYLE);
581
582
        if (!empty($current_style)) {
583
            $newsub .= "/" . $current_style;
584
        }
585
        debug_add("Updating Component Context Substyle from $current_style to $newsub");
586
587
        $context->set_key(MIDCOM_CONTEXT_SUBSTYLE, $newsub);
588
    }
589
590
    /**
591
     * Switches the context (see dynamic load).
592
     *
593
     * Private variables are adjusted, and the prepend and append styles are merged with the componentstyle.
594
     * You cannot change the style stack after that (unless you call enter_context again of course).
595
     *
596
     * @param midcom_core_context $context The context to enter
597
     */
598 268
    public function enter_context(midcom_core_context $context)
599
    {
600
        // set new context and topic
601 268
        array_unshift($this->_context, $context); // push into context stack
602
603 268
        $this->_topic = $context->get_key(MIDCOM_CONTEXT_CONTENTTOPIC);
0 ignored issues
show
Documentation Bug introduced by
It seems like $context->get_key(MIDCOM_CONTEXT_CONTENTTOPIC) can also be of type false. However, the property $_topic is declared as type midcom_db_topic. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
604
605
        // Prepare styledir stacks
606 268
        if (!isset($this->_styledirs_prepend[$context->id])) {
607 200
            $this->_styledirs_prepend[$context->id] = [];
608
        }
609 268
        if (!isset($this->_styledirs_append[$context->id])) {
610 195
            $this->_styledirs_append[$context->id] = [];
611
        }
612
613 268
        if ($_st = $this->_get_component_style()) {
614
            array_unshift($this->_scope, $_st);
615
        }
616
617 268
        $this->_snippetdir = $this->_get_component_snippetdir();
618
619 268
        $this->_styledirs[$context->id] = array_merge(
620 268
            $this->_styledirs_prepend[$context->id],
621 268
            [$this->_snippetdir],
622 268
            $this->_styledirs_append[$context->id]
623
        );
624 268
    }
625
626
    /**
627
     * Switches the context (see dynamic load). Private variables $_context, $_topic
628
     * and $_snippetdir are adjusted.
629
     *
630
     * @todo check documentation
631
     */
632 268
    public function leave_context()
633
    {
634 268
        if ($this->_get_component_style()) {
635
            array_shift($this->_scope);
636
        }
637 268
        array_shift($this->_context);
638
639 268
        $previous_context = (empty($this->_context)) ? midcom_core_context::get() : $this->_context[0];
640 268
        $this->_topic = $previous_context->get_key(MIDCOM_CONTEXT_CONTENTTOPIC);
0 ignored issues
show
Documentation Bug introduced by
It seems like $previous_context->get_k...M_CONTEXT_CONTENTTOPIC) can also be of type false. However, the property $_topic is declared as type midcom_db_topic. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
641
642 268
        $this->_snippetdir = $this->_get_component_snippetdir();
643 268
    }
644
}
645