silverstripe-framework/src/ORM/ValidationResult.php

257 lines
8.6 KiB
PHP

<?php
namespace SilverStripe\ORM;
use InvalidArgumentException;
use Serializable;
use SilverStripe\Core\Convert;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Dev\Deprecation;
/**
* A class that combined as a boolean result with an optional list of error messages.
* This is used for returning validation results from validators
*
* Each message can have a code or field which will uniquely identify that message. However,
* messages can be stored without a field or message as an "overall" message.
*/
class ValidationResult implements Serializable
{
use Injectable;
/**
* Standard "error" type
*/
const TYPE_ERROR = 'error';
/**
* Standard "good" message type
*/
const TYPE_GOOD = 'good';
/**
* Non-error message type.
*/
const TYPE_INFO = 'info';
/**
* Warning message type
*/
const TYPE_WARNING = 'warning';
/**
* Message type is html
*/
const CAST_HTML = 'html';
/**
* Message type is plain text
*/
const CAST_TEXT = 'text';
/**
* Is the result valid or not.
* Note that there can be non-error messages in the list.
*
* @var bool
*/
protected $isValid = true;
/**
* List of messages
*
* @var array
*/
protected $messages = [];
/**
* Create a new ValidationResult.
* By default, it is a successful result. Call $this->error() to record errors.
*/
public function __construct()
{
if (func_num_args() > 0) {
Deprecation::notice('3.2', '$valid parameter is deprecated please addError to mark the result as invalid', false);
$this->isValid = func_get_arg(0);
}
if (func_num_args() > 1) {
Deprecation::notice('3.2', '$message parameter is deprecated please use addMessage or addError instead', false);
$this->addError(func_get_arg(1));
}
}
/**
* Record an error against this validation result,
*
* @param string $message The message string.
* @param string $messageType Passed as a CSS class to the form, so other values can be used if desired.
* Standard types are defined by the TYPE_ constant definitions.
* @param string $code A codename for this error. Only one message per codename will be added.
* This can be usedful for ensuring no duplicate messages
* @param string|bool $cast Cast type; One of the CAST_ constant definitions.
* Bool values will be treated as plain text flag.
* @return $this
*/
public function addError($message, $messageType = self::TYPE_ERROR, $code = null, $cast = self::CAST_TEXT)
{
return $this->addFieldError(null, $message, $messageType, $code, $cast);
}
/**
* Record an error against this validation result,
*
* @param string $fieldName The field to link the message to. If omitted; a form-wide message is assumed.
* @param string $message The message string.
* @param string $messageType The type of message: e.g. "bad", "warning", "good", or "required". Passed as a CSS
* class to the form, so other values can be used if desired.
* @param string $code A codename for this error. Only one message per codename will be added.
* This can be usedful for ensuring no duplicate messages
* @param string|bool $cast Cast type; One of the CAST_ constant definitions.
* Bool values will be treated as plain text flag.
* @return $this
*/
public function addFieldError(
$fieldName,
$message,
$messageType = self::TYPE_ERROR,
$code = null,
$cast = self::CAST_TEXT
) {
$this->isValid = false;
return $this->addFieldMessage($fieldName, $message, $messageType, $code, $cast);
}
/**
* Add a message to this ValidationResult without necessarily marking it as an error
*
* @param string $message The message string.
* @param string $messageType The type of message: e.g. "bad", "warning", "good", or "required". Passed as a CSS
* class to the form, so other values can be used if desired.
* @param string $code A codename for this error. Only one message per codename will be added.
* This can be usedful for ensuring no duplicate messages
* @param string|bool $cast Cast type; One of the CAST_ constant definitions.
* Bool values will be treated as plain text flag.
* @return $this
*/
public function addMessage($message, $messageType = self::TYPE_ERROR, $code = null, $cast = self::CAST_TEXT)
{
return $this->addFieldMessage(null, $message, $messageType, $code, $cast);
}
/**
* Add a message to this ValidationResult without necessarily marking it as an error
*
* @param string $fieldName The field to link the message to. If omitted; a form-wide message is assumed.
* @param string $message The message string.
* @param string $messageType The type of message: e.g. "bad", "warning", "good", or "required". Passed as a CSS
* class to the form, so other values can be used if desired.
* @param string $code A codename for this error. Only one message per codename will be added.
* This can be usedful for ensuring no duplicate messages
* @param string|bool $cast Cast type; One of the CAST_ constant definitions.
* Bool values will be treated as plain text flag.
* @return $this
*/
public function addFieldMessage(
$fieldName,
$message,
$messageType = self::TYPE_ERROR,
$code = null,
$cast = self::CAST_TEXT
) {
if ($code && is_numeric($code)) {
throw new InvalidArgumentException("Don't use a numeric code '$code'. Use a string.");
}
if (is_bool($cast)) {
$cast = $cast ? self::CAST_TEXT : self::CAST_HTML;
}
$metadata = [
'message' => $message,
'fieldName' => $fieldName,
'messageType' => $messageType,
'messageCast' => $cast,
];
if ($code) {
$this->messages[$code] = $metadata;
} else {
$this->messages[] = $metadata;
}
return $this;
}
/**
* Returns true if the result is valid.
* @return boolean
*/
public function isValid()
{
return $this->isValid;
}
/**
* Return the full error meta-data, suitable for combining with another ValidationResult.
*
* @return array Array of messages, where each item is an array of data for that message.
*/
public function getMessages()
{
return $this->messages;
}
/**
* Combine this Validation Result with the ValidationResult given in other.
* It will be valid if both this and the other result are valid.
* This object will be modified to contain the new validation information.
*
* @param ValidationResult $other the validation result object to combine
* @return $this
*/
public function combineAnd(ValidationResult $other)
{
$this->isValid = $this->isValid && $other->isValid();
$this->messages = array_merge($this->messages, $other->getMessages());
return $this;
}
public function __serialize(): array
{
return [
'messages' => $this->messages,
'isValid' => $this->isValid()
];
}
public function __unserialize(array $data): void
{
$this->messages = $data['messages'];
$this->isValid = $data['isValid'];
}
/**
* The __serialize() magic method will be automatically used instead of this
*
* @return string
* @deprecated 4.12.0 Use __serialize() instead
*/
public function serialize()
{
Deprecation::notice('4.12.0', 'Use __serialize() instead');
return json_encode([$this->messages, $this->isValid]);
}
/**
* The __unserialize() magic method will be automatically used instead of this almost all the time
* This method will be automatically used if existing serialized data was not saved as an associative array
* and the PHP version used in less than PHP 9.0
*
* @param string $serialized
* @deprecated 4.12.0 Use __unserialize() instead
*/
public function unserialize($serialized)
{
Deprecation::notice('4.12.0', 'Use __unserialize() instead');
list($this->messages, $this->isValid) = json_decode($serialized ?? '', true);
}
}