I am looking for a way to validate one array obtained via a form.
$arr = [13, 64];
The array is composed of 2 integers and I need to check that these integers are between 0 ad 1000, but also the 2nd integer is greater than the first AND the difference cannot exceed 100. The only only constraint I could put was the one validating the number with a know pattern :
'constraints' => new Assert\Collection([
'fields' => [
0 => new Assert\Range([
'min' => 0,
'max' => 1000,
]),
1 => new Assert\Range([
'min' => 0,
'max' => 1000,
]),
]
]),
What is missing in my validation:
$arr = [13, 64]; => should be correct
$arr = [140, 64]; => not correct, $arr[0] > $arr[1]
$arr = [13, 340]; => not correct, ($arr[1] - $arr[0]) > 100
I couldnt find in the symfony doc how to validate array fields among each others, and don't event know if there is a way to.
If anyone has a tip, you're welcome :)
thank you and cheers !
CodePudding user response:
Create a Custom Form Constraint.
Create 2 files and place them in src/Validator
The Constraint:
// src/Validator/CheckArray.php
namespace App\Validator;
use Symfony\Component\Validator\Constraint;
class CheckArray extends Constraint
{
public $type = 'One of the values is not an integer.';
public $range = 'One of the values is not within range. (0 and 1000)';
public $exceeded = 'Value mismatched. Exceeded expected value.';
}
The Validator:
// src/Validator/CheckArrayValidator.php
namespace App\Validator;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;
class CheckArrayValidator extends ConstraintValidator
{
public function validate($array, Constraint $constraint)
{
if (!$constraint instanceof CheckArray) {
throw new UnexpectedTypeException($constraint, CheckArray::class);
}
if (null === $array || '' === $array) {
return;
}
if (!is_array($array)) {
throw new UnexpectedValueException($array, 'array');
}
if ($this->checkType()) {
$this->context->buildViolation($constraint->type)->addViolation();
}
if ($this->checkRange()) {
$this->context->buildViolation($constraint->range)->addViolation();
}
if ($this->checkExceeded()) {
$this->context->buildViolation($constraint->exceeded)->addViolation();
}
}
private function checkType(array $array): bool
{
return $array !== array_filter($array, 'is_int');
}
private function checkRange(array $array): bool
{
return $array !== array_filter($array, function($v){
return ($v > 0 && $v < 1000);
});
}
private function checkExceeded(array $array): bool
{
if ($array[0] > $array[1]) return true;
if (($array[1] - $array[0]) > 100) return true;
return false;
}
}
In your form:
use App\Validator\CheckArray;
'constraints' => new CheckArray()
Not fully tested, tweak naming and messages as you need or add more.