Passed
Push — master ( 9eeb8b...1fec05 )
by Andreas
16:44
created

loader::get_element_from_snippet()   B

Complexity

Conditions 7
Paths 10

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 7

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 14
c 1
b 0
f 0
nc 10
nop 1
dl 0
loc 23
ccs 15
cts 15
cp 1
crap 7
rs 8.8333
1
<?php
2
/**
3
 * @package midcom.templating
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\templating;
10
11
use midcom;
12
use midcom_db_topic;
13
use midcom_core_context;
14
use midgard_style;
15
use midgard_element;
16
use midcom_db_style;
17
use midcom_helper_misc;
18
19
/**
20
 * templating loader class
21
 *
22
 * Style Inheritance
23
 *
24
 * The basic path the styleloader follows to find a style element is:
25
 * 1. Topic style -> if the current topic has a style set
26
 * 2. Inherited topic style -> if the topic inherits a style from another topic.
27
 * 3. Site-wide per-component default style -> if defined in MidCOM configuration key styleengine_default_styles
28
 * 4. Theme style -> the style of the MidCOM component.
29
 * 5. The file style. This is usually the elements found in the component's style directory.
30
 *
31
 * Regarding no. 5:
32
 * It is possible to add extra file styles if so is needed for example by a portal component.
33
 * This is done either using the append/prepend component_style functions of midcom::get()->style or by setting it
34
 * to another directory by calling (append|prepend)_styledir directly.
35
 *
36
 * @package midcom.templating
37
 */
38
class loader
39
{
40
    /**
41
     * Default style element cache
42
     *
43
     * @var string[]
44
     */
45
    private $_snippets = [];
46
47
    /**
48
     * The stack of directories to check for styles.
49
     *
50
     * @var string[]
51
     */
52
    private $directories = [];
53
54 268
    public function set_directories(?midcom_db_topic $topic, array $prepend, array $append)
55
    {
56 268
        $this->directories = $prepend;
57 268
        if ($snippetdir = $this->get_component_snippetdir($topic)) {
58 268
            $this->directories[] = $snippetdir;
59
        }
60 268
        $this->directories = array_merge($this->directories, $append);
61 268
    }
62
63
    /**
64
     * Gets the component styledir associated with the topic's component.
65
     *
66
     * @return mixed the path to the component's style directory.
67
     */
68 268
    private function get_component_snippetdir(?midcom_db_topic $topic) : ?string
69
    {
70 268
        if (empty($topic->component)) {
71 2
            return null;
72
        }
73 268
        return midcom::get()->componentloader->path_to_snippetpath($topic->component) . "/style";
74
    }
75
76
    /**
77
     * Returns a style element that matches $name and is in style $id.
78
     * It also returns an element if it is not in the given style,
79
     * but in one of its parent styles.
80
     *
81
     * @param int $id        The style id to search in.
82
     * @param string $name    The element to locate.
83
     * @return string    Value of the found element, or false on failure.
84
     */
85
    public function get_element_in_styletree($id, string $name) : ?string
86
    {
87
        static $cached = [];
88
        $cache_key = $id . '::' . $name;
89
90
        if (array_key_exists($cache_key, $cached)) {
91
            return $cached[$cache_key];
92
        }
93
94
        $element_mc = midgard_element::new_collector('style', $id);
95
        $element_mc->set_key_property('guid');
96
        $element_mc->add_value_property('value');
97
        $element_mc->add_constraint('name', '=', $name);
98
        $element_mc->execute();
99
100
        if ($keys = $element_mc->list_keys()) {
101
            $element_guid = key($keys);
102
            $cached[$cache_key] = $element_mc->get_subkey($element_guid, 'value');
103
            midcom::get()->cache->content->register($element_guid);
104
            return $cached[$cache_key];
105
        }
106
107
        // No such element on this level, check parents
108
        $style_mc = midgard_style::new_collector('id', $id);
109
        $style_mc->set_key_property('guid');
110
        $style_mc->add_value_property('up');
111
        $style_mc->add_constraint('up', '>', 0);
112
        $style_mc->execute();
113
114
        if ($keys = $style_mc->list_keys()) {
115
            $style_guid = key($keys);
116
            midcom::get()->cache->content->register($style_guid);
117
            $up = $style_mc->get_subkey($style_guid, 'up');
118
            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\templating\loader..._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

118
            return $this->get_element_in_styletree(/** @scrutinizer ignore-type */ $up, $name);
Loading history...
119
        }
120
121
        $cached[$cache_key] = null;
122
        return $cached[$cache_key];
123
    }
124
125
    /**
126
     * Try to get element from default style snippet
127
     */
128 202
    public function get_element_from_snippet(string $_element) : ?string
129
    {
130 202
        if (midcom::get()->config->get('theme')) {
131 202
            $src = "theme:{$_element}";
132 202
            if (array_key_exists($src, $this->_snippets)) {
133 18
                return $this->_snippets[$src];
134
            }
135 202
            if ($content = midcom_helper_misc::get_element_content($_element)) {
136 2
                $this->_snippets[$src] = $content;
137 2
                return $this->_snippets[$src];
138
            }
139
        }
140
141 202
        foreach ($this->directories as $path) {
142 202
            $filename = $path . "/{$_element}.php";
143 202
            if (file_exists($filename)) {
144 192
                if (!array_key_exists($filename, $this->_snippets)) {
145 147
                    $this->_snippets[$filename] = file_get_contents($filename);
146
                }
147 192
                return $this->_snippets[$filename];
148
            }
149
        }
150 24
        return null;
151
    }
152
153
    /**
154
     * Initializes style sources from topic
155
     */
156 268
    public function initialize_from_topic(midcom_db_topic $topic, midcom_core_context $context)
157
    {
158 268
        $_st = 0;
159
        // get user defined style for component
160
        // style inheritance
161
        // should this be cached somehow?
162 268
        if ($style = $topic->style ?: $context->get_inherited_style()) {
163
            if (substr($style, 0, 6) === 'theme:') {
164
                $theme_dir = OPENPSA2_THEME_ROOT . midcom::get()->config->get('theme') . '/style';
165
                $parts = explode('/', str_replace('theme:/', '', $style));
166
167
                foreach ($parts as &$part) {
168
                    $theme_dir .= '/' . $part;
169
                    $part = $theme_dir;
170
                }
171
                foreach (array_reverse(array_filter($parts, 'is_dir')) as $dirname) {
172
                    midcom::get()->style->prepend_styledir($dirname);
173
                }
174
            } else {
175
                $_st = midcom_db_style::id_from_path($style);
176
            }
177
        } else {
178
            // Get style from sitewide per-component defaults.
179 268
            $styleengine_default_styles = midcom::get()->config->get('styleengine_default_styles');
180 268
            if (isset($styleengine_default_styles[$topic->component])) {
181
                $_st = midcom_db_style::id_from_path($styleengine_default_styles[$topic->component]);
182
            }
183
        }
184
185 268
        if ($_st) {
186
            $substyle = $context->get_key(MIDCOM_CONTEXT_SUBSTYLE);
187
188
            if (is_string($substyle)) {
189
                $chain = explode('/', $substyle);
190
                foreach ($chain as $stylename) {
191
                    if ($_subst_id = midcom_db_style::id_from_path($stylename, $_st)) {
192
                        $_st = $_subst_id;
193
                    }
194
                }
195
            }
196
        }
197 268
        $context->set_custom_key(midcom_db_style::class, $_st);
198 268
    }
199
}
200