-
Notifications
You must be signed in to change notification settings - Fork 821
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #11408 from creative-commoners/pulls/6/field-valid…
…ators NEW Validate DBFields
- Loading branch information
Showing
92 changed files
with
3,747 additions
and
122 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
65 changes: 65 additions & 0 deletions
65
src/Core/Validation/FieldValidation/BigIntFieldValidator.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
<?php | ||
|
||
namespace SilverStripe\Core\Validation\FieldValidation; | ||
|
||
use RunTimeException; | ||
use SilverStripe\Core\Validation\FieldValidation\IntFieldValidator; | ||
use SilverStripe\Core\Validation\ValidationResult; | ||
|
||
/** | ||
* A field validator for 64-bit integers | ||
* Will throw a RunTimeException if used on a 32-bit system | ||
*/ | ||
class BigIntFieldValidator extends IntFieldValidator | ||
{ | ||
/** | ||
* The minimum value for a signed 64-bit integer. | ||
* Defined as string instead of int otherwise will end up as a float | ||
* on 64-bit systems | ||
* | ||
* When this is cast to an int in IntFieldValidator::__construct() | ||
* it will be properly cast to an int | ||
*/ | ||
protected const MIN_INT = '-9223372036854775808'; | ||
|
||
/** | ||
* The maximum value for a signed 64-bit integer. | ||
*/ | ||
protected const MAX_INT = '9223372036854775807'; | ||
|
||
public function __construct( | ||
string $name, | ||
mixed $value, | ||
?int $minValue = null, | ||
?int $maxValue = null | ||
) { | ||
if (is_null($minValue) || is_null($maxValue)) { | ||
$bits = strlen(decbin(~0)); | ||
if ($bits === 32) { | ||
throw new RunTimeException('Cannot use BigIntFieldValidator on a 32-bit system'); | ||
} | ||
} | ||
$this->minValue = $minValue; | ||
$this->maxValue = $maxValue; | ||
parent::__construct($name, $value, $minValue, $maxValue); | ||
} | ||
|
||
protected function validateValue(): ValidationResult | ||
{ | ||
$result = ValidationResult::create(); | ||
// Validate string values that are too large or too small | ||
// Only testing for string values here as that's all bccomp can take as arguments | ||
// int values that are too large or too small will be cast to float | ||
// on 64-bit systems and will fail the validation in IntFieldValidator | ||
if (is_string($this->value)) { | ||
if (!is_null($this->minValue) && bccomp($this->value, static::MIN_INT) === -1) { | ||
$result->addFieldError($this->name, $this->getTooSmallMessage()); | ||
} | ||
if (!is_null($this->maxValue) && bccomp($this->value, static::MAX_INT) === 1) { | ||
$result->addFieldError($this->name, $this->getTooLargeMessage()); | ||
} | ||
} | ||
$result->combineAnd(parent::validateValue()); | ||
return $result; | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
src/Core/Validation/FieldValidation/BooleanFieldValidator.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<?php | ||
|
||
namespace SilverStripe\Core\Validation\FieldValidation; | ||
|
||
use SilverStripe\Core\Validation\ValidationResult; | ||
use SilverStripe\Core\Validation\FieldValidation\FieldValidator; | ||
|
||
/** | ||
* Validates that a value is a boolean | ||
*/ | ||
class BooleanFieldValidator extends FieldValidator | ||
{ | ||
protected function validateValue(): ValidationResult | ||
{ | ||
$result = ValidationResult::create(); | ||
if (!is_bool($this->value)) { | ||
$message = _t(__CLASS__ . '.INVALID', 'Invalid value'); | ||
$result->addFieldError($this->name, $message); | ||
} | ||
return $result; | ||
} | ||
} |
39 changes: 39 additions & 0 deletions
39
src/Core/Validation/FieldValidation/CompositeFieldValidator.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<?php | ||
|
||
namespace SilverStripe\Core\Validation\FieldValidation; | ||
|
||
use InvalidArgumentException; | ||
use SilverStripe\Core\Validation\ValidationResult; | ||
use SilverStripe\Core\Validation\FieldValidation\FieldValidator; | ||
use SilverStripe\Core\Validation\FieldValidation\FieldValidationInterface; | ||
|
||
/** | ||
* A field validator used to validate DBComposite fields | ||
*/ | ||
class CompositeFieldValidator extends FieldValidator | ||
{ | ||
/** | ||
* @param mixed $value - an iterable list of FieldValidators | ||
*/ | ||
public function __construct(string $name, mixed $value) | ||
{ | ||
parent::__construct($name, $value); | ||
if (!is_iterable($value)) { | ||
throw new InvalidArgumentException('Value must be iterable'); | ||
} | ||
foreach ($value as $child) { | ||
if (!is_a($child, FieldValidationInterface::class)) { | ||
throw new InvalidArgumentException('Child is not a' . FieldValidationInterface::class); | ||
} | ||
} | ||
} | ||
|
||
protected function validateValue(): ValidationResult | ||
{ | ||
$result = ValidationResult::create(); | ||
foreach ($this->value as $child) { | ||
$result->combineAnd($child->validate()); | ||
} | ||
return $result; | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
src/Core/Validation/FieldValidation/DateFieldValidator.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
<?php | ||
|
||
namespace SilverStripe\Core\Validation\FieldValidation; | ||
|
||
use SilverStripe\Core\Validation\FieldValidation\FieldValidator; | ||
use SilverStripe\Core\Validation\ValidationResult; | ||
|
||
/** | ||
* Validates that a value is a valid date, which means that it follows the equivalent formats: | ||
* - PHP date format Y-m-d | ||
* - SO format y-MM-dd i.e. DBDate::ISO_DATE | ||
* | ||
* Blank string values are allowed | ||
*/ | ||
class DateFieldValidator extends FieldValidator | ||
{ | ||
protected function validateValue(): ValidationResult | ||
{ | ||
$result = ValidationResult::create(); | ||
// Allow empty strings | ||
if ($this->value === '') { | ||
return $result; | ||
} | ||
// Not using symfony/validator because it was allowing d-m-Y format strings | ||
$date = date_parse_from_format($this->getFormat(), $this->value ?? ''); | ||
if ($date === false || $date['error_count'] > 0 || $date['warning_count'] > 0) { | ||
$result->addFieldError($this->name, $this->getMessage()); | ||
} | ||
return $result; | ||
} | ||
|
||
protected function getFormat(): string | ||
{ | ||
return 'Y-m-d'; | ||
} | ||
|
||
protected function getMessage(): string | ||
{ | ||
return _t(__CLASS__ . '.INVALID', 'Invalid date'); | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
src/Core/Validation/FieldValidation/DatetimeFieldValidator.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php | ||
|
||
namespace SilverStripe\Core\Validation\FieldValidation; | ||
|
||
use SilverStripe\Core\Validation\FieldValidation\DateFieldValidator; | ||
|
||
/** | ||
* Validates that a value is a valid date/time, which means that it follows the equivalent formats: | ||
* - PHP date format Y-m-d H:i:s | ||
* - ISO format 'y-MM-dd HH:mm:ss' i.e. DBDateTime::ISO_DATETIME | ||
* | ||
* Blank string values are allowed | ||
*/ | ||
class DatetimeFieldValidator extends DateFieldValidator | ||
{ | ||
protected function getFormat(): string | ||
{ | ||
return 'Y-m-d H:i:s'; | ||
} | ||
|
||
protected function getMessage(): string | ||
{ | ||
return _t(__CLASS__ . '.INVALID', 'Invalid date/time'); | ||
} | ||
} |
78 changes: 78 additions & 0 deletions
78
src/Core/Validation/FieldValidation/DecimalFieldValidator.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
<?php | ||
|
||
namespace SilverStripe\Core\Validation\FieldValidation; | ||
|
||
use SilverStripe\Core\Validation\ValidationResult; | ||
use SilverStripe\Core\Validation\FieldValidation\NumericFieldValidator; | ||
|
||
/** | ||
* Validates that a value is a valid decimal | ||
* This intended for use when validating that a value can be stored in a database as a decimal | ||
* | ||
* Example of how digits are stored in the database | ||
* Decimal(5,2) is allowed a total of 5 digits, and will always round to 2 decimal places | ||
* This means it has a maximum 3 digits before the decimal point | ||
* | ||
* Valid | ||
* 123.99 | ||
* 999.99 | ||
* -999.99 | ||
* 123.999 - will round to 124.00 | ||
* | ||
* Not valid | ||
* 1234.9 - 4 digits the before the decimal point | ||
* 999.999 - would be rounded to 1000.00 which exceeds 5 total digits | ||
*/ | ||
class DecimalFieldValidator extends NumericFieldValidator | ||
{ | ||
/** | ||
* Whole number size e.g. For Decimal(9,2) this would be 9 | ||
*/ | ||
private int $wholeSize; | ||
|
||
/** | ||
* Decimal size e.g. For Decimal(5,2) this would be 2 | ||
*/ | ||
private int $decimalSize; | ||
|
||
public function __construct( | ||
string $name, | ||
mixed $value, | ||
int $wholeSize, | ||
int $decimalSize, | ||
int $minValue = null, | ||
int $maxValue = null, | ||
) { | ||
parent::__construct($name, $value, $minValue, $maxValue); | ||
$this->wholeSize = $wholeSize; | ||
$this->decimalSize = $decimalSize; | ||
} | ||
|
||
protected function validateValue(): ValidationResult | ||
{ | ||
$result = parent::validateValue(); | ||
if (!$result->isValid()) { | ||
return $result; | ||
} | ||
// Convert to absolute value - the minus sign is not relevant for validation | ||
$absValue = abs($this->value); | ||
// Round to the decimal size which is what the database will do | ||
$rounded = round($absValue, $this->decimalSize); | ||
// Get formatted as a string, which will right pad with zeros to the decimal size | ||
$rounded = number_format($rounded, $this->decimalSize, thousands_separator: ''); | ||
// Count this number of digits - the minus 1 is for the decimal point | ||
$digitCount = strlen((string) $rounded) - 1; | ||
if ($digitCount > $this->wholeSize) { | ||
$message = _t( | ||
__CLASS__ . '.TOOLARGE', | ||
'Cannot have more than {wholeSize} digits which includes {decimalSize} decimal places', | ||
[ | ||
'wholeSize' => $this->wholeSize, | ||
'decimalSize' => $this->decimalSize | ||
] | ||
); | ||
$result->addFieldError($this->name, $message); | ||
} | ||
return $result; | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
src/Core/Validation/FieldValidation/EmailFieldValidator.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?php | ||
|
||
namespace SilverStripe\Core\Validation\FieldValidation; | ||
|
||
use Symfony\Component\Validator\Constraint; | ||
use Symfony\Component\Validator\Constraints\Email; | ||
use SilverStripe\Core\Validation\FieldValidation\StringFieldValidator; | ||
use SilverStripe\Core\Validation\FieldValidation\SymfonyFieldValidatorTrait; | ||
use SilverStripe\Core\Validation\FieldValidation\SymfonyFieldValidatorInterface; | ||
|
||
/** | ||
* Validates that a value is a valid email address | ||
* Uses Symfony's Email constraint to validate | ||
*/ | ||
class EmailFieldValidator extends StringFieldValidator implements SymfonyFieldValidatorInterface | ||
{ | ||
use SymfonyFieldValidatorTrait; | ||
|
||
public function getConstraint(): Constraint|array | ||
{ | ||
$message = _t(__CLASS__ . '.INVALID', 'Invalid email address'); | ||
return new Email(message: $message); | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
src/Core/Validation/FieldValidation/FieldValidationInterface.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<?php | ||
|
||
namespace SilverStripe\Core\Validation\FieldValidation; | ||
|
||
use SilverStripe\Core\Validation\ValidationInterface; | ||
|
||
/** | ||
* Interface for fields e.g. a DBField or FormField, that can use FieldValidator's | ||
* Intended for use on classes that have the FieldValidationTrait applied | ||
*/ | ||
interface FieldValidationInterface extends ValidationInterface | ||
{ | ||
public function getName(): string; | ||
|
||
public function getValue(): mixed; | ||
|
||
public function getValueForValidation(): mixed; | ||
} |
Oops, something went wrong.