* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * sfValidatorSchema represents an array of fields. * * A field is a named validator. * * @package symfony * @subpackage validator * @author Fabien Potencier * @version SVN: $Id: sfValidatorSchema.class.php 22446 2009-09-26 07:55:47Z fabien $ */ class sfValidatorSchema extends sfValidatorBase implements ArrayAccess { protected $fields = array(), $preValidator = null, $postValidator = null; /** * Constructor. * * The first argument can be: * * * null * * an array of named sfValidatorBase instances * * @param mixed $fields Initial fields * @param array $options An array of options * @param array $messages An array of error messages * * @see sfValidatorBase */ public function __construct($fields = null, $options = array(), $messages = array()) { if (is_array($fields)) { foreach ($fields as $name => $validator) { $this[$name] = $validator; } } else if (null !== $fields) { throw new InvalidArgumentException('sfValidatorSchema constructor takes an array of sfValidatorBase objects.'); } parent::__construct($options, $messages); } /** * Configures the validator. * * Available options: * * * allow_extra_fields: if false, the validator adds an error if extra fields are given in the input array of values (default to false) * * filter_extra_fields: if true, the validator filters extra fields from the returned array of cleaned values (default to true) * * Available error codes: * * * extra_fields * * @param array $options An array of options * @param array $messages An array of error messages * * @see sfValidatorBase */ protected function configure($options = array(), $messages = array()) { $this->addOption('allow_extra_fields', false); $this->addOption('filter_extra_fields', true); $this->addMessage('extra_fields', 'Unexpected extra form field named "%field%".'); $this->addMessage('post_max_size', 'The form submission cannot be processed. It probably means that you have uploaded a file that is too big.'); } /** * @see sfValidatorBase */ public function clean($values) { return $this->doClean($values); } /** * @see sfValidatorBase */ protected function doClean($values) { if (null === $values) { $values = array(); } if (!is_array($values)) { throw new InvalidArgumentException('You must pass an array parameter to the clean() method'); } $clean = array(); $unused = array_keys($this->fields); $errorSchema = new sfValidatorErrorSchema($this); // check that post_max_size has not been reached if (isset($_SERVER['CONTENT_LENGTH']) && (int) $_SERVER['CONTENT_LENGTH'] > $this->getBytes(ini_get('post_max_size'))) { $errorSchema->addError(new sfValidatorError($this, 'post_max_size')); throw $errorSchema; } // pre validator try { $this->preClean($values); } catch (sfValidatorErrorSchema $e) { $errorSchema->addErrors($e); } catch (sfValidatorError $e) { $errorSchema->addError($e); } // validate given values foreach ($values as $name => $value) { // field exists in our schema? if (!array_key_exists($name, $this->fields)) { if (!$this->options['allow_extra_fields']) { $errorSchema->addError(new sfValidatorError($this, 'extra_fields', array('field' => $name))); } else if (!$this->options['filter_extra_fields']) { $clean[$name] = $value; } continue; } unset($unused[array_search($name, $unused, true)]); // validate value try { $clean[$name] = $this->fields[$name]->clean($value); } catch (sfValidatorError $e) { $clean[$name] = null; $errorSchema->addError($e, (string) $name); } } // are non given values required? foreach ($unused as $name) { // validate value try { $clean[$name] = $this->fields[$name]->clean(null); } catch (sfValidatorError $e) { $clean[$name] = null; $errorSchema->addError($e, (string) $name); } } // post validator try { $clean = $this->postClean($clean); } catch (sfValidatorErrorSchema $e) { $errorSchema->addErrors($e); } catch (sfValidatorError $e) { $errorSchema->addError($e); } if (count($errorSchema)) { throw $errorSchema; } return $clean; } /** * Cleans the input values. * * This method is the first validator executed by doClean(). * * It executes the validator returned by getPreValidator() * on the global array of values. * * @param array $values The input values * * @throws sfValidatorError */ public function preClean($values) { if (null === $validator = $this->getPreValidator()) { return; } $validator->clean($values); } /** * Cleans the input values. * * This method is the last validator executed by doClean(). * * It executes the validator returned by getPostValidator() * on the global array of cleaned values. * * @param array $values The input values * * @throws sfValidatorError */ public function postClean($values) { if (null === $validator = $this->getPostValidator()) { return $values; } return $validator->clean($values); } /** * Sets the pre validator. * * @param sfValidatorBase $validator An sfValidatorBase instance * * @return sfValidatorBase The current validator instance */ public function setPreValidator(sfValidatorBase $validator) { $this->preValidator = clone $validator; return $this; } /** * Returns the pre validator. * * @return sfValidatorBase A sfValidatorBase instance */ public function getPreValidator() { return $this->preValidator; } /** * Sets the post validator. * * @param sfValidatorBase $validator An sfValidatorBase instance * * @return sfValidatorBase The current validator instance */ public function setPostValidator(sfValidatorBase $validator) { $this->postValidator = clone $validator; return $this; } /** * Returns the post validator. * * @return sfValidatorBase An sfValidatorBase instance */ public function getPostValidator() { return $this->postValidator; } /** * Returns true if the schema has a field with the given name (implements the ArrayAccess interface). * * @param string $name The field name * * @return bool true if the schema has a field with the given name, false otherwise */ public function offsetExists($name) { return isset($this->fields[$name]); } /** * Gets the field associated with the given name (implements the ArrayAccess interface). * * @param string $name The field name * * @return sfValidatorBase The sfValidatorBase instance associated with the given name, null if it does not exist */ public function offsetGet($name) { return isset($this->fields[$name]) ? $this->fields[$name] : null; } /** * Sets a field (implements the ArrayAccess interface). * * @param string $name The field name * @param sfValidatorBase $validator An sfValidatorBase instance */ public function offsetSet($name, $validator) { if (!$validator instanceof sfValidatorBase) { throw new InvalidArgumentException('A field must be an instance of sfValidatorBase.'); } $this->fields[$name] = clone $validator; } /** * Removes a field by name (implements the ArrayAccess interface). * * @param string $name */ public function offsetUnset($name) { unset($this->fields[$name]); } /** * Returns an array of fields. * * @return sfValidatorBase An array of sfValidatorBase instances */ public function getFields() { return $this->fields; } /** * @see sfValidatorBase */ public function asString($indent = 0) { throw new Exception('Unable to convert a sfValidatorSchema to string.'); } public function __clone() { foreach ($this->fields as $name => $field) { $this->fields[$name] = clone $field; } if (null !== $this->preValidator) { $this->preValidator = clone $this->preValidator; } if (null !== $this->postValidator) { $this->postValidator = clone $this->postValidator; } } protected function getBytes($value) { $value = trim($value); switch (strtolower($value[strlen($value) - 1])) { // The 'G' modifier is available since PHP 5.1.0 case 'g': $value *= 1024; case 'm': $value *= 1024; case 'k': $value *= 1024; } return $value; } }