528 Zeilen
14 KiB
PHP
528 Zeilen
14 KiB
PHP
|
<?php
|
||
|
/**
|
||
|
* Zend Framework
|
||
|
*
|
||
|
* LICENSE
|
||
|
*
|
||
|
* This source file is subject to the new BSD license that is bundled
|
||
|
* with this package in the file LICENSE.txt.
|
||
|
* It is also available through the world-wide-web at this URL:
|
||
|
* http://framework.zend.com/license/new-bsd
|
||
|
* If you did not receive a copy of the license and are unable to
|
||
|
* obtain it through the world-wide-web, please send an email
|
||
|
* to license@zend.com so we can send you a copy immediately.
|
||
|
*
|
||
|
* @category Zend
|
||
|
* @package Zend_Filter
|
||
|
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
|
||
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||
|
* @version $Id$
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @see Zend_Filter
|
||
|
* @see Zend_Filter_Interface
|
||
|
*/
|
||
|
require_once 'Zend/Filter.php';
|
||
|
|
||
|
/**
|
||
|
* @see Zend_Loader_PluginLoader
|
||
|
*/
|
||
|
require_once 'Zend/Loader/PluginLoader.php';
|
||
|
|
||
|
/**
|
||
|
* Filter chain for string inflection
|
||
|
*
|
||
|
* @category Zend
|
||
|
* @package Zend_Filter
|
||
|
* @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
|
||
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||
|
*/
|
||
|
class Zend_Filter_Inflector implements Zend_Filter_Interface
|
||
|
{
|
||
|
/**
|
||
|
* @var Zend_Loader_PluginLoader_Interface
|
||
|
*/
|
||
|
protected $_pluginLoader = null;
|
||
|
|
||
|
/**
|
||
|
* @var string
|
||
|
*/
|
||
|
protected $_target = null;
|
||
|
|
||
|
/**
|
||
|
* @var bool
|
||
|
*/
|
||
|
protected $_throwTargetExceptionsOn = true;
|
||
|
|
||
|
/**
|
||
|
* @var string
|
||
|
*/
|
||
|
protected $_targetReplacementIdentifier = ':';
|
||
|
|
||
|
/**
|
||
|
* @var array
|
||
|
*/
|
||
|
protected $_rules = array();
|
||
|
|
||
|
/**
|
||
|
* Constructor
|
||
|
*
|
||
|
* @param string|array $options Options to set
|
||
|
*/
|
||
|
public function __construct($options = null)
|
||
|
{
|
||
|
if ($options instanceof Zend_Config) {
|
||
|
$options = $options->toArray();
|
||
|
} else if (!is_array($options)) {
|
||
|
$options = func_get_args();
|
||
|
$temp = array();
|
||
|
|
||
|
if (!empty($options)) {
|
||
|
$temp['target'] = array_shift($options);
|
||
|
}
|
||
|
|
||
|
if (!empty($options)) {
|
||
|
$temp['rules'] = array_shift($options);
|
||
|
}
|
||
|
|
||
|
if (!empty($options)) {
|
||
|
$temp['throwTargetExceptionsOn'] = array_shift($options);
|
||
|
}
|
||
|
|
||
|
if (!empty($options)) {
|
||
|
$temp['targetReplacementIdentifier'] = array_shift($options);
|
||
|
}
|
||
|
|
||
|
$options = $temp;
|
||
|
}
|
||
|
|
||
|
$this->setOptions($options);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Retreive PluginLoader
|
||
|
*
|
||
|
* @return Zend_Loader_PluginLoader_Interface
|
||
|
*/
|
||
|
public function getPluginLoader()
|
||
|
{
|
||
|
if (!$this->_pluginLoader instanceof Zend_Loader_PluginLoader_Interface) {
|
||
|
$this->_pluginLoader = new Zend_Loader_PluginLoader(array('Zend_Filter_' => 'Zend/Filter/'), __CLASS__);
|
||
|
}
|
||
|
|
||
|
return $this->_pluginLoader;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set PluginLoader
|
||
|
*
|
||
|
* @param Zend_Loader_PluginLoader_Interface $pluginLoader
|
||
|
* @return Zend_Filter_Inflector
|
||
|
*/
|
||
|
public function setPluginLoader(Zend_Loader_PluginLoader_Interface $pluginLoader)
|
||
|
{
|
||
|
$this->_pluginLoader = $pluginLoader;
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Use Zend_Config object to set object state
|
||
|
*
|
||
|
* @deprecated Use setOptions() instead
|
||
|
* @param Zend_Config $config
|
||
|
* @return Zend_Filter_Inflector
|
||
|
*/
|
||
|
public function setConfig(Zend_Config $config)
|
||
|
{
|
||
|
return $this->setOptions($config);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set options
|
||
|
*
|
||
|
* @param array $options
|
||
|
* @return Zend_Filter_Inflector
|
||
|
*/
|
||
|
public function setOptions($options) {
|
||
|
if ($options instanceof Zend_Config) {
|
||
|
$options = $options->toArray();
|
||
|
}
|
||
|
|
||
|
// Set Präfix Path
|
||
|
if (array_key_exists('filterPrefixPath', $options)) {
|
||
|
if (!is_scalar($options['filterPrefixPath'])) {
|
||
|
foreach ($options['filterPrefixPath'] as $prefix => $path) {
|
||
|
$this->addFilterPrefixPath($prefix, $path);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (array_key_exists('throwTargetExceptionsOn', $options)) {
|
||
|
$this->setThrowTargetExceptionsOn($options['throwTargetExceptionsOn']);
|
||
|
}
|
||
|
|
||
|
if (array_key_exists('targetReplacementIdentifier', $options)) {
|
||
|
$this->setTargetReplacementIdentifier($options['targetReplacementIdentifier']);
|
||
|
}
|
||
|
|
||
|
if (array_key_exists('target', $options)) {
|
||
|
$this->setTarget($options['target']);
|
||
|
}
|
||
|
|
||
|
if (array_key_exists('rules', $options)) {
|
||
|
$this->addRules($options['rules']);
|
||
|
}
|
||
|
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Convienence method to add prefix and path to PluginLoader
|
||
|
*
|
||
|
* @param string $prefix
|
||
|
* @param string $path
|
||
|
* @return Zend_Filter_Inflector
|
||
|
*/
|
||
|
public function addFilterPrefixPath($prefix, $path)
|
||
|
{
|
||
|
$this->getPluginLoader()->addPrefixPath($prefix, $path);
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set Whether or not the inflector should throw an exception when a replacement
|
||
|
* identifier is still found within an inflected target.
|
||
|
*
|
||
|
* @param bool $throwTargetExceptions
|
||
|
* @return Zend_Filter_Inflector
|
||
|
*/
|
||
|
public function setThrowTargetExceptionsOn($throwTargetExceptionsOn)
|
||
|
{
|
||
|
$this->_throwTargetExceptionsOn = ($throwTargetExceptionsOn == true) ? true : false;
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Will exceptions be thrown?
|
||
|
*
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function isThrowTargetExceptionsOn()
|
||
|
{
|
||
|
return $this->_throwTargetExceptionsOn;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the Target Replacement Identifier, by default ':'
|
||
|
*
|
||
|
* @param string $targetReplacementIdentifier
|
||
|
* @return Zend_Filter_Inflector
|
||
|
*/
|
||
|
public function setTargetReplacementIdentifier($targetReplacementIdentifier)
|
||
|
{
|
||
|
if ($targetReplacementIdentifier) {
|
||
|
$this->_targetReplacementIdentifier = (string) $targetReplacementIdentifier;
|
||
|
}
|
||
|
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get Target Replacement Identifier
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
public function getTargetReplacementIdentifier()
|
||
|
{
|
||
|
return $this->_targetReplacementIdentifier;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set a Target
|
||
|
* ex: 'scripts/:controller/:action.:suffix'
|
||
|
*
|
||
|
* @param string
|
||
|
* @return Zend_Filter_Inflector
|
||
|
*/
|
||
|
public function setTarget($target)
|
||
|
{
|
||
|
$this->_target = (string) $target;
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Retrieve target
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
public function getTarget()
|
||
|
{
|
||
|
return $this->_target;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set Target Reference
|
||
|
*
|
||
|
* @param reference $target
|
||
|
* @return Zend_Filter_Inflector
|
||
|
*/
|
||
|
public function setTargetReference(&$target)
|
||
|
{
|
||
|
$this->_target =& $target;
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* SetRules() is the same as calling addRules() with the exception that it
|
||
|
* clears the rules before adding them.
|
||
|
*
|
||
|
* @param array $rules
|
||
|
* @return Zend_Filter_Inflector
|
||
|
*/
|
||
|
public function setRules(Array $rules)
|
||
|
{
|
||
|
$this->clearRules();
|
||
|
$this->addRules($rules);
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* AddRules(): multi-call to setting filter rules.
|
||
|
*
|
||
|
* If prefixed with a ":" (colon), a filter rule will be added. If not
|
||
|
* prefixed, a static replacement will be added.
|
||
|
*
|
||
|
* ex:
|
||
|
* array(
|
||
|
* ':controller' => array('CamelCaseToUnderscore','StringToLower'),
|
||
|
* ':action' => array('CamelCaseToUnderscore','StringToLower'),
|
||
|
* 'suffix' => 'phtml'
|
||
|
* );
|
||
|
*
|
||
|
* @param array
|
||
|
* @return Zend_Filter_Inflector
|
||
|
*/
|
||
|
public function addRules(Array $rules)
|
||
|
{
|
||
|
$keys = array_keys($rules);
|
||
|
foreach ($keys as $spec) {
|
||
|
if ($spec[0] == ':') {
|
||
|
$this->addFilterRule($spec, $rules[$spec]);
|
||
|
} else {
|
||
|
$this->setStaticRule($spec, $rules[$spec]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get rules
|
||
|
*
|
||
|
* By default, returns all rules. If a $spec is provided, will return those
|
||
|
* rules if found, false otherwise.
|
||
|
*
|
||
|
* @param string $spec
|
||
|
* @return array|false
|
||
|
*/
|
||
|
public function getRules($spec = null)
|
||
|
{
|
||
|
if (null !== $spec) {
|
||
|
$spec = $this->_normalizeSpec($spec);
|
||
|
if (isset($this->_rules[$spec])) {
|
||
|
return $this->_rules[$spec];
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return $this->_rules;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* getRule() returns a rule set by setFilterRule(), a numeric index must be provided
|
||
|
*
|
||
|
* @param string $spec
|
||
|
* @param int $index
|
||
|
* @return Zend_Filter_Interface|false
|
||
|
*/
|
||
|
public function getRule($spec, $index)
|
||
|
{
|
||
|
$spec = $this->_normalizeSpec($spec);
|
||
|
if (isset($this->_rules[$spec]) && is_array($this->_rules[$spec])) {
|
||
|
if (isset($this->_rules[$spec][$index])) {
|
||
|
return $this->_rules[$spec][$index];
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ClearRules() clears the rules currently in the inflector
|
||
|
*
|
||
|
* @return Zend_Filter_Inflector
|
||
|
*/
|
||
|
public function clearRules()
|
||
|
{
|
||
|
$this->_rules = array();
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set a filtering rule for a spec. $ruleSet can be a string, Filter object
|
||
|
* or an array of strings or filter objects.
|
||
|
*
|
||
|
* @param string $spec
|
||
|
* @param array|string|Zend_Filter_Interface $ruleSet
|
||
|
* @return Zend_Filter_Inflector
|
||
|
*/
|
||
|
public function setFilterRule($spec, $ruleSet)
|
||
|
{
|
||
|
$spec = $this->_normalizeSpec($spec);
|
||
|
$this->_rules[$spec] = array();
|
||
|
return $this->addFilterRule($spec, $ruleSet);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add a filter rule for a spec
|
||
|
*
|
||
|
* @param mixed $spec
|
||
|
* @param mixed $ruleSet
|
||
|
* @return void
|
||
|
*/
|
||
|
public function addFilterRule($spec, $ruleSet)
|
||
|
{
|
||
|
$spec = $this->_normalizeSpec($spec);
|
||
|
if (!isset($this->_rules[$spec])) {
|
||
|
$this->_rules[$spec] = array();
|
||
|
}
|
||
|
|
||
|
if (!is_array($ruleSet)) {
|
||
|
$ruleSet = array($ruleSet);
|
||
|
}
|
||
|
|
||
|
if (is_string($this->_rules[$spec])) {
|
||
|
$temp = $this->_rules[$spec];
|
||
|
$this->_rules[$spec] = array();
|
||
|
$this->_rules[$spec][] = $temp;
|
||
|
}
|
||
|
|
||
|
foreach ($ruleSet as $rule) {
|
||
|
$this->_rules[$spec][] = $this->_getRule($rule);
|
||
|
}
|
||
|
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set a static rule for a spec. This is a single string value
|
||
|
*
|
||
|
* @param string $name
|
||
|
* @param string $value
|
||
|
* @return Zend_Filter_Inflector
|
||
|
*/
|
||
|
public function setStaticRule($name, $value)
|
||
|
{
|
||
|
$name = $this->_normalizeSpec($name);
|
||
|
$this->_rules[$name] = (string) $value;
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set Static Rule Reference.
|
||
|
*
|
||
|
* This allows a consuming class to pass a property or variable
|
||
|
* in to be referenced when its time to build the output string from the
|
||
|
* target.
|
||
|
*
|
||
|
* @param string $name
|
||
|
* @param mixed $reference
|
||
|
* @return Zend_Filter_Inflector
|
||
|
*/
|
||
|
public function setStaticRuleReference($name, &$reference)
|
||
|
{
|
||
|
$name = $this->_normalizeSpec($name);
|
||
|
$this->_rules[$name] =& $reference;
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Inflect
|
||
|
*
|
||
|
* @param string|array $source
|
||
|
* @return string
|
||
|
*/
|
||
|
public function filter($source)
|
||
|
{
|
||
|
// clean source
|
||
|
foreach ( (array) $source as $sourceName => $sourceValue) {
|
||
|
$source[ltrim($sourceName, ':')] = $sourceValue;
|
||
|
}
|
||
|
|
||
|
$pregQuotedTargetReplacementIdentifier = preg_quote($this->_targetReplacementIdentifier, '#');
|
||
|
$processedParts = array();
|
||
|
|
||
|
foreach ($this->_rules as $ruleName => $ruleValue) {
|
||
|
if (isset($source[$ruleName])) {
|
||
|
if (is_string($ruleValue)) {
|
||
|
// overriding the set rule
|
||
|
$processedParts['#'.$pregQuotedTargetReplacementIdentifier.$ruleName.'#'] = str_replace('\\', '\\\\', $source[$ruleName]);
|
||
|
} elseif (is_array($ruleValue)) {
|
||
|
$processedPart = $source[$ruleName];
|
||
|
foreach ($ruleValue as $ruleFilter) {
|
||
|
$processedPart = $ruleFilter->filter($processedPart);
|
||
|
}
|
||
|
$processedParts['#'.$pregQuotedTargetReplacementIdentifier.$ruleName.'#'] = str_replace('\\', '\\\\', $processedPart);
|
||
|
}
|
||
|
} elseif (is_string($ruleValue)) {
|
||
|
$processedParts['#'.$pregQuotedTargetReplacementIdentifier.$ruleName.'#'] = str_replace('\\', '\\\\', $ruleValue);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// all of the values of processedParts would have been str_replace('\\', '\\\\', ..)'d to disable preg_replace backreferences
|
||
|
$inflectedTarget = preg_replace(array_keys($processedParts), array_values($processedParts), $this->_target);
|
||
|
|
||
|
if ($this->_throwTargetExceptionsOn && (preg_match('#(?='.$pregQuotedTargetReplacementIdentifier.'[A-Za-z]{1})#', $inflectedTarget) == true)) {
|
||
|
require_once 'Zend/Filter/Exception.php';
|
||
|
throw new Zend_Filter_Exception('A replacement identifier ' . $this->_targetReplacementIdentifier . ' was found inside the inflected target, perhaps a rule was not satisfied with a target source? Unsatisfied inflected target: ' . $inflectedTarget);
|
||
|
}
|
||
|
|
||
|
return $inflectedTarget;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Normalize spec string
|
||
|
*
|
||
|
* @param string $spec
|
||
|
* @return string
|
||
|
*/
|
||
|
protected function _normalizeSpec($spec)
|
||
|
{
|
||
|
return ltrim((string) $spec, ':&');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Resolve named filters and convert them to filter objects.
|
||
|
*
|
||
|
* @param string $rule
|
||
|
* @return Zend_Filter_Interface
|
||
|
*/
|
||
|
protected function _getRule($rule)
|
||
|
{
|
||
|
if ($rule instanceof Zend_Filter_Interface) {
|
||
|
return $rule;
|
||
|
}
|
||
|
|
||
|
$rule = (string) $rule;
|
||
|
|
||
|
$className = $this->getPluginLoader()->load($rule);
|
||
|
$ruleObject = new $className();
|
||
|
if (!$ruleObject instanceof Zend_Filter_Interface) {
|
||
|
require_once 'Zend/Filter/Exception.php';
|
||
|
throw new Zend_Filter_Exception('No class named ' . $rule . ' implementing Zend_Filter_Interface could be found');
|
||
|
}
|
||
|
|
||
|
return $ruleObject;
|
||
|
}
|
||
|
}
|