Completed
Push — master ( 81eb48...b7618e )
by Andreas
15:55
created

midcom_admin_help_help::_list_components()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 0
dl 0
loc 15
ccs 0
cts 9
cp 0
crap 12
rs 9.4285
c 0
b 0
f 0
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 $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 5
    public function __construct()
32
    {
33 5
        parent::__construct();
34 5
        $this->add_stylesheet(MIDCOM_STATIC_URL . '/midcom.admin.help/style-editor.css');
35
36 5
        midcom::get()->head->add_jsfile(MIDCOM_STATIC_URL . '/midcom.admin.help/twisty.js');
37 5
    }
38
39
    public function _on_initialize()
40
    {
41
        midcom::get()->skip_page_style = true;
42
        // doing this here as this component most probably will not be called by itself.
43
        midcom::get()->style->prepend_component_styledir('midcom.admin.help');
44
    }
45
46
    /**
47
     * Get component's documentation directory path
48
     *
49
     * @param string $component Component name
50
     * @return string Component documentation directory path
51
     */
52 6
    private static function get_documentation_dir($component)
53
    {
54 6
        if (!midcom::get()->componentloader->is_installed($component)) {
55
            throw new midcom_error("Failed to generate documentation path for component {$component} as it is not installed.");
56
        }
57 6
        return midcom::get()->componentloader->path_to_snippetpath($component) . '/documentation/';
58
    }
59
60 6
    public static function generate_file_path($help_id, $component, $language = null)
61
    {
62 6
        if ($language === null) {
63 6
            $language = midcom::get()->i18n->get_current_language();
64
        }
65
66 6
        $file = self::get_documentation_dir($component) . "{$help_id}.{$language}.txt";
67 6
        if (!file_exists($file)) {
68 5
            if ($language != midcom::get()->config->get('i18n_fallback_language')) {
69
                // Try MidCOM's default fallback language
70 1
                return self::generate_file_path($help_id, $component, midcom::get()->config->get('i18n_fallback_language'));
71
            }
72 5
            return null;
73
        }
74
75 3
        return $file;
76
    }
77
78 2
    private function get_help_title($help_id, $component)
79
    {
80 2
        if ($path = self::generate_file_path($help_id, $component)) {
81 2
            $file_contents = file($path);
82 2
            if (trim($file_contents[0])) {
83 2
                return trim($file_contents[0]);
84
            }
85
        }
86
87
        return midcom::get()->i18n->get_string("help_" . $help_id, 'midcom.admin.help');
88
    }
89
90
    /**
91
     * Load the file from the component's documentation directory.
92
     */
93 4
    private function _load_file($help_id, $component)
94
    {
95
        // Try loading the file
96 4
        $file = self::generate_file_path($help_id, $component);
97 4
        if (!$file) {
98 4
            return false;
99
        }
100
101
        // Load the contents
102
        $help_contents = file_get_contents($file);
103
104
        // Replace static URLs (URLs for screenshots etc)
105
        return str_replace('MIDCOM_STATIC_URL', MIDCOM_STATIC_URL, $help_contents);
106
    }
107
108
    /**
109
     * Load a help file and markdownize it
110
     */
111 4
    public function get_help_contents($help_id, $component)
112
    {
113 4
        $text = $this->_load_file($help_id, $component);
114 4
        if (!$text) {
115 4
            return false;
116
        }
117
        return MarkdownExtra::defaultTransform($text);
118
    }
119
120 3
    public function list_files($component, $with_index = false)
121
    {
122 3
        $files = $this->_list_physical_files($component);
123 3
        $files = $this->_add_virtual_files($files, $component);
124
125 3
        ksort($files);
126
        // prepend 'index' URL if required
127 3
        if ($with_index) {
128 1
            $files = array_merge([
129
                'index' => [
130 1
                    'path' => '/',
131 1
                    'subject' => $this->_l10n->get('help_index'),
132 1
                    'lang' => 'en',
133
                ]],
134
                $files
135
            );
136
        }
137 3
        return $files;
138
    }
