mirror of
https://github.com/OpenXE-org/OpenXE.git
synced 2025-02-11 20:20:10 +01:00
574 lines
16 KiB
PHP
574 lines
16 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @see https://github.com/laminas/laminas-validator for the canonical source repository
|
|
* @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
|
|
* @license https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
|
|
*/
|
|
|
|
namespace Laminas\Validator;
|
|
|
|
use Laminas\Stdlib\ArrayUtils;
|
|
use Traversable;
|
|
|
|
abstract class AbstractValidator implements
|
|
Translator\TranslatorAwareInterface,
|
|
ValidatorInterface
|
|
{
|
|
/**
|
|
* The value to be validated
|
|
*
|
|
* @var mixed
|
|
*/
|
|
protected $value;
|
|
|
|
/**
|
|
* Default translation object for all validate objects
|
|
* @var Translator\TranslatorInterface
|
|
*/
|
|
protected static $defaultTranslator;
|
|
|
|
/**
|
|
* Default text domain to be used with translator
|
|
* @var string
|
|
*/
|
|
protected static $defaultTranslatorTextDomain = 'default';
|
|
|
|
/**
|
|
* Limits the maximum returned length of an error message
|
|
*
|
|
* @var int
|
|
*/
|
|
protected static $messageLength = -1;
|
|
|
|
protected $abstractOptions = [
|
|
'messages' => [], // Array of validation failure messages
|
|
'messageTemplates' => [], // Array of validation failure message templates
|
|
'messageVariables' => [], // Array of additional variables available for validation failure messages
|
|
'translator' => null, // Translation object to used -> Translator\TranslatorInterface
|
|
'translatorTextDomain' => null, // Translation text domain
|
|
'translatorEnabled' => true, // Is translation enabled?
|
|
'valueObscured' => false, // Flag indicating whether or not value should be obfuscated
|
|
// in error messages
|
|
];
|
|
|
|
/**
|
|
* Abstract constructor for all validators
|
|
* A validator should accept following parameters:
|
|
* - nothing f.e. Validator()
|
|
* - one or multiple scalar values f.e. Validator($first, $second, $third)
|
|
* - an array f.e. Validator(array($first => 'first', $second => 'second', $third => 'third'))
|
|
* - an instance of Traversable f.e. Validator($config_instance)
|
|
*
|
|
* @param array|Traversable $options
|
|
*/
|
|
public function __construct($options = null)
|
|
{
|
|
// The abstract constructor allows no scalar values
|
|
if ($options instanceof Traversable) {
|
|
$options = ArrayUtils::iteratorToArray($options);
|
|
}
|
|
|
|
if (isset($this->messageTemplates)) {
|
|
$this->abstractOptions['messageTemplates'] = $this->messageTemplates;
|
|
}
|
|
|
|
if (isset($this->messageVariables)) {
|
|
$this->abstractOptions['messageVariables'] = $this->messageVariables;
|
|
}
|
|
|
|
if (is_array($options)) {
|
|
$this->setOptions($options);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns an option
|
|
*
|
|
* @param string $option Option to be returned
|
|
* @return mixed Returned option
|
|
* @throws Exception\InvalidArgumentException
|
|
*/
|
|
public function getOption($option)
|
|
{
|
|
if (array_key_exists($option, $this->abstractOptions)) {
|
|
return $this->abstractOptions[$option];
|
|
}
|
|
|
|
if (isset($this->options) && array_key_exists($option, $this->options)) {
|
|
return $this->options[$option];
|
|
}
|
|
|
|
throw new Exception\InvalidArgumentException("Invalid option '$option'");
|
|
}
|
|
|
|
/**
|
|
* Returns all available options
|
|
*
|
|
* @return array Array with all available options
|
|
*/
|
|
public function getOptions()
|
|
{
|
|
$result = $this->abstractOptions;
|
|
if (isset($this->options)) {
|
|
$result += $this->options;
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Sets one or multiple options
|
|
*
|
|
* @param array|Traversable $options Options to set
|
|
* @throws Exception\InvalidArgumentException If $options is not an array or Traversable
|
|
* @return $this Provides fluid interface
|
|
*/
|
|
public function setOptions($options = [])
|
|
{
|
|
if (! is_array($options) && ! $options instanceof Traversable) {
|
|
throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable');
|
|
}
|
|
|
|
foreach ($options as $name => $option) {
|
|
$fname = 'set' . ucfirst($name);
|
|
$fname2 = 'is' . ucfirst($name);
|
|
if (($name !== 'setOptions') && method_exists($this, $name)) {
|
|
$this->{$name}($option);
|
|
} elseif (($fname !== 'setOptions') && method_exists($this, $fname)) {
|
|
$this->{$fname}($option);
|
|
} elseif (method_exists($this, $fname2)) {
|
|
$this->{$fname2}($option);
|
|
} elseif (isset($this->options)) {
|
|
$this->options[$name] = $option;
|
|
} else {
|
|
$this->abstractOptions[$name] = $option;
|
|
}
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Returns array of validation failure messages
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getMessages()
|
|
{
|
|
return array_unique($this->abstractOptions['messages'], SORT_REGULAR);
|
|
}
|
|
|
|
/**
|
|
* Invoke as command
|
|
*
|
|
* @param mixed $value
|
|
* @return bool
|
|
*/
|
|
public function __invoke($value)
|
|
{
|
|
return $this->isValid($value);
|
|
}
|
|
|
|
/**
|
|
* Returns an array of the names of variables that are used in constructing validation failure messages
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getMessageVariables()
|
|
{
|
|
return array_keys($this->abstractOptions['messageVariables']);
|
|
}
|
|
|
|
/**
|
|
* Returns the message templates from the validator
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getMessageTemplates()
|
|
{
|
|
return $this->abstractOptions['messageTemplates'];
|
|
}
|
|
|
|
/**
|
|
* Sets the validation failure message template for a particular key
|
|
*
|
|
* @param string $messageString
|
|
* @param string $messageKey OPTIONAL
|
|
* @return $this Provides a fluent interface
|
|
* @throws Exception\InvalidArgumentException
|
|
*/
|
|
public function setMessage($messageString, $messageKey = null)
|
|
{
|
|
if ($messageKey === null) {
|
|
$keys = array_keys($this->abstractOptions['messageTemplates']);
|
|
foreach ($keys as $key) {
|
|
$this->setMessage($messageString, $key);
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
if (! isset($this->abstractOptions['messageTemplates'][$messageKey])) {
|
|
throw new Exception\InvalidArgumentException("No message template exists for key '$messageKey'");
|
|
}
|
|
|
|
$this->abstractOptions['messageTemplates'][$messageKey] = $messageString;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Sets validation failure message templates given as an array, where the array keys are the message keys,
|
|
* and the array values are the message template strings.
|
|
*
|
|
* @param array $messages
|
|
* @return $this
|
|
*/
|
|
public function setMessages(array $messages)
|
|
{
|
|
foreach ($messages as $key => $message) {
|
|
$this->setMessage($message, $key);
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Magic function returns the value of the requested property, if and only if it is the value or a
|
|
* message variable.
|
|
*
|
|
* @param string $property
|
|
* @return mixed
|
|
* @throws Exception\InvalidArgumentException
|
|
*/
|
|
public function __get($property)
|
|
{
|
|
if ($property == 'value') {
|
|
return $this->value;
|
|
}
|
|
|
|
if (array_key_exists($property, $this->abstractOptions['messageVariables'])) {
|
|
$result = $this->abstractOptions['messageVariables'][$property];
|
|
if (is_array($result)) {
|
|
return $this->{key($result)}[current($result)];
|
|
}
|
|
return $this->{$result};
|
|
}
|
|
|
|
if (isset($this->messageVariables) && array_key_exists($property, $this->messageVariables)) {
|
|
$result = $this->{$this->messageVariables[$property]};
|
|
if (is_array($result)) {
|
|
return $this->{key($result)}[current($result)];
|
|
}
|
|
return $this->{$result};
|
|
}
|
|
|
|
throw new Exception\InvalidArgumentException("No property exists by the name '$property'");
|
|
}
|
|
|
|
/**
|
|
* Constructs and returns a validation failure message with the given message key and value.
|
|
*
|
|
* Returns null if and only if $messageKey does not correspond to an existing template.
|
|
*
|
|
* If a translator is available and a translation exists for $messageKey,
|
|
* the translation will be used.
|
|
*
|
|
* @param string $messageKey
|
|
* @param string|array|object $value
|
|
* @return string
|
|
*/
|
|
protected function createMessage($messageKey, $value)
|
|
{
|
|
if (! isset($this->abstractOptions['messageTemplates'][$messageKey])) {
|
|
return;
|
|
}
|
|
|
|
$message = $this->abstractOptions['messageTemplates'][$messageKey];
|
|
|
|
$message = $this->translateMessage($messageKey, $message);
|
|
|
|
if (is_object($value) &&
|
|
! in_array('__toString', get_class_methods($value))
|
|
) {
|
|
$value = get_class($value) . ' object';
|
|
} elseif (is_array($value)) {
|
|
$value = var_export($value, 1);
|
|
} else {
|
|
$value = (string) $value;
|
|
}
|
|
|
|
if ($this->isValueObscured()) {
|
|
$value = str_repeat('*', strlen($value));
|
|
}
|
|
|
|
$message = str_replace('%value%', (string) $value, $message);
|
|
foreach ($this->abstractOptions['messageVariables'] as $ident => $property) {
|
|
if (is_array($property)) {
|
|
$value = $this->{key($property)}[current($property)];
|
|
if (is_array($value)) {
|
|
$value = '[' . implode(', ', $value) . ']';
|
|
}
|
|
} else {
|
|
$value = $this->$property;
|
|
}
|
|
$message = str_replace("%$ident%", (string) $value, $message);
|
|
}
|
|
|
|
$length = self::getMessageLength();
|
|
if (($length > -1) && (strlen($message) > $length)) {
|
|
$message = substr($message, 0, $length - 3) . '...';
|
|
}
|
|
|
|
return $message;
|
|
}
|
|
|
|
/**
|
|
* @param string $messageKey
|
|
* @param string $value OPTIONAL
|
|
* @return void
|
|
*/
|
|
protected function error($messageKey, $value = null)
|
|
{
|
|
if ($messageKey === null) {
|
|
$keys = array_keys($this->abstractOptions['messageTemplates']);
|
|
$messageKey = current($keys);
|
|
}
|
|
|
|
if ($value === null) {
|
|
$value = $this->value;
|
|
}
|
|
|
|
$this->abstractOptions['messages'][$messageKey] = $this->createMessage($messageKey, $value);
|
|
}
|
|
|
|
/**
|
|
* Returns the validation value
|
|
*
|
|
* @return mixed Value to be validated
|
|
*/
|
|
protected function getValue()
|
|
{
|
|
return $this->value;
|
|
}
|
|
|
|
/**
|
|
* Sets the value to be validated and clears the messages and errors arrays
|
|
*
|
|
* @param mixed $value
|
|
* @return void
|
|
*/
|
|
protected function setValue($value)
|
|
{
|
|
$this->value = $value;
|
|
$this->abstractOptions['messages'] = [];
|
|
}
|
|
|
|
/**
|
|
* Set flag indicating whether or not value should be obfuscated in messages
|
|
*
|
|
* @param bool $flag
|
|
* @return $this
|
|
*/
|
|
public function setValueObscured($flag)
|
|
{
|
|
$this->abstractOptions['valueObscured'] = (bool) $flag;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Retrieve flag indicating whether or not value should be obfuscated in
|
|
* messages
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function isValueObscured()
|
|
{
|
|
return $this->abstractOptions['valueObscured'];
|
|
}
|
|
|
|
/**
|
|
* Set translation object
|
|
*
|
|
* @param Translator\TranslatorInterface|null $translator
|
|
* @param string $textDomain (optional)
|
|
* @return $this
|
|
* @throws Exception\InvalidArgumentException
|
|
*/
|
|
public function setTranslator(Translator\TranslatorInterface $translator = null, $textDomain = null)
|
|
{
|
|
$this->abstractOptions['translator'] = $translator;
|
|
if (null !== $textDomain) {
|
|
$this->setTranslatorTextDomain($textDomain);
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Return translation object
|
|
*
|
|
* @return Translator\TranslatorInterface|null
|
|
*/
|
|
public function getTranslator()
|
|
{
|
|
if (! $this->isTranslatorEnabled()) {
|
|
return;
|
|
}
|
|
|
|
if (null === $this->abstractOptions['translator']) {
|
|
$this->abstractOptions['translator'] = self::getDefaultTranslator();
|
|
}
|
|
|
|
return $this->abstractOptions['translator'];
|
|
}
|
|
|
|
/**
|
|
* Does this validator have its own specific translator?
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function hasTranslator()
|
|
{
|
|
return (bool) $this->abstractOptions['translator'];
|
|
}
|
|
|
|
/**
|
|
* Set translation text domain
|
|
*
|
|
* @param string $textDomain
|
|
* @return $this
|
|
*/
|
|
public function setTranslatorTextDomain($textDomain = 'default')
|
|
{
|
|
$this->abstractOptions['translatorTextDomain'] = $textDomain;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Return the translation text domain
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getTranslatorTextDomain()
|
|
{
|
|
if (null === $this->abstractOptions['translatorTextDomain']) {
|
|
$this->abstractOptions['translatorTextDomain'] =
|
|
self::getDefaultTranslatorTextDomain();
|
|
}
|
|
return $this->abstractOptions['translatorTextDomain'];
|
|
}
|
|
|
|
/**
|
|
* Set default translation object for all validate objects
|
|
*
|
|
* @param Translator\TranslatorInterface|null $translator
|
|
* @param string $textDomain (optional)
|
|
* @return void
|
|
* @throws Exception\InvalidArgumentException
|
|
*/
|
|
public static function setDefaultTranslator(Translator\TranslatorInterface $translator = null, $textDomain = null)
|
|
{
|
|
static::$defaultTranslator = $translator;
|
|
if (null !== $textDomain) {
|
|
self::setDefaultTranslatorTextDomain($textDomain);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get default translation object for all validate objects
|
|
*
|
|
* @return Translator\TranslatorInterface|null
|
|
*/
|
|
public static function getDefaultTranslator()
|
|
{
|
|
return static::$defaultTranslator;
|
|
}
|
|
|
|
/**
|
|
* Is there a default translation object set?
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function hasDefaultTranslator()
|
|
{
|
|
return (bool) static::$defaultTranslator;
|
|
}
|
|
|
|
/**
|
|
* Set default translation text domain for all validate objects
|
|
*
|
|
* @param string $textDomain
|
|
* @return void
|
|
*/
|
|
public static function setDefaultTranslatorTextDomain($textDomain = 'default')
|
|
{
|
|
static::$defaultTranslatorTextDomain = $textDomain;
|
|
}
|
|
|
|
/**
|
|
* Get default translation text domain for all validate objects
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function getDefaultTranslatorTextDomain()
|
|
{
|
|
return static::$defaultTranslatorTextDomain;
|
|
}
|
|
|
|
/**
|
|
* Indicate whether or not translation should be enabled
|
|
*
|
|
* @param bool $flag
|
|
* @return $this
|
|
*/
|
|
public function setTranslatorEnabled($flag = true)
|
|
{
|
|
$this->abstractOptions['translatorEnabled'] = (bool) $flag;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Is translation enabled?
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function isTranslatorEnabled()
|
|
{
|
|
return $this->abstractOptions['translatorEnabled'];
|
|
}
|
|
|
|
/**
|
|
* Returns the maximum allowed message length
|
|
*
|
|
* @return int
|
|
*/
|
|
public static function getMessageLength()
|
|
{
|
|
return static::$messageLength;
|
|
}
|
|
|
|
/**
|
|
* Sets the maximum allowed message length
|
|
*
|
|
* @param int $length
|
|
*/
|
|
public static function setMessageLength($length = -1)
|
|
{
|
|
static::$messageLength = $length;
|
|
}
|
|
|
|
/**
|
|
* Translate a validation message
|
|
*
|
|
* @param string $messageKey
|
|
* @param string $message
|
|
* @return string
|
|
*/
|
|
protected function translateMessage($messageKey, $message)
|
|
{
|
|
$translator = $this->getTranslator();
|
|
if (! $translator) {
|
|
return $message;
|
|
}
|
|
|
|
return $translator->translate($message, $this->getTranslatorTextDomain());
|
|
}
|
|
}
|