* @author Kornel LesiƄski * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License * @version SVN: $Id$ * @link http://phptal.org/ */ /** * Global registry of TALES expression modifiers * * @package PHPTAL * @subpackage Php */ class PHPTAL_TalesRegistry { private static $instance; /** * This is a singleton * * @return PHPTAL_TalesRegistry */ static public function getInstance() { if (!self::$instance) { self::$instance = new PHPTAL_TalesRegistry(); } return self::$instance; } protected function __construct() { $this->registerPrefix('not', array('PHPTAL_Php_TalesInternal', 'not')); $this->registerPrefix('path', array('PHPTAL_Php_TalesInternal', 'path')); $this->registerPrefix('string', array('PHPTAL_Php_TalesInternal', 'string')); $this->registerPrefix('php', array('PHPTAL_Php_TalesInternal', 'php')); $this->registerPrefix('phptal-internal-php-block', array('PHPTAL_Php_TalesInternal', 'phptal_internal_php_block')); $this->registerPrefix('exists', array('PHPTAL_Php_TalesInternal', 'exists')); $this->registerPrefix('number', array('PHPTAL_Php_TalesInternal', 'number')); $this->registerPrefix('true', array('PHPTAL_Php_TalesInternal', 'true')); // these are added as fallbacks $this->registerPrefix('json', array('PHPTAL_Php_TalesInternal', 'json'), true); $this->registerPrefix('urlencode', array('PHPTAL_Php_TalesInternal', 'urlencode'), true); } /** * Unregisters a expression modifier * * @param string $prefix * * @throws PHPTAL_ConfigurationException */ public function unregisterPrefix($prefix) { if (!$this->isRegistered($prefix)) { throw new PHPTAL_ConfigurationException("Expression modifier '$prefix' is not registered"); } unset($this->_callbacks[$prefix]); } /** * * Expects an either a function name or an array of class and method as * callback. * * @param string $prefix * @param mixed $callback * @param bool $is_fallback if true, method will be used as last resort (if there's no phptal_tales_foo) */ public function registerPrefix($prefix, $callback, $is_fallback = false) { if ($this->isRegistered($prefix) && !$this->_callbacks[$prefix]['is_fallback']) { if ($is_fallback) { return; // simply ignored } throw new PHPTAL_ConfigurationException("Expression modifier '$prefix' is already registered"); } // Check if valid callback if (is_array($callback)) { $class = new ReflectionClass($callback[0]); if (!$class->isSubclassOf('PHPTAL_Tales')) { throw new PHPTAL_ConfigurationException('The class you want to register does not implement "PHPTAL_Tales".'); } $method = new ReflectionMethod($callback[0], $callback[1]); if (!$method->isStatic()) { throw new PHPTAL_ConfigurationException('The method you want to register is not static.'); } // maybe we want to check the parameters the method takes } else { if (!function_exists($callback)) { throw new PHPTAL_ConfigurationException('The function you are trying to register does not exist.'); } } $this->_callbacks[$prefix] = array('callback'=>$callback, 'is_fallback'=>$is_fallback); } /** * true if given prefix is taken */ public function isRegistered($prefix) { if (array_key_exists($prefix, $this->_callbacks)) { return true; } } private function findUnregisteredCallback($typePrefix) { // class method if (strpos($typePrefix, '.')) { $classCallback = explode('.', $typePrefix, 2); $callbackName = null; if (!is_callable($classCallback, false, $callbackName)) { throw new PHPTAL_UnknownModifierException("Unknown phptal modifier $typePrefix. Function $callbackName does not exists or is not statically callable", $typePrefix); } $ref = new ReflectionClass($classCallback[0]); if (!$ref->implementsInterface('PHPTAL_Tales')) { throw new PHPTAL_UnknownModifierException("Unable to use phptal modifier $typePrefix as the class $callbackName does not implement the PHPTAL_Tales interface", $typePrefix); } return $classCallback; } // check if it is implemented via code-generating function $func = 'phptal_tales_'.str_replace('-', '_', $typePrefix); if (function_exists($func)) { return $func; } // The following code is automatically modified in version for PHP 5.3 $func = 'PHPTALNAMESPACE\\phptal_tales_'.str_replace('-', '_', $typePrefix); if (function_exists($func)) { return $func; } return null; } /** * get callback for the prefix * * @return callback or NULL */ public function getCallback($prefix) { if ($this->isRegistered($prefix) && !$this->_callbacks[$prefix]['is_fallback']) { return $this->_callbacks[$prefix]['callback']; } if ($callback = $this->findUnregisteredCallback($prefix)) { return $callback; } if ($this->isRegistered($prefix)) { return $this->_callbacks[$prefix]['callback']; } return null; } /** * {callback, bool is_fallback} */ private $_callbacks = array(); }