Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactored Float and Integer field types to use external validators #425

Merged
merged 10 commits into from
Aug 28, 2024
435 changes: 0 additions & 435 deletions phpstan-baseline.neon

Large diffs are not rendered by default.

83 changes: 83 additions & 0 deletions src/lib/FieldType/BaseNumericType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Core\FieldType;

use Ibexa\Contracts\Core\FieldType\Value as SPIValue;
use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition;
use JMS\TranslationBundle\Translation\TranslationContainerInterface;

abstract class BaseNumericType extends FieldType implements TranslationContainerInterface
{
/**
* @return array<string, \Ibexa\Core\FieldType\Validator>
*/
abstract protected function getValidators(): array;

public function getValidator(string $validatorIdentifier): ?Validator
{
return $this->getValidators()[$validatorIdentifier] ?? null;
}

/**
* Validates the validatorConfiguration of a FieldDefinitionCreateStruct or FieldDefinitionUpdateStruct.
*
* @param array<string, mixed> $validatorConfiguration
*
* @return \Ibexa\Contracts\Core\FieldType\ValidationError[]
*/
public function validateValidatorConfiguration($validatorConfiguration): array
{
$validationErrors = [];
$validatorValidationErrors = [];
foreach ($validatorConfiguration as $validatorIdentifier => $constraints) {
$validator = $this->getValidator($validatorIdentifier);
if (null === $validator) {
$validationErrors[] = new ValidationError(
"Validator '%validator%' is unknown",
null,
[
'%validator%' => $validatorIdentifier,
],
"[$validatorIdentifier]"
);

continue;
}

$validatorValidationErrors[] = $validator->validateConstraints($constraints);
}

return array_merge($validationErrors, ...$validatorValidationErrors);
}

/**
* Validates a field based on the validators in the field definition.
*
* @return \Ibexa\Contracts\Core\FieldType\ValidationError[]
*
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\PropertyNotFoundException
*/
public function validate(FieldDefinition $fieldDefinition, SPIValue $value): array
{
if ($this->isEmptyValue($value)) {
return [];
}

$errors = [];
$validatorConfiguration = $fieldDefinition->getValidatorConfiguration();
foreach ($this->getValidators() as $validatorIdentifier => $validator) {
$validator->initializeWithConstraints($validatorConfiguration[$validatorIdentifier] ?? []);
if (!$validator->validate($value, $fieldDefinition)) {
$errors[] = $validator->getMessage();
}
}

return array_merge(...$errors);
}
}
130 changes: 10 additions & 120 deletions src/lib/FieldType/Float/Type.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,17 @@
use Ibexa\Contracts\Core\FieldType\Value as SPIValue;
use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition;
use Ibexa\Core\Base\Exceptions\InvalidArgumentType;
use Ibexa\Core\FieldType\FieldType;
use Ibexa\Core\FieldType\ValidationError;
use Ibexa\Core\FieldType\BaseNumericType;
use Ibexa\Core\FieldType\Validator;
use Ibexa\Core\FieldType\Value as BaseValue;
use JMS\TranslationBundle\Model\Message;
use JMS\TranslationBundle\Translation\TranslationContainerInterface;

