Zend Framework Source Code Snippets

Plugger - A Plugin Manager

Bookmark and Share
1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
2526
27
28
29
3031
32
33
34
3536
37
38
39
4041
42
43
44
4546
47
48
49
5051
52
53
TUTORIAL
Usage in bootstrap with setters:
 
// Include PHP file...
// Plugin Manager.$plugger = new Bolzz_Zend_PluggerPlugin();
 
// This instance is used by plugger to load
// a plugin on demand.
$oLoaderPlugins = new Zend_Loader_PluginLoader(); 
// Add all prefix-path-mappings. That's all what plugger needs.
$oLoaderPlugins->addPrefixPath('Tools_Plugin', '../application/modules/tools/plugins/'); // EXAMPLE!
 
// Now, add the PluginLoader instance to the plugger.$plugger->setLoader($oLoaderPlugins);
 
// Set "default plugins". These plugins will be loaded on each request.
// That's the ZF standard.
$plugger->addDefaults('ToolBar'); 
// Add some arguments for plugin's constructor, if needed.
// Plugger will pass these 3 args in the same order and data type:
// Tools_Plugin_ToolBar - a boolean, an integer and a num array.
$plugger->addArgs('ToolBar', true, 1, array('val1', 'val2')); 
// Above, last two calls can be done by one:
// $plugger->addDefaults('ToolBar', true, 1, array('val1', 'val2'));
 
// Now, first example why it's good to use plugger.// Tools_Plugin_UserToolBar is only needed if a user wants to edit his options.
// Therefor, a user calls the URL http://www.mydomain.com/settings/someUsername.
// Now, plugger detects "settings" in the URL and loads all plugins,
// which were registered to this request.
$plugger->addSpecials('settings', 'UserToolBar', true, 1, array('val1', 'val2'));// Tools_Plugin_AdminToolBar is only needed/loaded in an admin panel.
$plugger->addSpecials('admin', 'AdminToolBar');
 
// plugger handles each request by 3 steps to get known which AREA (settings, admins, etc.)
// should be loaded. This process can be customized. 
// Option 1: Searches in URL for a module name and sets it as AREA.
// $plugger->setMode('module');
// Option 2: If the regex matches the URL "settings" is been set as AREA.
$plugger->setRegex('settings', '^settings/[a-z]*');// Option 3: Searches in URL request string for "settings" and on success "settings" is being set as AREA.
// $plugger->setNeedle('settings', 'settings');
 
// Now, plugger is working.
$plugger->run(); 
 
// Note: plugger could throw an exception Bolzz_Exception_Plugger.
1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
2526
27
28
29
<?php
/**
 * Bolzz Library
 * http://www.bolzz.com - BOLZZ | IT Entwicklung
 * * LICENSE
 * 100% Freeware and Open Source
 *
 * @package Bolzz
 * @subpackage Zend * @category Plugins
 * @filesource
 */
 
require_once '../libs/Bolzz_Library/Bolzz/Exception/Plugger.php'; 
/**
 * Plugger (Plugin Manager)
 * Manages all plugins and loads them only if they are really needed.
 * On each request the Plugger registers plugins, if they are linked * to that request and only then.
 *
 * @example Quickstart_PluggerPlugin.php
 * @tutorial http://www.zfforum.de/showpost.php?p=29802&postcount=21
 * @version Version 1.4.2 */
final class Bolzz_Zend_PluggerPlugin extends Zend_Controller_Plugin_Abstract
{
// data elements ###########################################################
1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
2526
27
28
29
3031
32
33
34
3536
37
38
39
4041
42
43
44
4546
47
48
49
5051
52
53
54
5556
57
58
59
6061
62
63
64
6566
67
68
69
7071
72
73
74
7576
77
78
79
8081
82
83
84
8586
87
88
89
9091
92
93
94
9596
97
98
99
100101
102
103
104
105106
107
108
109
110111
112
113
114
115116
117
118
119
120121
122
123
124
125126
127
128
129
130131
132
133
134
135136
137
138
139
140141
142
143
144
145146
147
148
149
150151
// MUST ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        
        /**
         * Count of members which has to be initialized to use/run Plugger.
         */        const MEMBERS_TO_INIT = 2;
        
        /**
         * Counter flag.
         *         * @var int Default: count of members to initialize.
         */
        private $_initialized = self::MEMBERS_TO_INIT;
        
        /**         * List of initialized members. Setter method as element.
         *
         * @var array Num Array.
         */
        private $_initList = array();        
        /**
         * Mode
         *
         * @var bool         */
        private $_run = false;
        
        /**
         * Base URL set by front controller.         * @var string On init() $baseUrl is set on $this->front->getBaseUrl().
         */
        private $_baseUrl = '';
        