139
140 3
    private function _add_virtual_files($files, $component)
141
    {
142
        // Schemas
143 3
        $this->_request_data['mgdschemas'] = midcom::get()->dbclassloader->get_component_classes($component);
144 3
        if (count($this->_request_data['mgdschemas'])) {
145 1
            $files['mgdschemas'] = [
146 1
                'path' => '/mgdschemas',
147 1
                'subject' => $this->_l10n->get('help_mgdschemas'),
148 1
                'lang' => 'en',
149
            ];
150
        }
151
152
        // URL Methods
153 3
        $this->_request_data['urlmethods'] = $this->read_url_methods($component);
154 3
        if (count($this->_request_data['urlmethods'])) {
155 2
            $files['urlmethods'] = [
156 2
                'path' => '/urlmethods',
157 2
                'subject' => $this->_l10n->get('help_urlmethods'),
158 2
                'lang' => 'en',
159
            ];
160
        }
161
162
        // Break if dealing with MidCOM Core docs
163 3
        if ($component == 'midcom') {
164
            ksort($files);
165
            return $files;
166
        }
167
168
        // handlers
169 3
        $this->_request_data['request_switch_info'] = $this->read_component_handlers($component);
170 3
        if (count($this->_request_data['request_switch_info'])) {
171
            $files['handlers'] = [
172
                'path' => '/handlers',
173
                'subject' => $this->_l10n->get('help_handlers'),
174
                'lang' => 'en',
175
            ];
176
        }
177
178 3
        return $files;
179
    }
180
181 3
    private function _list_physical_files($component)
182
    {
183 3
        $component_dir = self::get_documentation_dir($component);
184 3
        if (!is_dir($component_dir)) {
185 1
            return [];
186
        }
187
188 2
        $files = [];
189 2
        $pattern = $component_dir . '*.{' . midcom::get()->i18n->get_current_language() . ',' . midcom::get()->config->get('i18n_fallback_language') . '}.txt';
190
191 2
        foreach (glob($pattern, GLOB_NOSORT|GLOB_BRACE) as $path) {
192 2
            $entry = basename($path);
193 2
            if (    substr($entry, 0, 5) == 'index'
194 2
                 || substr($entry, 0, 7) == 'handler'
195 2
                 || substr($entry, 0, 9) == 'urlmethod') {
196
                // Ignore dotfiles, handlers & index.lang.txt
197 1
                continue;
198
            }
199
200 2
            $filename_parts = explode('.', $entry);
201
202 2
            $files[$filename_parts[0]] = [
203 2
                'path' => $path,
204 2
                'subject' => $this->get_help_title($filename_parts[0], $component),
205 2
                'lang' => $filename_parts[1],
206
            ];
207
        }
208
209 2
        return $files;
210
    }
211
212 3
    private function read_component_handlers($component)
213
    {
214 3
        $data = [];
215
216
        // TODO: We're using "private" members here, better expose them through a method
217 3
        $handler = midcom::get()->componentloader->get_interface_class($component);
218 3
        $request =& $handler->_context_data[midcom_core_context::get()->id]['handler'];
219 3
        if (!isset($request->_request_switch)) {
220
            // No request switch available, skip loading it
221 3
            return $data;
222
        }
223
224
        foreach ($request->_request_switch as $request_handler_id => $request_data) {
225
            if (substr($request_handler_id, 0, 12) == '____ais-help') {
226
                // Skip self
227
                continue;
228
            }
229
230
            $data[$request_handler_id] = [];
231
232
            // Build the dynamic_loadable URI, starting from topic path
233
            $data[$request_handler_id]['route'] = str_replace(midcom_connection::get_url('prefix'), '', midcom_core_context::get()->get_key(MIDCOM_CONTEXT_ANCHORPREFIX));
234
            // Add fixed arguments
235
            $data[$request_handler_id]['route'] .= implode('/', $request_data['fixed_args']) . '/';
236
            // Add variable_arguments
237
            $i = 0;
238
            while ($i < $request_data['variable_args']) {
239
                $data[$request_handler_id]['route'] .= '{$args[' . $i . ']}/';
240
                $i++;
241
            }
242
243
            if (is_array($request_data['handler'])) {
244
                $data[$request_handler_id]['controller'] = $request_data['handler'][0];
245
246
                if (is_object($data[$request_handler_id]['controller'])) {
247
                    $data[$request_handler_id]['controller'] = get_class($data[$request_handler_id]['controller']);
248
                }
249
250
                $data[$request_handler_id]['action'] = $request_data['handler'][1];
251
            }
252
253
            if (self::generate_file_path('handlers_' . $request_handler_id, $component)) {
254
                $data[$request_handler_id]['info'] = $this->get_help_contents('handlers_' . $request_handler_id, $component);
255
                $data[$request_handler_id]['handler_help_url'] = 'handlers_' . $request_handler_id;
256
            }
257
        }
258
259
        return $data;
260
    }
