OpenXE/vendor/laminas/laminas-validator/src/AbstractValidator.php
2021-05-21 08:49:41 +02:00

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());
}
}