        /**         * Parameters in URL.
         * If $baseUrl is set, it will be filtered from $urlParams automatically by the _loadAreaBy*()-methods.
         * @var string On init() $urlParams is set on $_SERVER['REQUEST_URI'].
         */
        private $_urlParams = '';        
        /**
         * Name of Module, Controller, Action or whatever you like. If empty tried to set by loadArea().
         * This variable represents current website area to register plugins for.
         * Plugins from $pluginsAreas will be loaded by the Manager, if their associative key is equal with $area.         * <code>
         * <?php
         * // Define plugins to load in specified areas.
         * $pluginsAreas = array(
         * 'areaFoo' => array('Plugin_Class1', 'Plugin_Class2'), // Area 1 ------- * Plugin          * 'areaBar' => 'Plugin_Class3', // Area 1 ------- 1 Plugin
         * 'areaFooBar' => array('Plugin_Class4')); // Area 1 ------- 1 Plugin
         * 
         * // if $area === 'areaFoo'
         * //    Plugin_Class1 and Plugin_Class2 will be registered.         * //    Plugin_Class3 and Plugin_Class4 will NOT be registered.
         * </code>
         * @var string
         */
        private $_area = ''; 
        /**
         * If you set $areaMode your project has to use a conventional modular directory struture, like Zend does recommend.
         * If $areaRegex or $areaNeedle are set, they will be checked first.
         * @link http://framework.zend.com/manual/en/zend.controller.modular.html 7.11. Using a Conventional Modular Directory Structure         * @var string 'module' | 'controller' | 'action' | ''. By Default: 'module'.
         */
        private $_areaMode = 'module';
        
        /**         * If $areaRegex is set, then Regex will be checked against the URL before $areaMode but after $areaNeedle.
         * Haystack is URL string.
         * <code>
         * <?php
         * array('area name' => 'REGEX');         * </code>       
         * @var array Associative Array.
         */
        private $_areaRegex = array();
         /**
         * If $areaNeedle is set, then your Regex will be checked against the URL before $areaMode and $areaRegex.
         * Haystack is URL string.
         * <code>
         * <?php         * array('area name' => 'needle');
         * </code>
         * @var array Associative Array.
         */
        private $_areaNeedle = array();        
        /**
         * Management for prefixes and paths of plugin classes.
         * @var object Zend_Loader_PluginLoader_Interface
         */        private $_loader = null;
        
        /**
         * Default plugins to load.
         * <code>         * <?php
         * $pluginsDefaults = array('Plugin_Class1', 'Plugin_Class2', 'Plugin_Class3');
         * </code>
         * @var array Numeric Array
         */        private $_pluginsDefaults = array();
 
        /**
         * Plugins to load in specified areas.
         * <code>         * <?php
         * // Exammple 1: In each area only one plugin will be loaded.
         * $pluginsAreas = array(
         * 'areaFoo' => 'Plugin_Class1', 
         * 'areaBar' => 'Plugin_Class2',          * 'areaFooBar' => 'Plugin_Class3');
         * 
         * // Example 2: In area 'areaFoo' will be more than one plugin loaded.
         * $pluginsAreas = array(
         * 'areaFoo' => array('Plugin_Class1', 'Plugin_Class2'), // Area 1 ------- * Plugin          * 'areaBar' => 'Plugin_Class3', // Area 1 ------- 1 Plugin
         * 'areaFooBar' => array('Plugin_Class4')); // Area 1 ------- 1 Plugin
         * </code>
         * @var array Associative Array
         */        private $_pluginsAreas = array();
        
        /**
         * Arguments for constructors of plugins.
         * <code>         * <?php
         * // Example 1: One argument needed - Given as an string
         * $arguments = array('classname' => 'param1');
         * // Example 2: One argument needed - Given as an array
         * $arguments = array('classname' => array('param1'));         * // Example 3: Two or more arguments needed
         * $arguments = array('classname' => array('param1', 'param2'));
         * </code>
         *
         * @var array Assoziative [multiple] array.         */
        private $_arguments = array();
        
