File indexing completed on 2024-05-12 06:02:33

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 }