Passed
Push — master ( 1b6466...f0a80d )
by Andreas
24:57
created

loader   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 143
Duplicated Lines 0 %

Test Coverage

Coverage 86.36%

Importance

Changes 8
Bugs 0 Features 0
Metric Value
eloc 63
c 8
b 0
f 0
dl 0
loc 143
ccs 57
cts 66
cp 0.8636
rs 10
wmc 27

7 Methods

Rating   Name   Duplication   Size   Complexity  
A set_directories() 0 7 2
A initialize() 0 12 5
B get_element() 0 22 7
A get_component_snippetdir() 0 6 2
A add_to_cache() 0 4 1
A get_element_from_theme() 0 32 6
A resolve_includes() 0 17 4
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 midcom_connection;
15
16
/**
17
 * templating loader class
18
 *
19
 * Style Inheritance
20
 *
21
 * The basic path the styleloader follows to find a style element is:
22
 * 1. Topic style -> if the current topic has a style set
23
 * 2. Inherited topic style -> if the topic inherits a style from another topic.
24
 * 3. Site-wide per-component default style -> if defined in MidCOM configuration key styleengine_default_styles
25
 * 4. Theme style -> the style of the MidCOM component.
26
 * 5. The file style. This is usually the elements found in the component's style directory.
27
 *
28
 * Regarding no. 5:
29
 * It is possible to add extra file styles if so is needed for example by a portal component.
30
 * This is done either using the append/prepend component_style functions of midcom::get()->style or by setting it
31
 * to another directory by calling (append|prepend)_styledir directly.
32
 *
33
 * @package midcom.templating
34
 */
35
class loader
36
{
37
    /**
38
     * Default style element cache
39
     *
40
     * @var string[]
41
     */
42
    protected $cache = [];
43
44
    /**
45
     * The stack of directories to check for styles.
46
     *
47
     * @var string[]
48
     */
49
    private $directories = [];
50
51 271
    public function set_directories(?midcom_db_topic $topic, array $prepend, array $append)
52
    {
53 271
        $this->directories = $prepend;
54 271
        if ($snippetdir = $this->get_component_snippetdir($topic)) {
55 271
            $this->directories[] = $snippetdir;
56
        }
57 271
        $this->directories = array_merge($this->directories, $append);
58 271
    }
59
60
    /**
61
     * Gets the component styledir associated with the topic's component.
62
     *
63
     * @return mixed the path to the component's style directory.
64
     */
65 271
    private function get_component_snippetdir(?midcom_db_topic $topic) : ?string
66
    {
67 271
        if (empty($topic->component)) {
68 2
            return null;
69
        }
70 271
        return midcom::get()->componentloader->path_to_snippetpath($topic->component) . "/style";
71
    }
72
73
    /**
74
     * Try to get element from default style snippet
75
     */
76 205
    public function get_element(string $name, bool $scope_from_path) : ?string
77
    {
78 205
        if (midcom::get()->config->get('theme')) {
79 205
            $src = "theme:{$name}";
80 205
            if (array_key_exists($src, $this->cache)) {
81 13
                return $this->cache[$src];
82
            }
83 205
            if ($content = $this->get_element_from_theme($name)) {
84 2
                return $this->add_to_cache($src, $content);
85
            }
86
        }
87
88 205
        foreach ($this->directories as $path) {
89 205
            $filename = $path . "/{$name}.php";
90 205
            if (file_exists($filename)) {
91 195
                if (array_key_exists($filename, $this->cache)) {
92 79
                    return $this->cache[$filename];
93
                }
94 150
                return $this->add_to_cache($filename, file_get_contents($filename));
95
            }
96
        }
97 20
        return null;
98
    }
99
100
    /**
101
     * Get the content of the element by the passed element name.
102
     * Tries to resolve path according to theme-name & page
103
     */
104 205
    private function get_element_from_theme(string $element_name) : ?string
105
    {
106 205
        $theme = midcom::get()->config->get('theme');
107 205
        $path_array = explode('/', $theme);
0 ignored issues
show
Bug introduced by
It seems like $theme can also be of type null; however, parameter $string of explode() does only seem to accept string, 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

107
        $path_array = explode('/', /** @scrutinizer ignore-type */ $theme);
Loading history...
108
109
        //get the page if there is one
110 205
        $page = midcom_connection::get_url('page_style');
111 205
        $substyle = midcom_core_context::get()->get_key(MIDCOM_CONTEXT_SUBSTYLE);
112
        //check if we have elements for the sub-styles
113 205
        while (!empty($path_array)) {
114 205
            $theme_path = implode('/', $path_array);
115 205
            $candidates = [];
116 205
            if ($substyle) {
117 31
                $candidates[] = '/' . $substyle . '/' . $element_name;
118
            }
119 205
            if ($page) {
120
                $candidates[] = $page . '/' . $element_name;
121
            }
122 205
            $candidates[] = '/' . $element_name;
123
124 205
            foreach ($candidates as $candidate) {
125 205
                $filename = OPENPSA2_THEME_ROOT . $theme_path . '/style' . $candidate . '.php';
126 205
                if (file_exists($filename)) {
127 2
                    return file_get_contents($filename);
128
                }
129
            }
130
131
            //remove last theme part
132 205
            array_pop($path_array);
133
        }
134
135 205
        return null;
136
    }
137
138 151
    protected function add_to_cache(string $cache_key, string $content) : string
139
    {
140 151
        $this->cache[$cache_key] = $this->resolve_includes($content);
141 151
        return $this->cache[$cache_key];
142
    }
143
144 151
    private function resolve_includes(string $content) : string
145
    {
146
        return preg_replace_callback("/<\\(([a-zA-Z0-9 _-]+)\\)>/", function (array $matches) {
147 3
            $element = $matches[1];
148
149 3
            switch ($element) {
150 3
                case 'title':
151 2
                    return midcom::get()->config->get('midcom_site_title');
152 2
                case 'content':
153 2
                    return '<?php midcom_core_context::get()->show(); ?>';
154
                default:
155 1
                    if ($value = $this->get_element_from_theme($element)) {
156 1
                        return $this->resolve_includes($value);
157
                    }
158
                    return '';
159
            }
160 151
        }, $content);
161
    }
162
163
    /**
164
     * Initializes style sources
165
     */
166 271
    public function initialize(midcom_core_context $context, ?string $style)
167
    {
168 271
        if ($style && str_starts_with($style, 'theme:')) {
169
            $theme_dir = OPENPSA2_THEME_ROOT . midcom::get()->config->get('theme') . '/style';
170
            $parts = explode('/', str_replace('theme:/', '', $style));
171
172
            foreach ($parts as &$part) {
173
                $theme_dir .= '/' . $part;
174
                $part = $theme_dir;
175
            }
176
            foreach (array_reverse(array_filter($parts, 'is_dir')) as $dirname) {
177
                midcom::get()->style->prepend_styledir($dirname);
178
            }
179
        }
180 271
    }
181
}
182