261
262 3
    private function read_url_methods($component)
263
    {
264 3
        $data = [];
265
266 3
        $exec_path = midcom::get()->componentloader->path_to_snippetpath($component) . '/exec/';
267 3
        if (   !is_dir($exec_path)
268 3
            || !is_readable($exec_path)) {
269
            // Directory not accessible, skip loading it
270 1
            return $data;
271
        }
272
273 2
        foreach (glob($exec_path . '/*.php', GLOB_NOSORT) as $path) {
274 2
            $file = basename($path);
275 2
            $data[$file] = [];
276
277 2
            $info_id = "urlmethod_" . str_replace('.php', '', $file);
278
279 2
            $data[$file]['url'] = '/midcom-exec-' . $component . '/' . $file;
280 2
            $data[$file]['description'] = $this->get_help_contents($info_id, $component);
281
282 2
            if (self::generate_file_path($info_id, $component)) {
283 2
                $data[$file]['handler_help_url'] = $info_id;
284
            }
285
        }
286
287 2
        return $data;
288
    }
289
290
    private function read_schema_properties()
291
    {
292
        foreach (array_keys($this->_request_data['mgdschemas']) as $mgdschema_class) {
293
            $mrp = new midgard_reflection_property($mgdschema_class);
294
            $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

294
            $class_props = connection::get_em()->getClassMetadata($mgdschema_class)->/** @scrutinizer ignore-call */ get_schema_properties();
Loading history...
295
296
            unset($class_props['metadata']);
297
            $default_properties = [];
298
            $additional_properties = [];
299
300
            foreach ($class_props as $prop) {
301
                switch ($prop) {
302
                    case 'action':
303
                        // Midgard-internal properties, skip
304
                        break;
305
                    case 'guid':
306
                    case 'id':
307
                        $default_properties[$prop] = $this->_get_property_data($mrp, $prop);
308
                        break;
309
                    default:
310
                        $additional_properties[$prop] = $this->_get_property_data($mrp, $prop);
311
                        break;
312
                }
313
            }
314
            ksort($default_properties);
315
            ksort($additional_properties);
316
317
            $this->_request_data['properties'][$mgdschema_class] = array_merge($default_properties, $additional_properties);
318
        }
319
    }
320
321
    private function _get_property_data(midgard_reflection_property $mrp, $prop)
322
    {
323
        return [
324
            'value' => $mrp->description($prop),
325
            'link' => $mrp->is_link($prop),
326
            'link_name' => $mrp->get_link_name($prop),
327
            'link_target' => $mrp->get_link_target($prop),
328
            'midgard_type' => $this->mgdtypes[$mrp->get_midgard_type($prop)]
329
        ];
330
    }
331
332
    private function _load_component_data($name)
