Plugger - A Plugin Manager
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.
<?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 #############################################################
// 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 ##########################################################
// 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;
}
}
}
}
<?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.
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.
- Created:
-
DavidToniolo
- Edited:
-
DavidToniolo
- Revision Id:
- 99
- Edit Message:
- Initial Release
- Tags:
- plugin bootstrap Manager Loader
- Comments:
- 0
- Points:
- 0 (0 votes)