539 Zeilen
14 KiB
PHP
539 Zeilen
14 KiB
PHP
<?php
|
|
/**
|
|
* Project:
|
|
* Contenido Content Management System
|
|
*
|
|
* Description:
|
|
* Contenido Extension Chainer (CEC).
|
|
* See "docs/techref/plugins/Contenido Extension Chainer.pdf" for more details about CEC.
|
|
*
|
|
* Requirements:
|
|
* @con_php_req 5.0
|
|
*
|
|
*
|
|
* @package Contenido Backend classes
|
|
* @subpackage CEC
|
|
* @version 1.2.0
|
|
* @author Timo A. Hummel
|
|
* @author Murat Purc <murat@purc.de>
|
|
* @copyright four for business AG <www.4fb.de>
|
|
* @license http://www.contenido.org/license/LIZENZ.txt
|
|
* @link http://www.4fb.de
|
|
* @link http://www.contenido.org
|
|
* @since file available since contenido release <= 4.6
|
|
*
|
|
* {@internal
|
|
* created unknown
|
|
* modified 2008-06-30, Dominik Ziegler, add security fix
|
|
* modified 2008-08-28, Murat Purc, add singleton pattern feature
|
|
* modified 2009-12-30, Murat Purc, redesign of cApiCECRegistry and pApiCECChainItem bearing in mind of
|
|
* downwards compatibility and documenting the code, see [#CON-291], also regards to [#CON-256]
|
|
*
|
|
* $Id$:
|
|
* }}
|
|
*
|
|
*/
|
|
|
|
if(!defined('CON_FRAMEWORK')) {
|
|
die('Illegal call');
|
|
}
|
|
|
|
|
|
/**
|
|
* CEC registry class. Used to register chains and chain functions to invoke.
|
|
*
|
|
* Following 3 types of CEC functions/callbacks are supported at the moment:
|
|
* - Callbacks, which should only be invoked. They don't return a value and have no
|
|
* break conditions, @see CEC_Hook::execute()
|
|
* - Callbacks, which should return a value and/or should modify a passed parameter,
|
|
* @see CEC_Hook::executeAndReturn()
|
|
* - Callbacks, which should be processed untill a defined break condition achieves,
|
|
* @see CEC_Hook::executeWhileBreakCondition()
|
|
*
|
|
* @author Timo A. Hummel
|
|
* @author Murat Purc <murat@purc.de>
|
|
* @package Contenido Backend classes
|
|
* @subpackage CEC
|
|
*/
|
|
class cApiCECRegistry
|
|
{
|
|
/**
|
|
* List of available chains
|
|
* @var array
|
|
*/
|
|
private $_aChains;
|
|
|
|
/**
|
|
* Self instance
|
|
* @var cApiCECRegistry
|
|
*/
|
|
private static $_instance = null;
|
|
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function __construct()
|
|
{
|
|
$this->_aChains = array();
|
|
}
|
|
|
|
|
|
/**
|
|
* Prevent cloning
|
|
*
|
|
* @return void
|
|
*/
|
|
private function __clone()
|
|
{
|
|
// donut
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns a instance of cApiCECRegistry
|
|
*
|
|
* @return cApiCECRegistry
|
|
*/
|
|
public static function getInstance()
|
|
{
|
|
if (self::$_instance == null) {
|
|
self::$_instance = new cApiCECRegistry();
|
|
}
|
|
return self::$_instance;
|
|
}
|
|
|
|
|
|
/**
|
|
* Registers a chain (adds the chain to the internal chain holder)
|
|
*
|
|
* @param string $sChainName
|
|
* @param mixed First chain parameter
|
|
* @param mixed Second chain parameter
|
|
* @param mixed Third chain parameter...
|
|
* NOTE: The number of parameter is not restricted, you can pass parameter as
|
|
* much as you want.
|
|
* @return void
|
|
*/
|
|
public function registerChain($sChainName)
|
|
{
|
|
$aParam = array();
|
|
$iNumArgs = func_num_args();
|
|
|
|
for ($iCount = 0; $iCount < $iNumArgs; $iCount++) {
|
|
$aParam[$iCount] = func_get_arg($iCount);
|
|
}
|
|
|
|
$this->_addChain($sChainName, $aParam);
|
|
}
|
|
|
|
|
|
/**
|
|
* Unregisters a chain
|
|
*
|
|
* @param string $sChainName
|
|
* @return void
|
|
*/
|
|
public function unregisterChain($sChainName)
|
|
{
|
|
// Check if the chain exists
|
|
if (!$this->isChainRegistered($sChainName)) {
|
|
cWarning(__FILE__, __LINE__, "Chain " . $sChainName . " doesn't exist.");
|
|
return false;
|
|
}
|
|
|
|
$functions = array();
|
|
$this->_resetIterator($sChainName);
|
|
$chainFunctions = $this->_aChains[$sChainName]['functions'];
|
|
foreach ($chainFunctions as $pos => $item) {
|
|
$functions[] = $item->getFunctionName();
|
|
}
|
|
|
|
foreach ($functions as $p => $func) {
|
|
$this->removeChainFunction($sChainName, $func);
|
|
}
|
|
|
|
unset($this->_aChains[$sChainName]);
|
|
}
|
|
|
|
|
|
/**
|
|
* Checks if a chain is registered or not.
|
|
*
|
|
* @param string $sChainName
|
|
* @return bool
|
|
*/
|
|
public function isChainRegistered($sChainName)
|
|
{
|
|
return (isset($this->_aChains[$sChainName]));
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns list of registered chain names
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getRegisteredChainNames()
|
|
{
|
|
return array_keys($this->_aChains);
|
|
}
|
|
|
|
|
|
/**
|
|
* Adds the chain to the internal chain holder
|
|
*
|
|
* @param string $sChainName Chain name
|
|
* @param array $aParameters Chain parameter
|
|
* @return void
|
|
*/
|
|
protected function _addChain($sChainName, array $aParameters = array())
|
|
{
|
|
$this->_aChains[$sChainName]['parameters'] = $aParameters;
|
|
$this->_aChains[$sChainName]['functions'] = array();
|
|
}
|
|
|
|
|
|
/**
|
|
* Adds a chain function which is to invoke.
|
|
*
|
|
* @param string $sChainName Chain name
|
|
* @param string $sFunctionName Name of function/callback to invoke. Feasible values are:
|
|
* - "ClassName->methodName" to invoke a method of a ClassName instance.
|
|
* A instance of the clas will be created here.
|
|
* - "ClassName::methodName" to invoke a static method of ClassName.
|
|
* - "FunctionName" to invoke a function.
|
|
* NOTE: Necessary files must be manually included before or by defined autoloader.
|
|
* @return bool True on success, otherwhise false
|
|
*/
|
|
public function addChainFunction($sChainName, $sFunctionName)
|
|
{
|
|
// Check if the chain exists
|
|
if (!$this->isChainRegistered($sChainName)) {
|
|
cWarning(__FILE__, __LINE__, "Chain " . $sChainName . " doesn't exist.");
|
|
return false;
|
|
}
|
|
|
|
if (strpos($sFunctionName, '->') > 0) {
|
|
// chain function is a method of a object instance
|
|
list($class, $method) = explode('->', $sFunctionName);
|
|
if (!class_exists($class)) {
|
|
cWarning(__FILE__, __LINE__, "Class " . $class . " doesn't exist, can't add " . $sFunctionName . " to chain " . $sChainName);
|
|
return false;
|
|
} elseif (!method_exists($class, $method)) {
|
|
cWarning(__FILE__, __LINE__, "Method " . $method . " in class " . $class . " doesn't exist, can't add " . $sFunctionName . " to chain " . $sChainName);
|
|
return false;
|
|
}
|
|
$call = array(new $class(), $method);
|
|
} elseif (strpos($sFunctionName, '::') > 0) {
|
|
// chain function is static method of a object
|
|
list($class, $method) = explode('::', $sFunctionName);
|
|
if (!class_exists($class)) {
|
|
cWarning(__FILE__, __LINE__, "Class " . $class . " doesn't exist, can't add " . $sFunctionName . " to chain " . $sChainName);
|
|
return false;
|
|
} elseif (!method_exists($class, $method)) {
|
|
cWarning(__FILE__, __LINE__, "Method " . $method . " in class " . $class . " doesn't exist, can't add " . $sFunctionName . " to chain " . $sChainName);
|
|
return false;
|
|
}
|
|
$call = array($class, $method);
|
|
} else {
|
|
// chain function is a function
|
|
if (!function_exists($sFunctionName)) {
|
|
cWarning(__FILE__, __LINE__, "Function " . $sFunctionName . " doesn't exist, can't add to chain " . $sChainName);
|
|
return false;
|
|
}
|
|
$call = $sFunctionName;
|
|
}
|
|
|
|
// Last check if the callback is callable
|
|
if (!is_callable($call)) {
|
|
cWarning(__FILE__, __LINE__, "Function " . $sFunctionName . " isn't callable, can't add to chain " . $sChainName);
|
|
return false;
|
|
}
|
|
|
|
$oChainItem = new pApiCECChainItem($sChainName, $sFunctionName, $this->_aChains[$sChainName]['parameters']);
|
|
$oChainItem->setCallback($call);
|
|
array_push($this->_aChains[$sChainName]['functions'], $oChainItem);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Checks if a chain function exists.
|
|
*
|
|
* @param string $sChainName Chain name
|
|
* @param string $sFunctionName Name of function to check
|
|
* @return bool
|
|
*/
|
|
public function chainFunctionExists($sChainName, $sFunctionName)
|
|
{
|
|
if (!$this->isChainRegistered($sChainName)) {
|
|
return false;
|
|
}
|
|
|
|
$this->_resetIterator($sChainName);
|
|
$chainFunctions = $this->_aChains[$sChainName]['functions'];
|
|
foreach ($chainFunctions as $pos => $item) {
|
|
if ($item->getFunctionName() == $sFunctionName) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Removes a chain function.
|
|
*
|
|
* @param string $sChainName Chain name
|
|
* @param string $sFunctionName Name of function to remove from chain.
|
|
*/
|
|
public function removeChainFunction($sChainName, $sFunctionName)
|
|
{
|
|
if (!$this->isChainRegistered($sChainName)) {
|
|
return;
|
|
}
|
|
|
|
$this->_resetIterator($sChainName);
|
|
$chainFunctions = $this->_aChains[$sChainName]['functions'];
|
|
foreach ($this->_aChains[$sChainName]['functions'] as $pos => $item) {
|
|
if ($item->getFunctionName() == $sFunctionName) {
|
|
unset($this->_aChains[$sChainName]['functions'][$pos]);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the iterator for a desired chain.
|
|
*
|
|
* @TODO: cIterator should be replaced by ArrayIterator (@see http://www.php.net/spl)
|
|
* but ArrayIterator uses rewind() instead of reset()...
|
|
*
|
|
* @param string $sChainName Chain name
|
|
* @return cIterator
|
|
*/
|
|
public function getIterator($sChainName)
|
|
{
|
|
return new cIterator($this->_aChains[$sChainName]['functions']);
|
|
}
|
|
|
|
|
|
/**
|
|
* Resets the chain iterator.
|
|
*
|
|
* @param string $sChainName
|
|
* @return void
|
|
*/
|
|
protected function _resetIterator($sChainName)
|
|
{
|
|
$iterator = $this->getIterator($sChainName);
|
|
$iterator->reset();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* CEC chain item class.
|
|
*
|
|
* @author Timo A. Hummel
|
|
* @author Murat Purc <murat@purc.de>
|
|
* @package Contenido Backend classes
|
|
* @subpackage CEC
|
|
*/
|
|
class pApiCECChainItem
|
|
{
|
|
/**
|
|
* Chain name
|
|
* @var string
|
|
*/
|
|
protected $_sChainName;
|
|
|
|
/**
|
|
* Name of function to invoke
|
|
* @var string
|
|
*/
|
|
protected $_sFunctionName;
|
|
|
|
/**
|
|
* Callback name. Contains either the function name to invoke, or a indexed array (class/object and method)
|
|
* and it's method to execute.
|
|
* @var array|string
|
|
*/
|
|
protected $_mCallback;
|
|
|
|
/**
|
|
* Parameter to pass to the function
|
|
* @var array
|
|
*/
|
|
protected $_aParameters;
|
|
|
|
|
|
/**
|
|
* Temporary arguments holder
|
|
* @var array|null
|
|
*/
|
|
protected $_mTemporaryArguments;
|
|
|
|
|
|
/**
|
|
* Constructor, sets the CEC chain item properties.
|
|
*
|
|
* @param string $sChainName
|
|
* @param string $sFunctionName
|
|
* @param array $aParameters
|
|
* @return void
|
|
*/
|
|
public function __construct($sChainName, $sFunctionName, $aParameters)
|
|
{
|
|
$this->setChainName($sChainName);
|
|
$this->setFunctionName($sFunctionName);
|
|
$this->setParameters($aParameters);
|
|
$this->setCallback($this->getFunctionName());
|
|
}
|
|
|
|
|
|
/**
|
|
* Sets the chain name
|
|
*
|
|
* @param string $sChainName
|
|
* @return void
|
|
*/
|
|
public function setChainName($sChainName)
|
|
{
|
|
$this->_sChainName = $sChainName;
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the chain name
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getChainName()
|
|
{
|
|
return $this->_sChainName;
|
|
}
|
|
|
|
|
|
/**
|
|
* Sets the function name
|
|
*
|
|
* @param string $sFunctionName
|
|
* @return void
|
|
*/
|
|
public function setFunctionName($sFunctionName)
|
|
{
|
|
$this->_sFunctionName = $sFunctionName;
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the function name
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getFunctionName()
|
|
{
|
|
return $this->_sFunctionName;
|
|
}
|
|
|
|
|
|
/**
|
|
* Sets the callback parameters
|
|
*
|
|
* @param array $aParameters
|
|
* @return void
|
|
*/
|
|
public function setParameters(array $aParameters)
|
|
{
|
|
$this->_aParameters = $aParameters;
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the function name
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getParameters()
|
|
{
|
|
return $this->_aParameters;
|
|
}
|
|
|
|
|
|
/**
|
|
* Sets the callback
|
|
*
|
|
* @return string|array
|
|
*/
|
|
public function setCallback($callback)
|
|
{
|
|
if (is_string($callback) || is_array($callback)) {
|
|
$this->_mCallback = $callback;
|
|
} else {
|
|
throw new Exception("Passed argument isn't as expected");
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the callback
|
|
*
|
|
* @return string|array
|
|
*/
|
|
public function getCallback()
|
|
{
|
|
return $this->_mCallback;
|
|
}
|
|
|
|
|
|
/**
|
|
* Another way to set the arguments before invoking execute() method.
|
|
*
|
|
* @param array $args
|
|
* @return void
|
|
*/
|
|
public function setTemporaryArguments(array $args=array())
|
|
{
|
|
$this->_mTemporaryArguments = $args;
|
|
}
|
|
|
|
/**
|
|
* Will be invoked by execute() method. If temporary arguments where set before,
|
|
* it returns them and resets the property.
|
|
*
|
|
* @param array $args
|
|
* @return void
|
|
*/
|
|
public function getTemporaryArguments()
|
|
{
|
|
$args = $this->_mTemporaryArguments;
|
|
$this->_mTemporaryArguments = null;
|
|
return $args;
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Invokes the CEC function/callback.
|
|
*
|
|
* @return mixed If available, the result of the CEC function/callback
|
|
*/
|
|
public function execute()
|
|
{
|
|
// get temporary arguments, if the where set before
|
|
if (!$args = $this->getTemporaryArguments()) {
|
|
// no temporary arguments available, get them by func_get_args()
|
|
$args = func_get_args();
|
|
}
|
|
return call_user_func_array($this->getCallback(), $args);
|
|
}
|
|
|
|
}
|