333
    {
334
        $component_array = [];
335
        $component_array['name'] = $name;
336
        $component_array['title'] = midcom::get()->i18n->get_string($name, $name);
337
        $component_array['icon'] = midcom::get()->componentloader->get_component_icon($name);
338
339
        if (isset(midcom::get()->componentloader->manifests[$name])) {
340
            $manifest = midcom::get()->componentloader->manifests[$name];
341
            $component_array['purecode'] = $manifest->purecode;
342
            $component_array['description'] = $manifest->description;
343
        }
344
        return $component_array;
345
    }
346
347
    private function _list_components()
348
    {
349
        $this->_request_data['components'] = [];
350
        $this->_request_data['libraries'] = [];
351
352
        foreach (midcom::get()->componentloader->manifests as $name => $manifest) {
353
            $type = ($manifest->purecode) ? 'libraries' : 'components';
354
355
            $component_array = $this->_load_component_data($name);
356
357
            $this->_request_data[$type][$name] = $component_array;
358
        }
359
360
        asort($this->_request_data['components']);
361
        asort($this->_request_data['libraries']);
362
    }
363
364
    private function _prepare_breadcrumb($handler_id)
365
    {
366
        $this->add_breadcrumb("__ais/help/", $this->_l10n->get('midcom.admin.help'));
367
368
        if (   $handler_id == '____ais-help-help'
369
            || $handler_id == '____ais-help-component') {
370
            $this->add_breadcrumb(
371
                "__ais/help/{$this->_request_data['component']}/",
372
                sprintf($this->_l10n->get('help for %s'), midcom::get()->i18n->get_string($this->_request_data['component'], $this->_request_data['component']))
373
            );
374
        }
375
376
        if ($handler_id == '____ais-help-help') {
377
            if (   $this->_request_data['help_id'] == 'handlers'
378
                || $this->_request_data['help_id'] == 'urlmethods'
379
                || $this->_request_data['help_id'] == 'mgdschemas') {
380
                $this->add_breadcrumb(
381
                    "__ais/help/{$this->_request_data['component']}/{$this->_request_data['help_id']}",
382
                    $this->_l10n->get($this->_request_data['help_id'])
383
                );
384
            } else {
385
                $this->add_breadcrumb(
386
                    "__ais/help/{$this->_request_data['component']}/{$this->_request_data['help_id']}",
387
                    $this->get_help_title($this->_request_data['help_id'], $this->_request_data['component'])
388
                );
389
            }
390
        }
391
    }
392
393
    /**
394
     * @param mixed $handler_id The ID of the handler.
395
     * @param array $args The argument list.
396
     * @param array &$data The local request data.
397
     */
398
    public function _handler_welcome($handler_id, array $args, array &$data)
399
    {
400
        midcom::get()->auth->require_valid_user();
401
402
        $data['view_title'] = $this->_l10n->get($this->_component);
403
        midcom::get()->head->set_pagetitle($data['view_title']);
404
405
        $this->_list_components();
406
407
        $this->_prepare_breadcrumb($handler_id);
408
    }
409
410
    /**
411
     * Shows the help system main screen
412
     *
413
     * @param mixed $handler_id The ID of the handler.
414
     * @param array &$data The local request data.
415
     */
416
    public function _show_welcome($handler_id, array &$data)
417
    {
418
        midcom_show_style('midcom_admin_help_header');
419
        $list_types = ['components', 'libraries'];
420
421
        foreach ($list_types as $list_type) {
422
            $data['list_type'] = $list_type;
423
            midcom_show_style('midcom_admin_help_list_header');
424
            foreach ($data[$list_type] as $component_data) {
425
                $data['component_data'] = $component_data;
426
                midcom_show_style('midcom_admin_help_list_item');
427
            }
428
            midcom_show_style('midcom_admin_help_list_footer');
429
        }
430
431
        midcom_show_style('midcom_admin_help_footer');
432
    }
433
434
    /**
435
     * @param mixed $handler_id The ID of the handler.
436
     * @param array $args The argument list.
437
     * @param array &$data The local request data.
438
     */
439
    public function _handler_component($handler_id, array $args, array &$data)
