Passed
Push — master ( 598445...fef947 )
by Andreas
11:12
created

midcom_admin_help_help::_prepare_breadcrumb()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 5
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 8
ccs 6
cts 6
cp 1
crap 2
rs 10
1
<?php
2
/**
3
 * @package midcom.admin.help
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
use Michelf\MarkdownExtra;
10
use midgard\portable\storage\connection;
11
12
/**
13
 * Online help display
14
 *
15
 * @package midcom.admin.help
16
 */
17
class midcom_admin_help_help extends midcom_baseclasses_components_plugin
18
{
19
    private array $mgdtypes = [
20
        MGD_TYPE_STRING => "string",
21
        MGD_TYPE_INT => "integer",
22
        MGD_TYPE_UINT => "unsigned integer",
23
        MGD_TYPE_FLOAT => "float",
24
        MGD_TYPE_BOOLEAN => "boolean",
25
        MGD_TYPE_TIMESTAMP => "datetime",
26
        MGD_TYPE_LONGTEXT => "longtext",
27
        MGD_TYPE_GUID => "guid",
28
        MGD_TYPE_NONE => 'none'
29
    ];
30
31 3
    public function _on_initialize()
32
    {
33 3
        midcom::get()->auth->require_valid_user();
34
35 3
        midcom::get()->skip_page_style = true;
36
        // doing this here as this component most probably will not be called by itself.
37 3
        midcom::get()->style->prepend_component_styledir('midcom.admin.help');
38
    }
39
40
    /**
41
     * Get component's documentation directory path
42
     */
43 8
    private static function get_documentation_dir(string $component) : string
44
    {
45 8
        return midcom::get()->componentloader->path_to_snippetpath($component) . '/documentation/';
46
    }
47
48 8
    public static function generate_file_path(string $help_id, string $component, ?string $language = null) : ?string
49
    {
50 8
        $language ??= midcom::get()->i18n->get_current_language();
51
52 8
        $file = self::get_documentation_dir($component) . "{$help_id}.{$language}.txt";
53 8
        if (!file_exists($file)) {
54 8
            if ($language != midcom::get()->i18n->get_fallback_language()) {
55
                // Try MidCOM's default fallback language
56 1
                return self::generate_file_path($help_id, $component, midcom::get()->i18n->get_fallback_language());
57
            }
58 8
            return null;
59
        }
60
61 5
        return $file;
62
    }
63
64 4
    private function get_help_title(string $help_id, string $component) : string
65
    {
66 4
        if ($path = self::generate_file_path($help_id, $component)) {
67 4
            $file_contents = file($path);
68 4
            if (trim($file_contents[0])) {
69 4
                return trim($file_contents[0]);
70
            }
71
        }
72
73 1
        return $this->_l10n->get("help_" . $help_id);
74
    }
75
76
    /**
77
     * Load the file from the component's documentation directory.
78
     */
79 5
    private function _load_file(string $help_id, string $component) : ?string
80
    {
81
        // Try loading the file
82 5
        if ($file = self::generate_file_path($help_id, $component)) {
83
            // Load the contents
84 1
            $help_contents = file_get_contents($file);
85
86
            // Replace static URLs (URLs for screenshots etc)
87 1
            return str_replace('MIDCOM_STATIC_URL', MIDCOM_STATIC_URL, $help_contents);
88
        }
89 4
        return null;
90
    }
91
92
    /**
93
     * Load a help file and markdownize it
94
     */
95 5
    public function get_help_contents(string $help_id, string $component) : ?string
96
    {
97 5
        if ($text = $this->_load_file($help_id, $component)) {
98 1
            return MarkdownExtra::defaultTransform($text);
99
        }
100 4
        return null;
101
    }
102
103 5
    public function list_files(string $component, bool $with_index = false) : array
104
    {
105 5
        $files = $this->_list_physical_files($component);
106 5
        $files = $this->_add_virtual_files($files, $component);
107
108 5
        ksort($files);
109
        // prepend 'index' URL if required
110 5
        if ($with_index) {
111 1
            $files = array_merge([
112 1
                'index' => [
113 1
                    'path' => '/',
114 1
                    'subject' => $this->_l10n->get('help_index'),
115 1
                    'lang' => 'en',
116 1
                ]],
117 1
                $files
118 1
            );
119
        }
120 5
        return $files;
121
    }
122
123 5
    private function _add_virtual_files(array $files, string $component) : array
124
    {
125 5
        $options = [
126 5
            'mgdschemas' => midcom::get()->dbclassloader->get_component_classes($component),
127 5
            'urlmethods' => $this->read_url_methods($component)
128 5
        ];
129 5
        if ($component != 'midcom') {
130 5
            $options['handlers'] = $this->read_component_handlers($component);
131
        }
132 5
        foreach (array_filter($options) as $key => $values) {
133 5
            $files[$key] = [
134 5
                'path' => '/' . $key,
135 5
                'subject' => $this->_l10n->get('help_' . $key),
136 5
                'lang' => 'en',
137 5
            ];
138 5
            $this->_request_data[$key] = $values;
139
        }
140
141 5
        return $files;
142
    }
143
144 5
    private function _list_physical_files(string $component) : array
145
    {
146 5
        $component_dir = self::get_documentation_dir($component);
147 5
        if (!is_dir($component_dir)) {
148 1
            return [];
149
        }
150
151 4
        $files = [];
152 4
        $pattern = $component_dir . '*.{' . $this->_i18n->get_current_language() . ',' . $this->_i18n->get_fallback_language() . '}.txt';
153
154 4
        foreach (glob($pattern, GLOB_NOSORT|GLOB_BRACE) as $path) {
155 4
            $entry = basename($path);
156 4
            if (   str_starts_with($entry, 'index')
157 4
                || str_starts_with($entry, 'handler')
158 4
                || str_starts_with($entry, 'urlmethod')) {
159
                // Ignore dotfiles, handlers & index.lang.txt
160 1
                continue;
161
            }
162
163 4
            $filename_parts = explode('.', $entry);
164
165 4
            $files[$filename_parts[0]] = [
166 4
                'path' => $path,
167 4
                'subject' => $this->get_help_title($filename_parts[0], $component),
168 4
                'lang' => $filename_parts[1],
169 4
            ];
170
        }
171
172 4
        return $files;
173
    }
174
175 5
    private function read_component_handlers(string $component) : array
176
    {
177 5
        $data = [];
178
179 5
        $viewer = midcom::get()->componentloader->get_interface_class($component)->get_viewer(new midcom_db_topic);
180 5
        $routes = $viewer->get_router()->getRouteCollection()->all();
181 5
        foreach ($routes as $handler_id => $route) {
182 4
            $details = [
183 4
                'route' => preg_replace('/args_(\d+)/', 'args[\1]', $route->getPath())
184 4
            ];
185
186 4
            [$details['controller'], $details['action']] = explode('::', $route->getDefault('_controller'), 2);
187
188 4
            if (self::generate_file_path('handlers_' . $handler_id, $component)) {
189 1
                $details['info'] = $this->get_help_contents('handlers_' . $handler_id, $component);
190 1
                $details['handler_help_url'] = 'handlers_' . $handler_id;
191
            }
192 4
            $data[$handler_id] = $details;
193
        }
194
195 5
        return $data;
196
    }
197
198 5
    private function read_url_methods(string $component) : array
199
    {
200 5
        $data = [];
201
202 5
        $exec_path = midcom::get()->componentloader->path_to_snippetpath($component) . '/exec/';
203 5
        if (   !is_dir($exec_path)
204 5
            || !is_readable($exec_path)) {
205
            // Directory not accessible, skip loading it
206 1
            return $data;
207
        }
208
209 4
        foreach (glob($exec_path . '/*.php', GLOB_NOSORT) as $path) {
210 4
            $file = basename($path);
211 4
            $info_id = "urlmethod_" . str_replace('.php', '', $file);
212
213 4
            $data[$file] = [
214 4
                'url' => '/midcom-exec-' . $component . '/' . $file,
215 4
            ];
216
217 4
            if (self::generate_file_path($info_id, $component)) {
218
                $data[$file]['handler_help_url'] = $info_id;
219
                $data[$file]['description'] = $this->get_help_contents($info_id, $component);
220
            }
221
        }
222
223 4
        return $data;
224
    }
225
226 1
    private function read_schema_properties()
227
    {
228 1
        foreach (array_keys($this->_request_data['mgdschemas']) as $mgdschema_class) {
229 1
            $this->_request_data['properties'][$mgdschema_class] = [];
230 1
            $mrp = new midgard_reflection_property($mgdschema_class);
231 1
            $class_props = connection::get_em()->getClassMetadata($mgdschema_class)->get_schema_properties();
0 ignored issues
show
introduced by
The method get_schema_properties() does not exist on Doctrine\ORM\Mapping\ClassMetadata. Are you sure you never get this type here, but always one of the subclasses? ( Ignorable by Annotation )

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

231
            $class_props = connection::get_em()->getClassMetadata($mgdschema_class)->/** @scrutinizer ignore-call */ get_schema_properties();
Loading history...
232
233 1
            foreach (array_diff($class_props, ['action', 'metadata']) as $prop) {
234 1
                $this->_request_data['properties'][$mgdschema_class][$prop] = [
235 1
                    'value' => $mrp->description($prop) ?? '',
236 1
                    'link' => $mrp->is_link($prop),
237 1
                    'link_name' => $mrp->get_link_name($prop),
238 1
                    'link_target' => $mrp->get_link_target($prop),
239 1
                    'midgard_type' => $this->mgdtypes[$mrp->get_midgard_type($prop)]
240 1
                ];
241
            }
242
        }
243
    }
244
245 3
    private function _prepare_breadcrumb(string $handler_id)
246
    {
247 3
        $this->add_breadcrumb($this->router->generate('welcome'), $this->_l10n->get('help'));
248
249 3
        if (in_array($handler_id, ['help', 'component'])) {
250 2
            $this->add_breadcrumb(
251 2
                $this->router->generate('component', ['component' => $this->_request_data['component']]),
252 2
                $this->_i18n->get_string($this->_request_data['component'], $this->_request_data['component'])
253 2
            );
254
        }
255
    }
256
257 1
    public function _handler_welcome(string $handler_id, array &$data)
258
    {
259 1
        $data['view_title'] = $this->_l10n->get($this->_component);
260 1
        midcom::get()->head->set_pagetitle($data['view_title']);
261
262 1
        $data['components'] = [];
263 1
        $data['libraries'] = [];
264
265 1
        foreach (midcom::get()->componentloader->get_manifests() as $manifest) {
266 1
            $type = $manifest->purecode ? 'libraries' : 'components';
267 1
            $title = $manifest->get_name_translated();
268 1
            if ($title == $manifest->name) {
269 1
                $title = '';
270
            }
271
272 1
            $data[$type][$manifest->name] = [
273 1
                'name' => $manifest->name,
274 1
                'title' => $title,
275 1
                'icon' => midcom::get()->componentloader->get_component_icon($manifest->name),
276 1
                'description' => $manifest->description,
277 1
            ];
278
        }
279
280 1
        asort($data['components']);
281 1
        asort($data['libraries']);
282
283 1
        $this->_prepare_breadcrumb($handler_id);
284
    }
285
286
    /**
287
     * Shows the help system main screen
288
     */
289 1
    public function _show_welcome(string $handler_id, array &$data)
290
    {
291 1
        midcom_show_style('midcom_admin_help_header');
292 1
        midcom_show_style('midcom_admin_help_about');
293 1
        $list_types = ['components', 'libraries'];
294
295 1
        foreach ($list_types as $list_type) {
296 1
            $data['list_type'] = $list_type;
297 1
            midcom_show_style('midcom_admin_help_list_header');
298 1
            foreach ($data[$list_type] as $component_data) {
299 1
                $data['component_data'] = $component_data;
300 1
                midcom_show_style('midcom_admin_help_list_item');
301
            }
302 1
            midcom_show_style('midcom_admin_help_list_footer');
303
        }
304
305 1
        midcom_show_style('midcom_admin_help_footer');
306
    }
307
308 1
    public function _handler_component(string $handler_id, string $component, array &$data)
309
    {
310 1
        $data['component'] = $component;
311 1
        $data['view_title'] = sprintf($this->_l10n->get('help for %s'), $this->_i18n->get_string($component, $component));
312 1
        midcom::get()->head->set_pagetitle($data['view_title']);
313
314 1
        $data['help_files'] = $this->list_files($component);
315 1
        $data['html'] = $this->get_help_contents('index', $component);
316 1
        $this->_prepare_breadcrumb($handler_id);
317
    }
318
319
    /**
320
     * Shows the component help ToC.
321
     */
322 1
    public function _show_component(string $handler_id, array &$data)
323
    {
324 1
        midcom_show_style('midcom_admin_help_header');
325
326 1
        midcom_show_style('midcom_admin_help_show');
327 1
        midcom_show_style('midcom_admin_help_component');
328
329 1
        midcom_show_style('midcom_admin_help_footer');
330
    }
331
332 1
    public function _handler_help(string $handler_id, string $component, string $help_id, array &$data)
333
    {
334 1
        $data['help_id'] = $help_id;
335 1
        $data['component'] = $component;
336 1
        $data['help_files'] = $this->list_files($component);
337
338 1
        if ($help_id == 'mgdschemas') {
339 1
            $this->read_schema_properties();
340
        }
341 1
        $data['html'] = $this->get_help_contents($help_id, $component);
342
343 1
        midcom::get()->head->add_jsfile(MIDCOM_STATIC_URL . '/midcom.admin.help/twisty.js');
344 1
        $this->add_stylesheet(MIDCOM_STATIC_URL . '/stock-icons/font-awesome-4.7.0/css/font-awesome.min.css');
345
346
        // Table of contents navi
347 1
        $data['view_title'] = sprintf(
348 1
            $this->_l10n->get('help for %s in %s'),
349 1
            $this->get_help_title($help_id, $component),
350 1
            $this->_i18n->get_string($component, $component)
351 1
        );
352 1
        midcom::get()->head->set_pagetitle($data['view_title']);
353 1
        $this->_prepare_breadcrumb($handler_id);
354 1
        if (in_array($help_id, ['handlers', 'urlmethods', 'mgdschemas'])) {
355 1
            $this->add_breadcrumb("", $this->_l10n->get($help_id));
356
        } else {
357
            $this->add_breadcrumb("", $this->get_help_title($help_id, $component));
358
        }
359
    }
360
361
    /**
362
     * Shows the help page.
363
     */
364 1
    public function _show_help(string $handler_id, array &$data)
365
    {
366 1
        midcom_show_style('midcom_admin_help_header');
367 1
        midcom_show_style('midcom_admin_help_show');
368 1
        if (in_array($data['help_id'], ['handlers', 'mgdschemas', 'urlmethods'])) {
369 1
            midcom_show_style('midcom_admin_help_' . $data['help_id']);
370
        } elseif (!$data['html']) {
371
            $data['html'] = $this->get_help_contents('notfound', $this->_component);
372
            midcom_show_style('midcom_admin_help_show');
373
            midcom_show_style('midcom_admin_help_component');
374
        }
375 1
        midcom_show_style('midcom_admin_help_footer');
376
    }
377
}
378