File indexing completed on 2025-01-26 05:29:30
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Filter 0017 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0018 * @license http://framework.zend.com/license/new-bsd New BSD License 0019 * @version $Id$ 0020 */ 0021 0022 /** 0023 * @see Zend_Filter 0024 * @see Zend_Filter_Interface 0025 */ 0026 // require_once 'Zend/Filter.php'; 0027 0028 /** 0029 * @see Zend_Loader_PluginLoader 0030 */ 0031 // require_once 'Zend/Loader/PluginLoader.php'; 0032 0033 /** 0034 * Filter chain for string inflection 0035 * 0036 * @category Zend 0037 * @package Zend_Filter 0038 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0039 * @license http://framework.zend.com/license/new-bsd New BSD License 0040 */ 0041 class Zend_Filter_Inflector implements Zend_Filter_Interface 0042 { 0043 /** 0044 * @var Zend_Loader_PluginLoader_Interface 0045 */ 0046 protected $_pluginLoader = null; 0047 0048 /** 0049 * @var string 0050 */ 0051 protected $_target = null; 0052 0053 /** 0054 * @var bool 0055 */ 0056 protected $_throwTargetExceptionsOn = true; 0057 0058 /** 0059 * @var string 0060 */ 0061 protected $_targetReplacementIdentifier = ':'; 0062 0063 /** 0064 * @var array 0065 */ 0066 protected $_rules = array(); 0067 0068 /** 0069 * Constructor 0070 * 0071 * @param string|array $options Options to set 0072 */ 0073 public function __construct($options = null) 0074 { 0075 if ($options instanceof Zend_Config) { 0076 $options = $options->toArray(); 0077 } else if (!is_array($options)) { 0078 $options = func_get_args(); 0079 $temp = array(); 0080 0081 if (!empty($options)) { 0082 $temp['target'] = array_shift($options); 0083 } 0084 0085 if (!empty($options)) { 0086 $temp['rules'] = array_shift($options); 0087 } 0088 0089 if (!empty($options)) { 0090 $temp['throwTargetExceptionsOn'] = array_shift($options); 0091 } 0092 0093 if (!empty($options)) { 0094 $temp['targetReplacementIdentifier'] = array_shift($options); 0095 } 0096 0097 $options = $temp; 0098 } 0099 0100 $this->setOptions($options); 0101 } 0102 0103 /** 0104 * Retreive PluginLoader 0105 * 0106 * @return Zend_Loader_PluginLoader_Interface 0107 */ 0108 public function getPluginLoader() 0109 { 0110 if (!$this->_pluginLoader instanceof Zend_Loader_PluginLoader_Interface) { 0111 $this->_pluginLoader = new Zend_Loader_PluginLoader(array('Zend_Filter_' => 'Zend/Filter/'), __CLASS__); 0112 } 0113 0114 return $this->_pluginLoader; 0115 } 0116 0117 /** 0118 * Set PluginLoader 0119 * 0120 * @param Zend_Loader_PluginLoader_Interface $pluginLoader 0121 * @return Zend_Filter_Inflector 0122 */ 0123 public function setPluginLoader(Zend_Loader_PluginLoader_Interface $pluginLoader) 0124 { 0125 $this->_pluginLoader = $pluginLoader; 0126 return $this; 0127 } 0128 0129 /** 0130 * Use Zend_Config object to set object state 0131 * 0132 * @deprecated Use setOptions() instead 0133 * @param Zend_Config $config 0134 * @return Zend_Filter_Inflector 0135 */ 0136 public function setConfig(Zend_Config $config) 0137 { 0138 return $this->setOptions($config); 0139 } 0140 0141 /** 0142 * Set options 0143 * 0144 * @param array $options 0145 * @return Zend_Filter_Inflector 0146 */ 0147 public function setOptions($options) { 0148 if ($options instanceof Zend_Config) { 0149 $options = $options->toArray(); 0150 } 0151 0152 // Set Präfix Path 0153 if (array_key_exists('filterPrefixPath', $options)) { 0154 if (!is_scalar($options['filterPrefixPath'])) { 0155 foreach ($options['filterPrefixPath'] as $prefix => $path) { 0156 $this->addFilterPrefixPath($prefix, $path); 0157 } 0158 } 0159 } 0160 0161 if (array_key_exists('throwTargetExceptionsOn', $options)) { 0162 $this->setThrowTargetExceptionsOn($options['throwTargetExceptionsOn']); 0163 } 0164 0165 if (array_key_exists('targetReplacementIdentifier', $options)) { 0166 $this->setTargetReplacementIdentifier($options['targetReplacementIdentifier']); 0167 } 0168 0169 if (array_key_exists('target', $options)) { 0170 $this->setTarget($options['target']); 0171 } 0172 0173 if (array_key_exists('rules', $options)) { 0174 $this->addRules($options['rules']); 0175 } 0176 0177 return $this; 0178 } 0179 0180 /** 0181 * Convienence method to add prefix and path to PluginLoader 0182 * 0183 * @param string $prefix 0184 * @param string $path 0185 * @return Zend_Filter_Inflector 0186 */ 0187 public function addFilterPrefixPath($prefix, $path) 0188 { 0189 $this->getPluginLoader()->addPrefixPath($prefix, $path); 0190 return $this; 0191 } 0192 0193 /** 0194 * Set Whether or not the inflector should throw an exception when a replacement 0195 * identifier is still found within an inflected target. 0196 * 0197 * @param bool $throwTargetExceptions 0198 * @return Zend_Filter_Inflector 0199 */ 0200 public function setThrowTargetExceptionsOn($throwTargetExceptionsOn) 0201 { 0202 $this->_throwTargetExceptionsOn = ($throwTargetExceptionsOn == true) ? true : false; 0203 return $this; 0204 } 0205 0206 /** 0207 * Will exceptions be thrown? 0208 * 0209 * @return bool 0210 */ 0211 public function isThrowTargetExceptionsOn() 0212 { 0213 return $this->_throwTargetExceptionsOn; 0214 } 0215 0216 /** 0217 * Set the Target Replacement Identifier, by default ':' 0218 * 0219 * @param string $targetReplacementIdentifier 0220 * @return Zend_Filter_Inflector 0221 */ 0222 public function setTargetReplacementIdentifier($targetReplacementIdentifier) 0223 { 0224 if ($targetReplacementIdentifier) { 0225 $this->_targetReplacementIdentifier = (string) $targetReplacementIdentifier; 0226 } 0227 0228 return $this; 0229 } 0230 0231 /** 0232 * Get Target Replacement Identifier 0233 * 0234 * @return string 0235 */ 0236 public function getTargetReplacementIdentifier() 0237 { 0238 return $this->_targetReplacementIdentifier; 0239 } 0240 0241 /** 0242 * Set a Target 0243 * ex: 'scripts/:controller/:action.:suffix' 0244 * 0245 * @param string 0246 * @return Zend_Filter_Inflector 0247 */ 0248 public function setTarget($target) 0249 { 0250 $this->_target = (string) $target; 0251 return $this; 0252 } 0253 0254 /** 0255 * Retrieve target 0256 * 0257 * @return string 0258 */ 0259 public function getTarget() 0260 { 0261 return $this->_target; 0262 } 0263 0264 /** 0265 * Set Target Reference 0266 * 0267 * @param reference $target 0268 * @return Zend_Filter_Inflector 0269 */ 0270 public function setTargetReference(&$target) 0271 { 0272 $this->_target =& $target; 0273 return $this; 0274 } 0275 0276 /** 0277 * SetRules() is the same as calling addRules() with the exception that it 0278 * clears the rules before adding them. 0279 * 0280 * @param array $rules 0281 * @return Zend_Filter_Inflector 0282 */ 0283 public function setRules(Array $rules) 0284 { 0285 $this->clearRules(); 0286 $this->addRules($rules); 0287 return $this; 0288 } 0289 0290 /** 0291 * AddRules(): multi-call to setting filter rules. 0292 * 0293 * If prefixed with a ":" (colon), a filter rule will be added. If not 0294 * prefixed, a static replacement will be added. 0295 * 0296 * ex: 0297 * array( 0298 * ':controller' => array('CamelCaseToUnderscore','StringToLower'), 0299 * ':action' => array('CamelCaseToUnderscore','StringToLower'), 0300 * 'suffix' => 'phtml' 0301 * ); 0302 * 0303 * @param array 0304 * @return Zend_Filter_Inflector 0305 */ 0306 public function addRules(Array $rules) 0307 { 0308 $keys = array_keys($rules); 0309 foreach ($keys as $spec) { 0310 if ($spec[0] == ':') { 0311 $this->addFilterRule($spec, $rules[$spec]); 0312 } else { 0313 $this->setStaticRule($spec, $rules[$spec]); 0314 } 0315 } 0316 0317 return $this; 0318 } 0319 0320 /** 0321 * Get rules 0322 * 0323 * By default, returns all rules. If a $spec is provided, will return those 0324 * rules if found, false otherwise. 0325 * 0326 * @param string $spec 0327 * @return array|false 0328 */ 0329 public function getRules($spec = null) 0330 { 0331 if (null !== $spec) { 0332 $spec = $this->_normalizeSpec($spec); 0333 if (isset($this->_rules[$spec])) { 0334 return $this->_rules[$spec]; 0335 } 0336 return false; 0337 } 0338 0339 return $this->_rules; 0340 } 0341 0342 /** 0343 * getRule() returns a rule set by setFilterRule(), a numeric index must be provided 0344 * 0345 * @param string $spec 0346 * @param int $index 0347 * @return Zend_Filter_Interface|false 0348 */ 0349 public function getRule($spec, $index) 0350 { 0351 $spec = $this->_normalizeSpec($spec); 0352 if (isset($this->_rules[$spec]) && is_array($this->_rules[$spec])) { 0353 if (isset($this->_rules[$spec][$index])) { 0354 return $this->_rules[$spec][$index]; 0355 } 0356 } 0357 return false; 0358 } 0359 0360 /** 0361 * ClearRules() clears the rules currently in the inflector 0362 * 0363 * @return Zend_Filter_Inflector 0364 */ 0365 public function clearRules() 0366 { 0367 $this->_rules = array(); 0368 return $this; 0369 } 0370 0371 /** 0372 * Set a filtering rule for a spec. $ruleSet can be a string, Filter object 0373 * or an array of strings or filter objects. 0374 * 0375 * @param string $spec 0376 * @param array|string|Zend_Filter_Interface $ruleSet 0377 * @return Zend_Filter_Inflector 0378 */ 0379 public function setFilterRule($spec, $ruleSet) 0380 { 0381 $spec = $this->_normalizeSpec($spec); 0382 $this->_rules[$spec] = array(); 0383 return $this->addFilterRule($spec, $ruleSet); 0384 } 0385 0386 /** 0387 * Add a filter rule for a spec 0388 * 0389 * @param mixed $spec 0390 * @param mixed $ruleSet 0391 * @return void 0392 */ 0393 public function addFilterRule($spec, $ruleSet) 0394 { 0395 $spec = $this->_normalizeSpec($spec); 0396 if (!isset($this->_rules[$spec])) { 0397 $this->_rules[$spec] = array(); 0398 } 0399 0400 if (!is_array($ruleSet)) { 0401 $ruleSet = array($ruleSet); 0402 } 0403 0404 if (is_string($this->_rules[$spec])) { 0405 $temp = $this->_rules[$spec]; 0406 $this->_rules[$spec] = array(); 0407 $this->_rules[$spec][] = $temp; 0408 } 0409 0410 foreach ($ruleSet as $rule) { 0411 $this->_rules[$spec][] = $this->_getRule($rule); 0412 } 0413 0414 return $this; 0415 } 0416 0417 /** 0418 * Set a static rule for a spec. This is a single string value 0419 * 0420 * @param string $name 0421 * @param string $value 0422 * @return Zend_Filter_Inflector 0423 */ 0424 public function setStaticRule($name, $value) 0425 { 0426 $name = $this->_normalizeSpec($name); 0427 $this->_rules[$name] = (string) $value; 0428 return $this; 0429 } 0430 0431 /** 0432 * Set Static Rule Reference. 0433 * 0434 * This allows a consuming class to pass a property or variable 0435 * in to be referenced when its time to build the output string from the 0436 * target. 0437 * 0438 * @param string $name 0439 * @param mixed $reference 0440 * @return Zend_Filter_Inflector 0441 */ 0442 public function setStaticRuleReference($name, &$reference) 0443 { 0444 $name = $this->_normalizeSpec($name); 0445 $this->_rules[$name] =& $reference; 0446 return $this; 0447 } 0448 0449 /** 0450 * Inflect 0451 * 0452 * @param string|array $source 0453 * @return string 0454 */ 0455 public function filter($source) 0456 { 0457 // clean source 0458 foreach ( (array) $source as $sourceName => $sourceValue) { 0459 $source[ltrim($sourceName, ':')] = $sourceValue; 0460 } 0461 0462 $pregQuotedTargetReplacementIdentifier = preg_quote($this->_targetReplacementIdentifier, '#'); 0463 $processedParts = array(); 0464 0465 foreach ($this->_rules as $ruleName => $ruleValue) { 0466 if (isset($source[$ruleName])) { 0467 if (is_string($ruleValue)) { 0468 // overriding the set rule 0469 $processedParts['#'.$pregQuotedTargetReplacementIdentifier.$ruleName.'#'] = str_replace('\\', '\\\\', $source[$ruleName]); 0470 } elseif (is_array($ruleValue)) { 0471 $processedPart = $source[$ruleName]; 0472 foreach ($ruleValue as $ruleFilter) { 0473 $processedPart = $ruleFilter->filter($processedPart); 0474 } 0475 $processedParts['#'.$pregQuotedTargetReplacementIdentifier.$ruleName.'#'] = str_replace('\\', '\\\\', $processedPart); 0476 } 0477 } elseif (is_string($ruleValue)) { 0478 $processedParts['#'.$pregQuotedTargetReplacementIdentifier.$ruleName.'#'] = str_replace('\\', '\\\\', $ruleValue); 0479 } 0480 } 0481 0482 // all of the values of processedParts would have been str_replace('\\', '\\\\', ..)'d to disable preg_replace backreferences 0483 $inflectedTarget = preg_replace(array_keys($processedParts), array_values($processedParts), $this->_target); 0484 0485 if ($this->_throwTargetExceptionsOn && (preg_match('#(?='.$pregQuotedTargetReplacementIdentifier.'[A-Za-z]{1})#', $inflectedTarget) == true)) { 0486 // require_once 'Zend/Filter/Exception.php'; 0487 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); 0488 } 0489 0490 return $inflectedTarget; 0491 } 0492 0493 /** 0494 * Normalize spec string 0495 * 0496 * @param string $spec 0497 * @return string 0498 */ 0499 protected function _normalizeSpec($spec) 0500 { 0501 return ltrim((string) $spec, ':&'); 0502 } 0503 0504 /** 0505 * Resolve named filters and convert them to filter objects. 0506 * 0507 * @param string $rule 0508 * @return Zend_Filter_Interface 0509 */ 0510 protected function _getRule($rule) 0511 { 0512 if ($rule instanceof Zend_Filter_Interface) { 0513 return $rule; 0514 } 0515 0516 $rule = (string) $rule; 0517 0518 $className = $this->getPluginLoader()->load($rule); 0519 $ruleObject = new $className(); 0520 if (!$ruleObject instanceof Zend_Filter_Interface) { 0521 // require_once 'Zend/Filter/Exception.php'; 0522 throw new Zend_Filter_Exception('No class named ' . $rule . ' implementing Zend_Filter_Interface could be found'); 0523 } 0524 0525 return $ruleObject; 0526 } 0527 }