        /**
         * The Singleton Front Controller         * Will be set each time when create an object. Flag $_run does not care.
         * @var object Zend_Controller_Front
         */
        public $front = null;
 // element functions ########################################################
1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
2526
27
28
29
3031
32
33
34
3536
37
38
39
4041
42
43
44
4546
47
48
49
5051
52
53
54
5556
57
58
59
6061
62
63
64
6566
67
68
69
7071
72
73
74
7576
77
78
79
8081
82
83
84
8586
87
88
89
9091
92
93
94
9596
97
98
99
100101
102
103
104
105106
107
108
109
110111
112
113
114
115116
117
118
119
120121
122
123
124
125126
127
128
129
130131
132
133
134
135136
137
138
139
140141
142
143
144
145146
147
148
149
150151
152
153
154
155156
157
158
159
160161
162
163
164
165166
167
168
169
170171
172
173
174
175176
177
178
179
180181
182
183
184
185186
187
188
189
190191
192
193
194
195196
197
198
199
200201
202
203
204
205206
207
208
209
210211
212
213
214
215216
217
218
219
220221
222
223
224
225226
227
228
229
230231
232
233
234
235236
237
238
239
240241
242
243
244
245246
247
248
249
250251
252
253
254
255256
257
258
259
260261
262
263
264
265266
267
268
269
270271
272
273
274
275276
277
278
279
280281
282
283
284
285286
287
288
289
290291
292
293
294
295296
297
298
299
300301
302
303
304
305306
307
308
309
310311
312
313
314
315316
317
318
319
320321
322
323
324
325326
327
328
329
330331
332
333
334
335336
337
338
339
340341
342
343
344
345346
347
348
349
350351
352
353
354
355356
357
358
359
360361
362
363
364
365366
367
368
369
370371
372
373
374
375376
377
378
379
380381
382
383
384
385386
387
388
389
390391
392
393
394
395396
397
398
399
400401
402
403
404
405406
407
408
409
410411
412
413
414
415416
417
418
419
420421
422
423
424
425426
427
428
429
430431
432
433
434
435436
437
438
439
440441
442
443
444
445446
447
448
449
450451
452
453
454
455456
457
458
459
460461
462
463
464
465466
467
468
469
470471
472
473
474
475476
477
478
479
480481
482
483
484
485486
487
488
489
490491
492
493
494
495496
497
498
499
500501
502
503
504
505506
507
508
509
510511
512
513
514
515516
517
518
519
520521
522
523
524
525526
527
528
529
530531
532
533
534
535536
537
538
539
540541
542
543
544
545546
547
548
549
550551
552
553
554
555556
557
558
559
560561
562
563
564
565566
567
568
569
570571
572
573
574
575576
577
578
579
580581
582
583
584
585586
587
588
589
590591
592
593
594
595596
597
598
599
600601
602
603
604
605606
607
608
609
610611
612
613
614
615616
617
618
619
620621
622
623
624
625626
627
628
629
630631
632
633
634
635636
637
638
639
640641
642
643
644
645646
647
648
649
650651
652
653
654
655656
657
658
659
660661
662
663
664
665666
667
668
669
670671
672
673
674
675676
677
678
679
680681
682
683
684
685686
687
688
689
690691
692
693
694
695696
697
698
699
700701
702
703
704
705706
707
708
709
710711
712
713
714
715716
717
718
719
720721
722
723
724
725726
727
728
729
730731
732
733
734
735736
737
738
739
740741
742
743
744
745746
747
748
749
750751
752
753
754
755756
757
758
759
760761
762
763
764
765766
767
768
769
770771
772
773
774
775776
777
778
779
780781
782
783
784
785786
787
788
789
790791
792
793
794
795796
797
798
799
800801
802
803
804
805806
807
808
809
810811
812
813
814
815816
817
818
819
820821
822
823
824
825826
827
828
829
830831
832
833
834
835836
837
838
839
840841
842
843
844
845846
847
848
849
850851
852
853
854
855856
857
858
859
860861
862
863
864
865
// MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
        /**
         * Constructor Bolzz_Zend_PluggerPlugin
         *          * Initialize members and register plugins.
         * 
         * @throws Bolzz_Exception_Plugger Only when $_run is true.
         * @uses run()
         * @uses Zend_Controller_Front::getInstance()         * @param object $_loader Zend_Loader_PluginLoader_Interface. By Default: null.
         * @param array $_pluginsDefaults Load these plugins by default - array('Plugin_Name1', 'Plugin_Name2')
         * @param array $_pluginsAreas Load these plugins in specific areas - array('area' => 'Plugin_Name')
         * @param array $_arguments Arguments for constructors of plugins.
         * @param string $_area Current name of Module, Controller or Action. If empty (default), Plugger will set it.         * @param string $_areaMode Values: 'module' | 'controller' | 'action' | ''. By Default: 'module'.
         * @param array $_areaRegex Associative Array. Key is area which will be set if value (regex) matches in URL. Note: Regex must be set in brackets (REGEX).
         * @param array $_areaNeedle Associative Array. Key is area, which will be set if value (needle) found in URL.
         * @param bool $_run If true, constructor will try to run Plugger. Default: false.
         */        public function __construct($_loader = null, $_pluginsDefaults = array(), $_pluginsAreas = array(),
                                                                $_arguments = array(), $_area = '',
                                                                $_areaMode = 'module', $_areaRegex = array(), $_areaNeedle = array(),
                                                                $_run = false)
        {                $this->front = Zend_Controller_Front::getInstance();
 
                $this->_run = $_run;
                
                $this->_init($_loader, $_pluginsDefaults, $_pluginsAreas, $_arguments, $_area, $_areaMode, $_areaRegex, $_areaNeedle); 
                if (true === $this->_run) {
                        $this->run();
                }
        } 
// MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
        /**
         * Initialize members.         * 
         * Uses $_SERVER['REQUEST_URI'] to get all GET parameters to $_urlParams.
         * 
         * @usedby __construct()
         * @param object $_loader Zend_Loader_PluginLoader_Interface         * @param array $_pluginsDefaults
         * @param array $_pluginsAreas
         * @param array $_arguments
         * @param string $_area
         * @param string $_areaMode         * @param array $_areaRegex
         * @param array $_areaNeedle
         * @return void
         */
        private function _init($_loader, $_pluginsDefaults, $_pluginsAreas, $_arguments, $_area,                                                        $_areaMode,     $_areaRegex, $_areaNeedle)
        {
                if ($_loader instanceof Zend_Loader_PluginLoader_Interface) {
                        $this->setLoader($_loader);
                } 
                $this->setBaseUrl($this->front->getBaseUrl());
                $this->setUrlParams($_SERVER['REQUEST_URI']);
                $this->setDefaults($_pluginsDefaults);
                $this->setSpecials($_pluginsAreas);                $this->setArgs($_arguments);
                $this->setMode($_areaMode);
                $this->setRegex($_areaRegex);
                $this->setNeedle($_areaNeedle);
                 if (!empty($_area)) {
                        $this->setArea($_area);
                }
        }
 // MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
        /**
         * Register plugins for specific areas.
         *          * @todo exception handling
         * @usedby __construct()
         * @uses _runFactory()
         * @uses $_pluginsAreas
         * @uses $_area         * @return void
         */
        private function _registerSpecials()
        {
                // identify equal areas                switch ($this->_area) {
                        case 'default':
                        case 'index':
                                $areaTmp = array('default', 'index');
                                break;                        default:
                                $areaTmp[0] = $this->_area;
                                break;
                }
                 if (is_array($areaTmp)) {
                        $counts = count($areaTmp);
                } else {
                        $counts = 0;
                } 
                while ($counts > 0) {
                        $countsIndex = --$counts;
 
                        if (isset($areaTmp[$countsIndex])) {                                if (isset($this->_pluginsAreas[$areaTmp[$countsIndex]])) {
                                        $areaClasses = $this->_pluginsAreas[$areaTmp[$countsIndex]];
 
                                        if (!empty($areaClasses)) {
                                                if (is_array($areaClasses)) {                                                        foreach ($areaClasses as $key => $name) {
                                                                $this->_runFactory($name);
                                                        }
                                                } else {
                                                        $this->_runFactory($areaClasses);                                                }
                                        }
                                }
                        }
                }        }       
 
// MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
        /**         * Register plugins for all areas of application.
         * 
         * @todo exception handling
         * @usedby __construct()
         * @uses _runFactory()         * @uses $_pluginsDefaults
         * @return void
         */
        private function _registerDefaults()
        {                if (!empty($this->_pluginsDefaults)) {
                        foreach ($this->_pluginsDefaults as $key => $name) {
                                $this->_runFactory($name);
                        }
                }        }       
 
// MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
        /**         * Factory Method for Plugins. Create an object.
         * 
         * @todo throw Exception if could not instantiate class, because of missing arguments, etc.
         * @uses ReflectionClass
         * @param string $_sName Filename or Class name         * @param string $_sClassName Is definetly a class name
         * @return bool|object false or instance of $_sClassName
         */
        private function _factory($_sName, $_sClassName)
        {                if (isset($_sName) && array_key_exists($_sName, $this->_arguments)) {
                        $index = $_sName;
                } elseif (isset($_sClassName) && array_key_exists($_sClassName, $this->_arguments)) {
                        $index = $_sClassName;
                } else {                        $index = false;
                }
                
                if ($index !== false
                && isset($_sClassName)                && !empty($_sClassName)
                && is_string($_sClassName)) {
                        if (is_array($this->_arguments[$index])) {
                                // array - support constructors with more than one arguments.                   
                                 $refl = new ReflectionClass($_sClassName);
 
                                $obj = $refl->newInstanceArgs($this->_arguments[$index]);
                        } else { 
                                // string - only one argument given to constructor. 
                                $obj = new $_sClassName($this->_arguments[$index]);     
                        }
                } else {
                        if (isset($_sClassName)                        && !empty($_sClassName)
                        && is_string($_sClassName))
                                $obj = new $_sClassName();
                        else
                                $obj = null;                }
 
                return (!is_null($obj) && is_object($obj)) ? $obj : false;
        }
 // MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 
        /**
         * Run Factory Method for Plugins.
         *          * @throws Zend_Loader_PluginLoader_Exception
         * @throws Bolzz_Exception_Plugger
         * @uses _factory()
         * @uses $front
         * @uses $_loader         * @param string $_sName Filename or Class name
         * @return void
         */
        private function _runFactory($_sName)
        {                if (!is_object($this->_loader)
                || !($this->_loader instanceof Zend_Loader_PluginLoader_Interface)) {
                        include_once 'Zend/Loader/PluginLoader/Exception.php';
                        
                        throw new Zend_Loader_PluginLoader_Exception(__CLASS__                                . '::$_loader has to be an instance of Zend_Loader_PluginLoader_Interface. Currently given: '
                                . gettype($this->_loader));
                }
 
                // NOTE: If class can not be loaded by name here, an exception                // Zend_Loader_PluginLoader_Exception will be thrown.
                $this->_loader->load($_sName);
 
                if ($this->_loader->isLoaded($_sName)) {
                        $className = $this->_loader->getClassName($_sName);                }
 
                $plugin = $this->_factory($_sName, $className);
 
                if ($plugin !== false) {                        $this->front->registerPlugin($plugin);
                } else {
                        throw new Bolzz_Exception_Plugger('Register plugin "'. $className .'" failed.');
                }
        } 
// MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
        /**
         * Search in array $areaNeedle for parameters of URL.          * 
         * First parameter found in array will set $area. So the order is: domain.de/p1/p2/p3
         * If p1 was found in array, return $areaNeedle[p1]. If not, array will be searched
         * for p2 and after all p3. There is no need to search for more than 3 parameters,
         * because of URL structure module/controller/action/...         * 
         * <code>
         * <?php
         * $areaNeedle = array('foo' => 'bar', 'bla' => 'blubb');
         * // so when manager calls _loadAreaByNeedle() and parameters are 'blubb' and 'bar' then         * // return 'bla', what means that $area is set to 'bla'. Controlled by order of params!
         * </code>
         * @usedby _init()
         * @uses $_urlParams
         * @uses $_baseUrl         * @uses $_areaNeedle
         * @return string Value for Bolzz_Zend_PluggerPlugin::$area. By Default: empty string.
         */     
        private function _loadAreaByNeedle()
        {                $aParams = array();
 
                if (!empty($this->_urlParams)) {
                        $params = str_replace($this->_baseUrl, '', $this->_urlParams);
                                                if ($params{0} === '/') {
                                $params = substr($params, 1);
                        }
                        
                        $aParams = explode('/', $params);                       }
 
                if (!empty($aParams)) {
                        $counts = count($aParams);
                                                // search for first 3 parameters only.
                        if ($counts > 3) {
                                $counts = 3;
                        }
                         for ($i = 0; $i < $counts; $i++) {
                                if (in_array($aParams[$i], $this->_areaNeedle)) {
                                        $aFlip = array_flip($this->_areaNeedle);
                                        
                                        return $aFlip[$aParams[$i]];                                }
                        }
                }
                
                return '';        }
 
// MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
        /**         * Check Regexes given as VALUES in assoc array $_areaRegex against first 3 parameters in URL.
         * 
         * $baseUrl is filtered from URL automatically, before checking. 
         * A trailing slash also will be filtered.
         *          * <code>
         * <?php
         * $areaRegex = array('foo' => '(^bar.*)', 'bla' => '^blubb.*');
         * // so when manager calls _loadAreaByRegex() then
         * // check regex (^bar.*) against parameters, on success return 'foo'.         * // Controlled by order of array! Unlike _loadAreaByNeedle().
         * </code>
         * @usedby _init()
         * @uses $_urlParams
         * @uses $_baseUrl         * @uses $_areaRegex
         * @return string Value of Bolzz_Zend_PluggerPlugin::$area. By Default: empty string.
         */     
        private function _loadAreaByRegex()
        {                $params = str_replace($this->_baseUrl, '', $this->_urlParams);
                
                if ($params{0} === '/') {
                        $params = substr($params, 1);
                }                
                $aParams = explode('/', $params);
 
                if (is_array($aParams)) {
                        $counts = count($aParams);                        
                        if ($counts > 3) {
                                $counts = 3;
                        }
                                                $params = '';
                        
                        for ($i = 0; $i < $counts; $i++) {
                                $params .= $aParams[$i] . '/';
                        }                }
 
                foreach ($this->_areaRegex as $area => $regex) {
                        if ($regex{0} !== '(') {
                                $regex = '(' . $regex . ')';                        }
                        
                        if (preg_match($regex, $params) === 1) {
                                return $area;
                        }                }
 
                return '';
        }
 // MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
        /**
         * Read Module, Controller or Action out of url string when $area is empty (default).
         * If no parameters found in URL or $areaMode is empty, then return 'default'.         * Is called last in the chain of the loadAreaBy*()-methods, if one or both of the other arrays are given.
         * 
         * <code>
         * <?php
         * $areaMode = 'module';         * // so when manager calls loadAreaByMode() then
         * // check if a module exists in parameters, on success return parameter stands for module.
         * 
         * // NOTE:
         * // So this means, URL should be like module/controller/action/key1/value1/... like Zend does recommend.         * // Visit link to Zend Documentation for more details about MVC structure of Zend Framework.
         * </code>
         * @todo optimize code, create _filterTrailingSlash() for loadAreaBy*()-methods
         * @link http://framework.zend.com/manual/en/zend.controller.modular.html 7.11. Using a Conventional Modular Directory Structure
         * @usedby _init()         * @uses $_urlParams
         * @uses $_baseUrl
         * @uses $_areaMode
         * @return string Value of Bolzz_Zend_PluggerPlugin::$area. Will never be an empty string like in the other loadAreaBy*-methods. By Default: 'default'.
         */             private function _loadAreaByMode()
        {
                $aParams = array();
 
                if (!empty($this->_urlParams)) {                        $params = str_replace($this->_baseUrl, '', $this->_urlParams);
                        
                        if ($params{0} === '/') {
                                $params = substr($params, 1);
                        }                        
                        $aParams = explode('/', $params);       
                }
 
                if (empty($aParams[0])) {                        return 'default'; // no parameter found in URL.
                } else {
                        switch ($this->_areaMode) {
                                case 'module':
                                        return (!empty($aParams[0])) ? $aParams[0] : $aParams[1]; 
                                case 'controller':
                                        return (!empty($aParams[0])) ? $aParams[1] : $aParams[2];
 
                                case 'action':                                        return (!empty($aParams[0])) ? $aParams[2] : $aParams[3];
 
                                default:
                                        return 'default'; // empty string given in $this->_areaMode (set by __construct)
                        }                }
        }
        
// MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
         /**
         * Mark members as initialized, which are needed to run Plugger.
         * 
         * @param string $_s
         * @return void         */
        private function _initialized($_s)
        {
                if (false === $this->isInitialized()
                && isset($_s)                && false === in_array($_s, $this->_initList, true)) {
                        $_s = (string) $_s;
 
                        array_push($this->_initList, $_s);
                                                $this->_initialized--;
                }
        }
        
// MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
        /**
         * Load area by Needle, Regex or Mode.
         * 
         * NOTE: If you use isInitialized() in your code, be sure that Area is set.         * Therefor you can use setArea(), loadArea() or constructor argument.
         * 
         * @usedby run()
         * @uses setArea()
         * @return void         */
        public function loadArea()
        {
                if (empty($this->_area)) {
                        if (!empty($this->_areaNeedle)) {                                                               $this->setArea($this->_loadAreaByNeedle());
                        }
 
                        if (empty($this->_area) && !empty($this->_areaRegex)) {                         
                                $this->setArea($this->_loadAreaByRegex());                        }
 
                        if (empty($this->_area)) {
                                $this->setArea($this->_loadAreaByMode());
                        }                }
        }
        
// MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
         /**
         * Check whether all members are initialized.
         * 
         * NOTE: This method would return false, if $_area or $_loader are not set.
         * @return bool         */
        public function isInitialized()
        {               
                if (count($this->_initList) == self::MEMBERS_TO_INIT
                && 0 === $this->_initialized) {                        return true;
                }
                
                return false;
        } 
// MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
        /**
         * Setter         * 
         * @usedby loadArea()
         * @param string $_s
         * @return void
         */        public function setArea($_s)
        {
                if (isset($_s) && is_string($_s)) {
                        $this->_area = $_s;
                        $this->_initialized(__METHOD__);                } else {
// @todo wrong type
                }
        }
        // MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
        /**
         * Setter
         *          * @param mixed $_m String: Areaname. | $_a assoc Array. Example: array('AREANAME' => 'NEEDLE');
         * @param string $_needle Needle. Default: ''.
         * @return void
         */
        public function setNeedle($_m, $_needle = '')        {
                if (isset($_m) && is_array($_m)) {
                        $this->_areaNeedle = $_m;
                } elseif (isset($_m) && is_string($_m)) {
                         $this->_areaNeedle = array($_m => $_needle);                } else {
// @todo wrong type
                }
        }
        // MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
        /**
         * Setter
         *          * @param mixed $_m String: Areaname. | assoc Array. Example: array('AREANAME' => '(^REGEX.*)');
         * @param string $_regex Regex. Default: ''.
         * @return void
         */
        public function setRegex($_m, $_regex = '')        {
                if (isset($_m) && is_array($_m)) {
                        $this->_areaRegex = $_m;
                } elseif (isset($_m) && is_string($_m)) {
                         $this->_areaRegex = array($_m => $_regex);                } else {
// @todo wrong type
                }
        }
        // MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
        /**
         * Setter
         *          * @param string $_s
         * @return void
         */
        public function setMode($_s)
        {                if (isset($_s) && is_string($_s)) {
                        $this->_areaMode = $_s;
                } else {
// @todo wrong type
                }        }
        
// MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
        /**         * Setter
         * 
         * Overwrite member. If you don't want, use {@see addSpecials()}.
         * @param array $_a assoc Array. Key: Area (string) Value: Classname (string|num array)
         * @return void         */
        public function setSpecials($_a)
        {
                if (isset($_a) && is_array($_a)) {
                        $this->_pluginsAreas = $_a;                } else {
// @todo wrong type
                }
        }
        // MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
        /**
         * Adder
         *          * NOTE: Value of an existing Key/Area will be overwritten.
         * Variable count of arguments allowed. They represent the constructor arguments
         * for the plugin class. Only allowed if first parameter is a string!
         * If Array, arguments will be ignored!
         * @varargs         * @uses ReflectionMethod
         * @param mixed $_m String: Area | assoc Array. Key: Area (string) Value: Classname (string|num array)
         * @param mixed $_mClass String: Classname. Default: null. | Num Array. Values: Classnames
         * @return void
         */        public function addSpecials($_m, $_mClass = null)
        {
                if (isset($_m) && is_array($_m)) {
                        foreach ($_m as $area => $mCls) {
                                if (is_string($area)                                && (is_string($mCls) || is_array($mCls))) {
                                        $this->_pluginsAreas[$area] = $mCls;
                                }
                        }
                } elseif (isset($_m) && is_string($_m)) {                        if (!empty($_m) && !empty($_mClass)) {
                                // Add specials.
                                if (is_string($_mClass) || is_array($_mClass)) {
                                        $this->_pluginsAreas[$_m] = $_mClass;
                                } 
                                // Constructor arguments are given.
                                if (func_num_args() > 2) {
                                        $aArgs = func_get_args();
                                                                                array_shift($aArgs); // remove AREANAME
                                        
                                        $addArgs = new ReflectionMethod(__CLASS__, 'addArgs');
                                        
                                        $addArgs->invokeArgs($this, $aArgs);                                }
                        }
                }
        }
        // MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
        /**
         * Setter
         *          * Overwrite member. If you don't want, use {@see addArgs()}.
         * @todo Implement variable arguments - second param needed.
         * @param array $_a assoc Array. Key: Classname Value: mixed
         * @return void
         */        public function setArgs($_a)
        {
                if (isset($_a) && is_array($_a)) {
                        $this->_arguments = $_a;
                } else {// @todo wrong type
                }
        }
 
// MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
        /**
         * Adder
         * 
         * Variable count of arguments allowed. They represent the constructor arguments         * for the plugin class.
         * @varargs
         * @param string $_className
         * @return void
         */        public function addArgs($_className)
        {
                if (isset($_className) && is_string($_className)) {
                        $aArgs = null;
                         if (func_num_args() > 1) {
                                $aArgs = func_get_args();
 
                                if ($aArgs[0] === $_className) {
                                        array_shift($aArgs);                                }                       
                        }
 
                        if (is_array($aArgs)) {
                                $aArguments = array();                                
                                foreach ($aArgs as $key => $mArg) {
                                        $aArguments[] = $mArg;
                                }
                                 if (!empty($aArguments)) {
                                        $this->_arguments[$_className] = $aArguments;
                                } else {
// @todo Exception: "No arguments given."
                                }                        } else {
// @todo Exception: "No arguments given."
                        }
                } else {
// @todo wrong type                }
        }
        
// MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
         /**
         * Setter
         * 
         * Overwrite member. If you don't want, use addDefaults().
         * @todo Implement usage with variable count of arguments.         * @param mixed $_m Num Array or String.
         * @return void
         */
        public function setDefaults($_m)
        {                if (isset($_m) && is_array($_m)) {
                        $this->_pluginsDefaults = $_m;
                } elseif (isset($_m) && is_string($_m)) {
                        $this->_pluginsDefaults = array($_m);
                } else {// @todo wrong type
                }
        }
        
// MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
        /**
         * Adder
         * 
         * Variable count of arguments allowed. They represent the constructor arguments         * for the plugin class. Only allowed if first parameter is a string!
         * If Array, arguments will be ignored!
         * @varargs
         * @uses ReflectionMethod
         * @param mixed $_m Num Array or String. Array: Classnames. String: Classname.         * @return void
         */
        public function addDefaults($_m)
        {
                if (isset($_m) && is_array($_m)) {                        foreach ($_m as $key => $className) {
                                if (is_string($className)
                                && false === in_array($className, $this->_pluginsDefaults)) {
                                        $this->_pluginsDefaults[] = $className;
                                }                        }
                } elseif (isset($_m) && is_string($_m)) {
                        // Add defaults.
                        if (false === in_array($_m, $this->_pluginsDefaults)) {
                                array_push($this->_pluginsDefaults, $_m);                        }
                        
                        // Constructor arguments are given.
                        if (func_num_args() > 1) {
                                $aArgs = func_get_args();                                
                                $addArgs = new ReflectionMethod(__CLASS__, 'addArgs');
                                
                                $addArgs->invokeArgs($this, $aArgs);
                        }                } else {
// @todo wrong type
                }
        }
        // MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
        /**
         * Setter
         *          * By Default: Value of $_SERVER['REQUEST_URI'].
         * @param string $_s
         * @return void
         */
        public function setUrlParams($_s)        {
                if (isset($_s) && is_string($_s)) {
                        $this->_urlParams = $_s;
                }
        }        
// MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
        /**
         * Setter         * 
         * BaseUrl comes from Front Controller and is set by constructor. You can
         * set (overwrite) the BaseUrl by this setter method.
         * NOTE: This setter will not change the major baseUrl of the front controller!
         * It is for Plugger use only.         * @param string $_s
         * @return void
         */
        public function setBaseUrl($_s)
        {                if (isset($_s) && is_string($_s)) {
                        $this->_baseUrl = $_s;
                }
        }
        // MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
        /**
         * Setter
         *          * NOTE: A Loader object has been set before run().
         * @param object $_o Zend_Loader_PluginLoader_Interface
         * @return void
         */
        public function setLoader(Zend_Loader_PluginLoader_Interface $_o)        {
                $this->_loader = $_o;
                $this->_initialized(__METHOD__);
        }
        // MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        
        /**
         * Run Plugger, means register plugins. Plugger has to be initialized otherwise
         * an exception would be thrown.         * 
         * NOTE: Use only in mode $_run: false (Last argument of constructor - Default: false).
         * @uses loadArea() 
         * @throws Bolzz_Exception_Plugger
         * @return void         */
        public function run()
        {
                $this->loadArea();
                 if (true === $this->isInitialized()) {
                        $this->_registerDefaults();
                        
                        $this->_registerSpecials();
                } else {                        throw new Bolzz_Exception_Plugger('Plugger is not full initialized and not ready to run or register plugins.');
                }
        }
        
// MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
        /**
         * Reset initialization. 
         * 
         * Members keep their values, only members which are         * important for a minimum of initialization will be cleared!
         * @uses ReflectionClass
         * @return void
         */
        public function reset()        {
                $clsPlugger = new ReflectionClass(__CLASS__);
                
                $defaultProps = $clsPlugger->getDefaultProperties();
                                $this->_initialized = $defaultProps['_initialized'];
                $this->_initList        = $defaultProps['_initList'];
                $this->_area            = $defaultProps['_area'];
                $this->_loader          = $defaultProps['_loader'];
        } 
// MUST +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
        /**
         * Clear all member values.         * 
         * @uses reset()
         * @uses ReflectionClass
         * @return void
         */        public function clear()
        {
                $this->reset();
 
                $clsParent              = new ReflectionClass(get_parent_class($this));                $parentProps    = $clsParent->getDefaultProperties();
 
                $clsPlugger     = new ReflectionClass(__CLASS__);
                $selfProps      = $clsPlugger->getDefaultProperties();
                                // Do not change parent's members
                $props = array_diff_assoc($selfProps, $parentProps);
                
                if (is_array($props)) {
                        foreach ($props as $sMember => $mValue) {                                $this->{$sMember} = $mValue;
                        }
                }
        }
}
1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
<?php
/**
 * Bolzz Library
 * http://www.bolzz.com - BOLZZ | IT Entwicklung
 * * LICENSE
 * 100% Freeware and Open Source
 *
 * @package Bolzz
 * @subpackage Exception */
 
/**
 * Plugin Manager Exception
 * * @version Version 0.1.0
 */
class Bolzz_Exception_Plugger extends Exception
{
        public function __construct($_message = '')        {
                $this->message = $_message;
        }
}

Comments

You must login before commenting on a snippet. If you do not have an account, please register.

Snippet description

The plugin manager - plugger - is implemented as a ZF plugin, but its not needed to register it as a plugin, only instantiate it and configure it by setters.

Why a plugin manager? If you have many plugins in your ZF application they are all loaded on each request. Even if they are not needed in current request.

The plugger is a layer before dispatch process is started and plugins are registered only if they are really needed in current request.



advantages

All plugins will be managed by one manager class, the plugin manager. The plugger has to be initiliazed in the bootstrap and after that, plugger registers all plugins automatically and only when they really needed.

It's possible to load plugins on each request or only if they really needed (known by the URL). This decreases ZF parse time and serves much more flexibility in using plugins.

The plugger detects the area from URL automatically in 3 optional steps by default. Alternativly a developer could set area by himself. This serves a lot of comfort to organize plugins.



disadvantage

If a baseUrl is used/needed, then it must be set manually in bootstrap, because plugger works completely in constructor and must be instantiated in bootstrap before running the dispatch process.

Snippet details

Created:
DavidToniolo DavidToniolo
1 year ago
Edited:
DavidToniolo DavidToniolo
1 year ago
Revision Id:
99
Edit Message:
Initial Release
Tags:
plugin bootstrap Manager Loader
Comments:
0
Views:
423
Points:
0 (0 votes)

History

r99

Initial Release

DavidToniolo DavidToniolo
1 year ago
diff
r98

Initial Release

DavidToniolo DavidToniolo
1 year ago