Completed
Push — master ( 9cf8bc...8e87e9 )
by Thierry
01:35
created

Manager::getPlugins()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Manager.php - Jaxon plugin manager
5
 *
6
 * Register Jaxon plugins, generate corresponding code, handle request
7
 * and redirect them to the right plugin.
8
 *
9
 * @package jaxon-core
10
 * @author Jared White
11
 * @author J. Max Wilson
12
 * @author Joseph Woolley
13
 * @author Steffen Konerow
14
 * @author Thierry Feuzeu <[email protected]>
15
 * @copyright Copyright (c) 2005-2007 by Jared White & J. Max Wilson
16
 * @copyright Copyright (c) 2008-2010 by Joseph Woolley, Steffen Konerow, Jared White  & J. Max Wilson
17
 * @copyright 2016 Thierry Feuzeu <[email protected]>
18
 * @license https://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
19
 * @link https://github.com/jaxon-php/jaxon-core
20
 */
21
22
namespace Jaxon\Plugin;
23
24
use Jaxon\Jaxon;
25
use Jaxon\Plugin\Package;
26
use Jaxon\Request\Support\CallableRepository;
27
use Jaxon\Request\Plugin\CallableClass;
28
use Jaxon\Request\Plugin\CallableDir;
29
use Jaxon\Request\Plugin\CallableFunction;
30
use Jaxon\Request\Plugin\FileUpload;
31
use Jaxon\Response\Plugin\JQuery as JQueryPlugin;
32
use Jaxon\Utils\Config\Config;
33
34
use Closure;
35
36
class Manager
37
{
38
    use \Jaxon\Features\Manager;
39
    use \Jaxon\Features\Config;
40
    use \Jaxon\Features\Event;
41
    use \Jaxon\Features\Translator;
42
43
    /**
44
     * All plugins, indexed by priority
45
     *
46
     * @var array
47
     */
48
    private $aPlugins = [];
49
50
    /**
51
     * Request plugins, indexed by name
52
     *
53
     * @var array
54
     */
55
    private $aRequestPlugins = [];
56
57
    /**
58
     * Response plugins, indexed by name
59
     *
60
     * @var array
61
     */
62
    private $aResponsePlugins = [];
63
64
    /**
65
     * An array of package names
66
     *
67
     * @var array
68
     */
69
    private $aPackages = [];
70
71
    /**
72
     * Get the request and response plugins
73
     *
74
     * @return array
75
     */
76
    public function getPlugins()
77
    {
78
        return $this->aPlugins;
79
    }
80
81
    /**
82
     * Get the request plugins
83
     *
84
     * @return array
85
     */
86
    public function getRequestPlugins()
87
    {
88
        return $this->aRequestPlugins;
89
    }
90
91
    /**
92
     * Get the response plugins
93
     *
94
     * @return array
95
     */
96
    public function getResponsePlugins()
97
    {
98
        return $this->aResponsePlugins;
99
    }
100
101
    /**
102
     * Get the package plugins
103
     *
104
     * @return array
105
     */
106
    public function getPackages()
107
    {
108
        return $this->aPackages;
109
    }
110
111
    /**
112
     * Inserts an entry into an array given the specified priority number
113
     *
114
     * If a plugin already exists with the given priority, the priority is automatically incremented until a free spot is found.
115
     * The plugin is then inserted into the empty spot in the array.
116
     *
117
     * @param Plugin         $xPlugin               An instance of a plugin
118
     * @param integer        $nPriority             The desired priority, used to order the plugins
119
     *
120
     * @return void
121
     */
122
    private function setPluginPriority(Plugin $xPlugin, $nPriority)
123
    {
124
        while (isset($this->aPlugins[$nPriority]))
125
        {
126
            $nPriority++;
127
        }
128
        $this->aPlugins[$nPriority] = $xPlugin;
129
        // Sort the array by ascending keys
130
        ksort($this->aPlugins);
131
    }
132
133
    /**
134
     * Register a plugin
135
     *
136
     * Below is a table for priorities and their description:
137
     * - 0 thru 999: Plugins that are part of or extensions to the jaxon core
138
     * - 1000 thru 8999: User created plugins, typically, these plugins don't care about order
139
     * - 9000 thru 9999: Plugins that generally need to be last or near the end of the plugin list
140
     *
141
     * @param Plugin         $xPlugin               An instance of a plugin
142
     * @param integer        $nPriority             The plugin priority, used to order the plugins
143
     *
144
     * @return void
145
     */
146
    public function registerPlugin(Plugin $xPlugin, $nPriority = 1000)
147
    {
148
        $bIsAlert = ($xPlugin instanceof \Jaxon\Contracts\Dialogs\Alert);
149
        $bIsConfirm = ($xPlugin instanceof \Jaxon\Contracts\Dialogs\Confirm);
150
        $bIsListener = ($xPlugin instanceof \Jaxon\Contracts\Event\Listener);
151
        if($xPlugin instanceof Request)
152
        {
153
            // The name of a request plugin is used as key in the plugin table
154
            $this->aRequestPlugins[$xPlugin->getName()] = $xPlugin;
155
        }
156
        elseif($xPlugin instanceof Response)
157
        {
158
            // The name of a response plugin is used as key in the plugin table
159
            $this->aResponsePlugins[$xPlugin->getName()] = $xPlugin;
160
        }
161
        elseif(!$bIsConfirm && !$bIsAlert && !$bIsListener)
162
        {
163
            $sErrorMessage = $this->trans('errors.register.invalid', ['name' => get_class($xPlugin)]);
164
            throw new \Jaxon\Exception\Error($sErrorMessage);
165
        }
166
        // This plugin implements the Alert interface
167
        if($bIsAlert)
168
        {
169
            jaxon()->dialog()->setAlert($xPlugin);
170
        }
171
        // This plugin implements the Confirm interface
172
        if($bIsConfirm)
173
        {
174
            jaxon()->dialog()->setConfirm($xPlugin);
175
        }
176
        // Register the plugin as an event listener
177
        if($bIsListener)
178
        {
179
            $this->addEventListener($xPlugin);
180
        }
181
182
        $this->setPluginPriority($xPlugin, $nPriority);
183
    }
184
185
    /**
186
     * Register a package
187
     *
188
     * @param string         $sPackageClass         The package class name
189
     * @param Closure        $xClosure              A closure to create package instance
190
     *
191
     * @return void
192
     */
193
    public function registerPackage(string $sPackageClass, Closure $xClosure)
194
    {
195
        $this->aPackages[] = $sPackageClass;
196
        jaxon()->di()->set($sPackageClass, $xClosure);
197
    }
198
199
    /**
200
     * Register a function, event or callable class
201
     *
202
     * Call the request plugin with the $sType defined as name.
203
     *
204
     * @param string        $sType          The type of request handler being registered
205
     * @param string        $sCallable      The callable entity being registered
206
     * @param array|string  $aOptions       The associated options
207
     *
208
     * @return mixed
209
     */
210
    public function registerCallable($sType, $sCallable, $aOptions = [])
211
    {
212
        if(!key_exists($sType, $this->aRequestPlugins))
213
        {
214
            throw new \Jaxon\Exception\Error($this->trans('errors.register.plugin', ['name' => $sType]));
215
        }
216
217
        $xPlugin = $this->aRequestPlugins[$sType];
218
        return $xPlugin->register($sType, $sCallable, $aOptions);
219
    }
220
221
    /**
222
     * Register callable from a section of the config
223
     *
224
     * @param Config        $xAppConfig        The config options
225
     * @param string        $sSection          The config section name
226
     * @param string        $sCallableType     The type of callable to register
227
     *
228
     * @return void
229
     */
230
    private function registerCallablesFromConfig($xAppConfig, $sSection, $sCallableType)
231
    {
232
        $aConfig = $xAppConfig->getOption($sSection, []);
233
        foreach($aConfig as $xKey => $xValue)
234
        {
235
            if(is_integer($xKey) && is_string($xValue))
236
            {
237
                // Register a function without options
238
                $this->registerCallable($sCallableType, $xValue);
239
            }
240
            elseif(is_string($xKey) && (is_array($xValue) || is_string($xValue)))
241
            {
242
                // Register a function with options
243
                $this->registerCallable($sCallableType, $xKey, $xValue);
244
            }
245
            else
246
            {
247
                continue;
248
                // Todo: throw an exception
249
            }
250
        }
251
    }
252
253
    /**
254
     * Read and set Jaxon options from a JSON config file
255
     *
256
     * @param Config        $xAppConfig        The config options
257
     *
258
     * @return void
259
     */
260
    public function registerFromConfig($xAppConfig)
261
    {
262
        // Register functions
263
        $this->registerCallablesFromConfig($xAppConfig, 'functions', Jaxon::CALLABLE_FUNCTION);
264
265
        // Register classes
266
        $this->registerCallablesFromConfig($xAppConfig, 'classes', Jaxon::CALLABLE_CLASS);
267
268
        // Register directories
269
        $this->registerCallablesFromConfig($xAppConfig, 'directories', Jaxon::CALLABLE_DIR);
270
    }
271
272
273
    /**
274
     * Find the specified response plugin by name and return a reference to it if one exists
275
     *
276
     * @param string        $sName                The name of the plugin
277
     *
278
     * @return \Jaxon\Plugin\Response
279
     */
280
    public function getResponsePlugin($sName)
281
    {
282
        if(array_key_exists($sName, $this->aResponsePlugins))
283
        {
284
            return $this->aResponsePlugins[$sName];
285
        }
286
        return null;
287
    }
288
289
    /**
290
     * Find the specified request plugin by name and return a reference to it if one exists
291
     *
292
     * @param string        $sName                The name of the plugin
293
     *
294
     * @return \Jaxon\Plugin\Request
295
     */
296
    public function getRequestPlugin($sName)
297
    {
298
        if(array_key_exists($sName, $this->aRequestPlugins))
299
        {
300
            return $this->aRequestPlugins[$sName];
301
        }
302
        return null;
303
    }
304
305
    /**
306
     * Register the Jaxon request plugins
307
     *
308
     * @return void
309
     */
310
    public function registerRequestPlugins()
311
    {
312
        $di = jaxon()->di();
313
        $this->registerPlugin($di->get(CallableClass::class), 101);
314
        $this->registerPlugin($di->get(CallableDir::class), 102);
315
        $this->registerPlugin($di->get(CallableFunction::class), 103);
316
        $this->registerPlugin($di->get(FileUpload::class), 104);
317
    }
318
319
    /**
320
     * Register the Jaxon response plugins
321
     *
322
     * @return void
323
     */
324
    public function registerResponsePlugins()
325
    {
326
        $di = jaxon()->di();
327
        // Register an instance of the JQuery plugin
328
        $this->registerPlugin($di->get(JQueryPlugin::class), 700);
329
    }
330
}
331