440
    {
441
        midcom::get()->auth->require_valid_user();
442
443
        $data['component'] = $args[0];
444
445
        if (!midcom::get()->componentloader->is_installed($data['component'])) {
446
            throw new midcom_error_notfound("Component {$data['component']} is not installed.");
447
        }
448
449
        if ($data['component'] != 'midcom') {
450
            midcom::get()->componentloader->load($data['component']);
451
        }
452
453
        $data['view_title'] = sprintf($this->_l10n->get('help for %s'), $this->_i18n->get_string($data['component'], $data['component']));
454
        midcom::get()->head->set_pagetitle($data['view_title']);
455
456
        $data['help_files'] = $this->list_files($data['component']);
457
        $data['html'] = $this->get_help_contents('index', $data['component']);
458
        $this->_prepare_breadcrumb($handler_id);
459
    }
460
461
    /**
462
     * Shows the component help ToC.
463
     *
464
     * @param mixed $handler_id The ID of the handler.
465
     * @param array &$data The local request data.
466
     */
467
    public function _show_component($handler_id, array &$data)
468
    {
469
        midcom_show_style('midcom_admin_help_header');
470
471
        midcom_show_style('midcom_admin_help_show');
472
        midcom_show_style('midcom_admin_help_component');
473
474
        midcom_show_style('midcom_admin_help_footer');
475
    }
476
477
    /**
478
     * @param mixed $handler_id The ID of the handler.
479
     * @param array $args The argument list.
480
     * @param array &$data The local request data.
481
     */
482
    public function _handler_help($handler_id, array $args, array &$data)
483
    {
484
        midcom::get()->auth->require_valid_user();
485
486
        $data['help_id'] = $args[1];
487
        $data['component'] = $args[0];
488
        if (!midcom::get()->componentloader->is_installed($data['component'])) {
489
            throw new midcom_error_notfound("Component {$data['component']} is not installed.");
490
        }
491
492
        if ($data['component'] != 'midcom') {
493
            midcom::get()->componentloader->load($data['component']);
494
        }
495
496
        $data['help_files'] = $this->list_files($data['component']);
497
498
        if ($data['help_id'] == 'mgdschemas') {
499
            $this->read_schema_properties();
500
        }
501
        $data['html'] = $this->get_help_contents($data['help_id'], $data['component']);
502
503
        // Table of contents navi
504
        $data['view_title'] = sprintf(
505
            $this->_l10n->get('help for %s in %s'),
506
            $this->get_help_title($data['help_id'], $data['component']),
507
            $this->_i18n->get_string($data['component'], $data['component'])
508
        );
509
        midcom::get()->head->set_pagetitle($data['view_title']);
510
        $this->_prepare_breadcrumb($handler_id);
511
    }
512
513
    /**
514
     * Shows the help page.
515
     *
516
     * @param mixed $handler_id The ID of the handler.
517
     * @param array &$data The local request data.
518
     */
519
    public function _show_help($handler_id, array &$data)
520
    {
521
        midcom_show_style('midcom_admin_help_header');
522
        switch ($this->_request_data['help_id']) {
523
            case 'handlers':
524
                midcom_show_style('midcom_admin_help_handlers');
525
                break;
526
            case 'mgdschemas':
527
                midcom_show_style('midcom_admin_help_show');
528
                midcom_show_style('midcom_admin_help_mgdschemas');
529
                break;
530
            case 'urlmethods':
531
                midcom_show_style('midcom_admin_help_show');
532
                midcom_show_style('midcom_admin_help_urlmethods');
533
                break;
534
            default:
535
                midcom_show_style('midcom_admin_help_show');
536
537
                if (!$this->_request_data['html']) {
538
                    $this->_request_data['html'] = $this->get_help_contents('notfound', 'midcom.admin.help');
539
                    midcom_show_style('midcom_admin_help_show');
540
                    midcom_show_style('midcom_admin_help_component');
541
                }
542
        }
543
        midcom_show_style('midcom_admin_help_footer');
544
    }
545
}
546