Issues (806)

src/midcom/routing/plugin.php (1 issue)

1
<?php
2
/**
3
 * @package midcom.routing
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\routing;
10
11
use midcom;
12
use midcom_admin_folder_management;
13
use midcom_admin_rcs_plugin;
14
use midcom_helper_imagepopup_viewer;
15
use midcom_admin_help_help;
16
use midgard_admin_asgard_plugin;
17
use midcom_error;
18
19
/**
20
 * <b>Plugin Interface</b>
21
 *
22
 * This class includes a plugin system which can be used to flexibly enhance the
23
 * functionality of the request classes by external sources. Your component does
24
 * not have to worry about this, you just have to provide a way to register plugins
25
 * to site authors.
26
 *
27
 * Plugins always come in "packages", which are assigned to a namespace. The namespace
28
 * is used to separate various plugins from each other, it is prepended before any
29
 * URL. Within a plugin you can register one or more handler classes. Each of this
30
 * classes can of course define more than one request handler.
31
 *
32
 * A plugin class must be a descendant of midcom_baseclasses_components_handler or at
33
 * least support its full interface.
34
 *
35
 * As outlined above, plugins are managed in a two-level hierarchy. First, there is
36
 * the plugin identifier, second the class identifier. When registering a plugin,
37
 * these two are specified. The request handlers obtained by the above callback are
38
 * automatically expanded to match the plugin namespace.
39
 *
40
 * <i>Example: Plugin registration</i>
41
 *
42
 * <code>
43
 * $this->register_plugin_namespace(
44
 *     '__ais', [
45
 *         'folder' => [
46
 *             'class' => 'midcom_admin_folder_management',
47
 *             'config' => null,
48
 *         ],
49
 *     ]
50
 * );
51
 * </code>
52
 *
53
 * The first argument of this call identifies the plugin namespace, the second
54
 * the list of classes associated with this plugin. Each class gets its own
55
 * identifier. The namespace and plugin identifier is used to construct the
56
 * final plugin URL: {$anchor_prefix}/{$namespace}/{$plugin_identifier}/...
57
 * This gives fully unique URL namespaces to all registered plugins.
58
 *
59
 * Plugin handlers always last in queue, so they won't override component handlers.
60
 * Their name is prefixed with __{$namespace}-{$plugin_identifier} to ensure
61
 * uniqueness.
62
 *
63
 * Each entry has these options:
64
 *
65
 * - class: The name of the class to use
66
 * - config: This is an optional configuration argument, allows for customization.
67
 *   May be omitted, in which case it defaults to null.
68
 *
69
 * Once a plugin has been successfully initialized, its configuration is put
70
 * into the request data:
71
 *
72
 * - mixed plugin_config: The configuration passed to the plugin as outlined
73
 *   above.
74
 * - string plugin_name: The name of the plugin as defined in its config
75
 *
76
 * @package midcom.routing
77
 */
78
class plugin
79
{
80
    /**
81
     * This variable keeps track of the registered plugin namespaces. It maps namespace
82
     * identifiers against plugin config lists.
83
     *
84
     * You have to use the viewer's register_plugin_namespace() member function during the
85
     * _on_initialize event to register plugin namespaces.
86
     */
87
    private static array $registry = [];
88
89
    /**
90
     * Create a new plugin namespace and map the configuration to it.
91
     * It allows flexible, user-configurable extension of components.
92
     *
93
     * Only very basic testing is done to keep runtime up, currently the system only
94
     * checks to prevent duplicate namespace registrations. In such a case,
95
     * midcom_error will be thrown.
96
     *
97
     * @param string $namespace The plugin namespace, checked against $args[0] during
98
     *     URL parsing.
99
     * @param array $config The configuration of the plugin namespace as outlined in
100
     *     the class introduction
101
     */
102 6
    public static function register_namespace(string $namespace, array $config)
103
    {
104 6
        self::init();
105 6
        if (array_key_exists($namespace, self::$registry)) {
106 4
            throw new midcom_error("Tried to register the plugin namespace {$namespace}, but it is already registered.");
107
        }
108 2
        self::$registry[$namespace] = $config;
109
    }
110
111 291
    public static function get_config(string $namespace, string $name) : ?array
112
    {
113 291
        self::init();
114 291
        if (empty(self::$registry[$namespace][$name])) {
115 203
            return null;
116
        }
117 88
        if (empty(self::$registry[$namespace][$name]['class']) || !class_exists(self::$registry[$namespace][$name]['class'])) {
118
            throw new midcom_error("Failed to load the plugin {$namespace}/{$name}, implementation class not available.");
119
        }
120 88
        return self::$registry[$namespace][$name];
121
    }
122
123
    /**
124
     * Register the plugin namespaces provided from MidCOM core.
125
     */
126 291
    private static function init()
127
    {
128 291
        if (self::$registry) {
0 ignored issues
show
Bug Best Practice introduced by
The expression self::registry of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
129 291
            return;
130
        }
131 1
        self::$registry = [
132 1
            '__ais' => [
133 1
                'folder' => [
134 1
                    'class' => midcom_admin_folder_management::class,
135 1
                ],
136 1
                'rcs' => [
137 1
                    'class' => midcom_admin_rcs_plugin::class,
138 1
                ],
139 1
                'imagepopup' => [
140 1
                    'class' => midcom_helper_imagepopup_viewer::class,
141 1
                ],
142 1
                'help' => [
143 1
                    'class' => midcom_admin_help_help::class,
144 1
                ],
145 1
            ]
146 1
        ];
147
148
        // Load plugins registered via component manifests
149 1
        $plugins = midcom::get()->componentloader->get_all_manifest_customdata('request_handler_plugin');
150 1
        $plugins['asgard'] = [
151 1
            'class' => midgard_admin_asgard_plugin::class,
152 1
        ];
153
154 1
        $customdata = midcom::get()->componentloader->get_all_manifest_customdata('asgard_plugin');
155 1
        foreach ($customdata as $component => $plugin_config) {
156 1
            $plugins["asgard_{$component}"] = $plugin_config;
157
        }
158
159 1
        self::register_namespace('__mfa', $plugins);
160
    }
161
}