/**
* Float field types.
*
* Represents floats.
*/
class Type extends FieldType implements TranslationContainerInterface
class Type extends BaseNumericType
{
protected $validatorConfigurationSchema = [
'FloatValueValidator' => [
Expand All @@ -36,112 +35,9 @@ class Type extends FieldType implements TranslationContainerInterface
],
];

/**
* Validates the validatorConfiguration of a FieldDefinitionCreateStruct or FieldDefinitionUpdateStruct.
*
* @param mixed $validatorConfiguration
*
* @return \Ibexa\Contracts\Core\FieldType\ValidationError[]
*/
public function validateValidatorConfiguration($validatorConfiguration)
{
$validationErrors = [];

foreach ($validatorConfiguration as $validatorIdentifier => $constraints) {
if ($validatorIdentifier !== 'FloatValueValidator') {
$validationErrors[] = new ValidationError(
"Validator '%validator%' is unknown",
null,
[
'%validator%' => $validatorIdentifier,
],
"[$validatorIdentifier]"
);

continue;
}

foreach ($constraints as $name => $value) {
switch ($name) {
case 'minFloatValue':
case 'maxFloatValue':
if ($value !== null && !is_numeric($value)) {
$validationErrors[] = new ValidationError(
"Validator parameter '%parameter%' value must be of numeric type",
null,
[
'%parameter%' => $name,
],
"[$validatorIdentifier][$name]"
);
}
break;
default:
$validationErrors[] = new ValidationError(
"Validator parameter '%parameter%' is unknown",
null,
[
'%parameter%' => $name,
],
"[$validatorIdentifier][$name]"
);
}
}
}

return $validationErrors;
}

/**
* Validates a field based on the validators in the field definition.
*
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
*
* @param \Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition $fieldDefinition The field definition of the field
* @param \Ibexa\Core\FieldType\Float\Value $fieldValue The field value for which an action is performed
*
* @return \Ibexa\Contracts\Core\FieldType\ValidationError[]
*/
public function validate(FieldDefinition $fieldDefinition, SPIValue $fieldValue)
protected function getValidators(): array
{
$validationErrors = [];

if ($this->isEmptyValue($fieldValue)) {
return $validationErrors;
}

$validatorConfiguration = $fieldDefinition->getValidatorConfiguration();
$constraints = isset($validatorConfiguration['FloatValueValidator']) ?
$validatorConfiguration['FloatValueValidator'] :
[];

$validationErrors = [];

if (isset($constraints['maxFloatValue']) &&
$constraints['maxFloatValue'] !== null && $fieldValue->value > $constraints['maxFloatValue']) {
$validationErrors[] = new ValidationError(
'The value can not be higher than %size%.',
null,
[
'%size%' => $constraints['maxFloatValue'],
],
'value'
);
}

if (isset($constraints['minFloatValue']) &&
$constraints['minFloatValue'] !== null && $fieldValue->value < $constraints['minFloatValue']) {
$validationErrors[] = new ValidationError(
'The value can not be lower than %size%.',
null,
[
'%size%' => $constraints['minFloatValue'],
],
'value'
);
}

return $validationErrors;
return ['FloatValueValidator' => new Validator\FloatValueValidator()];
}

/**
Expand All @@ -165,20 +61,14 @@ public function getName(SPIValue $value, FieldDefinition $fieldDefinition, strin
/**
* Returns the fallback default value of field type when no such default
* value is provided in the field definition in content types.
*
* @return \Ibexa\Core\FieldType\Float\Value
*/
public function getEmptyValue()
public function getEmptyValue(): Value
{
return new Value();
}

/**
* Implements the core of {@see isEmptyValue()}.
*
* @param mixed $value
*
* @return bool
* @param \Ibexa\Core\FieldType\Float\Value $value
*/
public function isEmptyValue(SPIValue $value)
{
Expand Down Expand Up @@ -209,7 +99,7 @@ protected function createValueFromInput($inputValue)
*
* @param \Ibexa\Core\FieldType\Float\Value $value
*/
protected function checkValueStructure(BaseValue $value)
protected function checkValueStructure(BaseValue $value): void
{
if (!is_float($value->value)) {
throw new InvalidArgumentType(
Expand Down Expand Up @@ -237,7 +127,7 @@ protected function getSortInfo(BaseValue $value)
*
* @return \Ibexa\Core\FieldType\Float\Value $value
*/
public function fromHash($hash)
public function fromHash($hash): Value
{
if ($hash === null) {
return $this->getEmptyValue();
Expand All @@ -253,7 +143,7 @@ public function fromHash($hash)
*
* @return mixed
*/
public function toHash(SPIValue $value)
public function toHash(SPIValue $value): mixed
{
if ($this->isEmptyValue($value)) {
return null;
Expand Down
Loading
Loading