Blame | Letzte Änderung | Log anzeigen | RSS feed
<?php/** This file is part of the symfony package.* (c) Fabien Potencier <fabien.potencier@symfony-project.com>** For the full copyright and license information, please view the LICENSE* file that was distributed with this source code.*//*** sfValidatorFromDescription converts a string to a validator.** @package symfony* @subpackage validator* @author Fabien Potencier <fabien.potencier@symfony-project.com>* @version SVN: $Id: sfValidatorFromDescription.class.php 28700 2010-03-23 11:57:16Z fabien $*/class sfValidatorFromDescription extends sfValidatorDecorator{protected$tokens = array(),$string = '';/*** @see sfValidatorBase*/public function __construct($string, $options = array(), $messages = array()){$this->string = $string;$this->tokens = $this->tokenize($string);parent::__construct($options, $messages);}/*** Returns a PHP representation for the validator.** This PHP representation can be evaled to return the object validator.** This is mainly useful to cache the result of the validator string parsing.** @return string The PHP representation for the validator*/public function asPhp(){return $this->reduceTokens($this->tokens, 'asPhp');}/*** @see sfValidatorDecorator*/public function getValidator(){if (null === $this->validator){$this->validator = $this->reduceTokens($this->tokens, 'getValidator');}return $this->validator;}/*** Tokenizes a validator string to a list of tokens in RPN.** @param string $string A validator string** @return array An array of tokens*/protected function tokenize($string){$tokens = array();$len = strlen($string);$i = 0;while ($i < $len){if (preg_match('/^([a-z0-9_\-]+)\s*(<=|>=|<|>|==|!=)/i', substr($string, $i), $match)){// schema compare validator$i += strlen($match[0]);$leftField = $match[1];$operator = $match[2];// arguments (optional)$arguments = $this->parseArguments($string, $i);// rightFieldif (!preg_match('/\s*([a-z0-9_\-]+)/', substr($string, $i), $match)){throw new DomainException('Parsing problem.');}$i += strlen($match[0]);$rightField = $match[1];$tokens[] = new sfValidatorFDToken('sfValidatorSchemaCompare', array($leftField, $operator, $rightField, $arguments[0], isset($arguments[1]) ? $arguments[1] : array()));}else if (preg_match('/^(and|or)/i', substr($string, $i), $match)){// all, any validador$i += strlen($match[0]);// arguments (optional)$arguments = $this->parseArguments($string, $i);$tokens[] = new sfValidatorFDTokenOperator(strtolower($match[1]), $arguments);}else if (preg_match('/^(?:([a-z0-9_\-]+)\:)?([a-z0-9_\-]+)/i', substr($string, $i), $match)){// single validator (optionally filtered)$i += strlen($match[0]);$class = 'sfValidator'.$match[2];$arguments = $this->parseArguments($string, $i);$token = new sfValidatorFDToken($class, array($arguments[0], isset($arguments[1]) ? $arguments[1] : array()));if ($match[1]){$token = new sfValidatorFDTokenFilter($match[1], $token);}$tokens[] = $token;}else if ('(' == $string[$i]){$tokens[] = new sfValidatorFDTokenLeftBracket();++$i;}else if (')' == $string[$i]){$tokens[] = new sfValidatorFDTokenRightBracket();++$i;}else if (in_array($string[$i], array(' ', "\t", "\r", "\n"))){++$i;}else{throw new DomainException(sprintf('Unable to parse string (%s).', $string));}}return $this->convertInfixToRpn($tokens);}/*** Parses validator arguments.** @param string $string The string to parse* @param integer $i The indice to start the parsing** @return array An array of parameters*/protected function parseArguments($string, &$i){$len = strlen($string);if ($i + 1 > $len || '(' != $string[$i]){return array(array(), array());}++$i;$args = '';$opened = 0;while ($i < $len){if ('(' == $string[$i]){++$opened;}else if (')' == $string[$i]){if (!$opened){break;}--$opened;}$args .= $string[$i++];}++$i;return sfYamlInline::load('['.(!$args ? '{}' : $args).']');}/*** Converts a token array from an infix notation to a RPN.** @param array $tokens An array of tokens in infix notation** @return array An array of token in RPN*/protected function convertInfixToRpn($tokens){$outputStack = array();$operatorStack = array();$precedences = array('and' => 2, 'or' => 1, '(' => 0);// based on the shunting yard algorithmforeach ($tokens as $token){switch (get_class($token)){case 'sfValidatorFDToken':$outputStack[] = $token;break;case 'sfValidatorFDTokenLeftBracket':$operatorStack[] = $token;break;case 'sfValidatorFDTokenRightBracket':while (!$operatorStack[count($operatorStack) - 1] instanceof sfValidatorFDTokenLeftBracket){$outputStack[] = array_pop($operatorStack);}array_pop($operatorStack);break;case 'sfValidatorFDTokenOperator':while (count($operatorStack) && $precedences[$token->__toString()] <= $precedences[$operatorStack[count($operatorStack) - 1]->__toString()]){$outputStack[] = array_pop($operatorStack);}$operatorStack[] = $token;break;default:$outputStack[] = $token;}}while (count($operatorStack)){$token = array_pop($operatorStack);if ($token instanceof sfValidatorFDTokenLeftBracket || $token instanceof sfValidatorFDTokenRightBracket){throw new DomainException(sprintf('Uneven parenthesis in string (%s).', $this->string));}$outputStack[] = $token;}return $outputStack;}/*** Reduces tokens to a single token and convert it with the given method.** @param array $tokens An array of tokens* @param string $method The method name to execute on each token** @return mixed A single validator representation*/protected function reduceTokens($tokens, $method){if (1 == count($tokens)){return $tokens[0]->$method();}// reduce to a single validatorwhile (count($tokens) > 1){$i = 0;while (isset($tokens[$i]) && !$tokens[$i] instanceof sfValidatorFDTokenOperator){$i++;}$tokens[$i] = $tokens[$i]->$method($tokens[$i - 2], $tokens[$i - 1]);unset($tokens[$i - 1], $tokens[$i - 2]);$tokens = array_values($tokens);}return $tokens[0];}}class sfValidatorFDToken{protected$class,$arguments;public function __construct($class, $arguments = array()){$this->class = $class;$this->arguments = $arguments;}public function asPhp(){return sprintf('new %s(%s)', $this->class, implode(', ', array_map(create_function('$a', 'return var_export($a, true);'), $this->arguments)));}public function getValidator(){$reflection = new ReflectionClass($this->class);return $reflection->newInstanceArgs($this->arguments);}}class sfValidatorFDTokenFilter{protected$field,$token;public function __construct($field, sfValidatorFDToken $token){$this->field = $field;$this->token = $token;}public function asPhp(){return sprintf('new sfValidatorSchemaFilter(\'%s\', %s)', $this->field, $this->token->asPhp());}public function getValidator(){return new sfValidatorSchemaFilter($this->field, $this->token->getValidator());}}class sfValidatorFDTokenOperator{protected$class,$operator,$token;public function __construct($operator, $arguments = array()){$this->operator = $operator;$this->arguments = $arguments;$this->class = 'or' == $operator ? 'sfValidatorOr' : 'sfValidatorAnd';}public function __toString(){return $this->operator;}public function asPhp($tokenLeft, $tokenRight){return sprintf('new %s(array(%s, %s), %s)',$this->class,is_object($tokenLeft) && in_array(get_class($tokenLeft), array('sfValidatorFDToken', 'sfValidatorFDTokenFilter')) ? $tokenLeft->asPhp() : $tokenLeft,is_object($tokenRight) && in_array(get_class($tokenRight), array('sfValidatorFDToken', 'sfValidatorFDTokenFilter')) ? $tokenRight->asPhp() : $tokenRight,implode(', ', array_map(create_function('$a', 'return var_export($a, true);'), $this->arguments)));}public function getValidator($tokenLeft, $tokenRight){$reflection = new ReflectionClass($this->class);$validators = array(in_array(get_class($tokenLeft), array('sfValidatorFDToken', 'sfValidatorFDTokenFilter')) ? $tokenLeft->getValidator() : $tokenLeft,in_array(get_class($tokenRight), array('sfValidatorFDToken', 'sfValidatorFDTokenFilter')) ? $tokenRight->getValidator() : $tokenRight,);return $reflection->newInstanceArgs(array_merge(array($validators), $this->arguments));}}class sfValidatorFDTokenLeftBracket{public function __toString(){return '(';}}class sfValidatorFDTokenRightBracket{public function __toString(){return ')';}}