diff --git a/README.md b/README.md
index 40a1ce5..ed11605 100644
--- a/README.md
+++ b/README.md
@@ -281,6 +281,18 @@ $builder->add('period', PeriodType::class, [
]);
```
+#### allow_null
+
+**type**: `bool` **default**: `true`
+Additional options to be used for the *boundaryType* form child.
+
+```php
+$builder->add('period', PeriodType::class, [
+ 'allow_null' => false,
+ // Allow to trigger an error when your Period property is not nullable.
+]);
+```
+
## Configuration (completely optional)
This bundle is build thinking how to save you time and follow best practices as close as possible.
diff --git a/src/Form/DataMapper/PeriodDataMapper.php b/src/Form/DataMapper/PeriodDataMapper.php
index 0e8cbb9..160fd8f 100644
--- a/src/Form/DataMapper/PeriodDataMapper.php
+++ b/src/Form/DataMapper/PeriodDataMapper.php
@@ -9,6 +9,7 @@
use League\Period\Exception;
use League\Period\Period;
use Symfony\Component\Form\DataMapperInterface;
+use Symfony\Component\Form\Exception\TransformationFailedException;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\Form\FormInterface;
@@ -18,6 +19,7 @@ class PeriodDataMapper implements DataMapperInterface
private string $startDateChildName;
private string $endDateChildName;
private string $boundaryTypeChildName;
+ private bool $allowNull;
private const BOUNDARY_TYPES = [
Period::INCLUDE_START_EXCLUDE_END,
@@ -30,13 +32,15 @@ public function __construct(
string $defaultBoundaryType = Period::INCLUDE_START_EXCLUDE_END,
string $startDateChildName = 'startDate',
string $endDateChildName = 'endDate',
- string $boundaryTypeChildName = 'boundaryType'
+ string $boundaryTypeChildName = 'boundaryType',
+ bool $allowNull = true
) {
$this->assertValidBoundaryType($defaultBoundaryType);
$this->defaultBoundaryType = $defaultBoundaryType;
$this->startDateChildName = $startDateChildName;
$this->endDateChildName = $endDateChildName;
$this->boundaryTypeChildName = $boundaryTypeChildName;
+ $this->allowNull = $allowNull;
}
private function assertValidBoundaryType(string $boundaryType): void
@@ -95,11 +99,60 @@ public function mapFormsToData(iterable $forms, &$viewData): void
$viewData = null;
+ if (! $startDate instanceof \DateTimeInterface && $endDate instanceof \DateTimeInterface) {
+ $failure = new TransformationFailedException(\sprintf(
+ 'Start date should be a %s',
+ \DateTimeInterface::class
+ ));
+ $failure->setInvalidMessage(
+ 'Start date should be valid. {{ startDate }} is not a valid date.',
+ ['{{ startDate }}' => json_encode($startDate)]
+ );
+ throw $failure;
+ }
+
+ if (! $endDate instanceof \DateTimeInterface && $startDate instanceof \DateTimeInterface) {
+ $failure = new TransformationFailedException(\sprintf(
+ 'End date should be a %s',
+ \DateTimeInterface::class
+ ));
+ $failure->setInvalidMessage(
+ 'End date should be valid. {{ endDate }} is not a valid date.',
+ ['{{ endDate }}' => json_encode($endDate)]
+ );
+ throw $failure;
+ }
+
if ($startDate instanceof \DateTimeInterface && $endDate instanceof \DateTimeInterface) {
+ if ($startDate > $endDate) {
+ $failure = new TransformationFailedException('Start date should be greater or equals then the end date.');
+ $failure->setInvalidMessage('Start date should be greater or equals then the end date', [
+ '{{ startDate }}' => json_encode($startDate),
+ '{{ endDate }}' => json_encode($endDate),
+ ]);
+ throw $failure;
+ }
+
try {
$viewData = Period::fromDatepoint($startDate, $endDate, $boundaryType);
} catch (Exception $e) {
+ $failure = new TransformationFailedException('Invalid Period', 0, $e);
+ $failure->setInvalidMessage('Invalid Period.', [
+ '{{ startDate }}' => json_encode($startDate),
+ '{{ endDate }}' => json_encode($endDate),
+ ]);
+
+ throw $failure;
}
}
+
+ if (!$this->allowNull && $viewData === null) {
+ $failure = new TransformationFailedException('A valid Period is required');
+ $failure->setInvalidMessage('A valid Period is required.', [
+ '{{ startDate }}' => json_encode($startDate),
+ '{{ endDate }}' => json_encode($endDate),
+ ]);
+ throw $failure;
+ }
}
}
diff --git a/src/Form/PeriodType.php b/src/Form/PeriodType.php
index a0a57fe..6627681 100644
--- a/src/Form/PeriodType.php
+++ b/src/Form/PeriodType.php
@@ -21,7 +21,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add($options['start_date_child_name'], $options['start_date_form_type'], \array_merge_recursive(
[
- 'label' => 'Start date',
+ 'label' => 'Start',
'input' => 'datetime_immutable',
'property_path' => 'startDate',
],
@@ -29,16 +29,9 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
));
$builder->add($options['end_date_child_name'], $options['end_date_form_type'], \array_merge_recursive(
[
- 'label' => 'End date',
+ 'label' => 'End',
'input' => 'datetime_immutable',
- 'property_path' => 'endDate',
- 'constraints' => [
- new GreaterThanOrEqualFormChildren([
- 'child' => $options['end_date_child_name'],
- 'gteChild' => $options['start_date_child_name'],
- 'useParent' => true,
- ]),
- ],
+ 'property_path' => 'endDate'
],
$options['end_date_options']
));
@@ -56,7 +49,8 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
$options['default_boundary_type'],
$options['start_date_child_name'],
$options['end_date_child_name'],
- $options['boundary_type_child_name']
+ $options['boundary_type_child_name'],
+ $options['allow_null']
)
);
}
@@ -97,6 +91,7 @@ public function configureOptions(OptionsResolver $resolver): void
'end_date_options' => [],
'boundary_type_child_name' => 'boundary',
'boundary_type_options' => [],
+ 'allow_null' => true
]);
$resolver->setAllowedValues('default_boundary_type', [
@@ -113,5 +108,6 @@ public function configureOptions(OptionsResolver $resolver): void
$resolver->setAllowedTypes('start_date_child_name', 'string');
$resolver->setAllowedTypes('end_date_child_name', 'string');
$resolver->setAllowedTypes('boundary_type_child_name', 'string');
+ $resolver->setAllowedTypes('allow_null', 'bool');
}
}
diff --git a/src/Form/Validator/GreaterThanOrEqualFormChildren.php b/src/Form/Validator/GreaterThanOrEqualFormChildren.php
deleted file mode 100644
index f69adb2..0000000
--- a/src/Form/Validator/GreaterThanOrEqualFormChildren.php
+++ /dev/null
@@ -1,37 +0,0 @@
-message = $message ?? $this->message;
-
- if (empty($this->child)) {
- throw new ConstraintDefinitionException(sprintf(
- 'The "%s" constraint requires "child" option to be set.',
- static::class
- ));
- }
-
- if (empty($this->gteChild)) {
- throw new ConstraintDefinitionException(sprintf(
- 'The "%s" constraint requires "$gteChild" option to be set.',
- static::class
- ));
- }
- }
-}
diff --git a/src/Form/Validator/GreaterThanOrEqualFormChildrenValidator.php b/src/Form/Validator/GreaterThanOrEqualFormChildrenValidator.php
deleted file mode 100644
index 4f7977e..0000000
--- a/src/Form/Validator/GreaterThanOrEqualFormChildrenValidator.php
+++ /dev/null
@@ -1,92 +0,0 @@
-context->getObject();
- if (!$object instanceof FormInterface) {
- throw new ConstraintDefinitionException(sprintf('"%s" constraint should only be used in Forms ', get_debug_type($constraint)));
- }
-
- $form = $constraint->useParent ? $object->getParent() : $object;
-
- if (null === $form) {
- throw new ConstraintDefinitionException(sprintf('"%s" cannot be used on root forms', get_debug_type($constraint)));
- }
-
- if (!$form->has($constraint->child)) {
- throw new ConstraintDefinitionException(sprintf('"%s" cannot find child "%s" on form', get_debug_type($constraint), $constraint->child));
- }
-
- if (!$form->has($constraint->gteChild)) {
- throw new ConstraintDefinitionException(sprintf('"%s" cannot find child "%s" on form', get_debug_type($constraint), $constraint->gteChild));
- }
-
- $comparedValue = $form->get($constraint->gteChild)->getData();
- $value = $form->get($constraint->child)->getData();
-
- if (null === $value || null === $comparedValue) {
- return;
- }
-
- // Convert strings to DateTimes if comparing another DateTime
- // This allows to compare with any date/time value supported by
- // the DateTime constructor:
- // https://php.net/datetime.formats
- if (\is_string($comparedValue) && $value instanceof \DateTimeInterface) {
- // If $value is immutable, convert the compared value to a DateTimeImmutable too, otherwise use DateTime
- $dateTimeClass = $value instanceof \DateTimeImmutable ? \DateTimeImmutable::class : \DateTime::class;
-
- try {
- $comparedValue = new $dateTimeClass($comparedValue);
- } catch (\Exception $e) {
- throw new ConstraintDefinitionException(sprintf('The compared value "%s" could not be converted to a "%s" instance in the "%s" constraint.', $comparedValue, $dateTimeClass, get_debug_type($constraint)));
- }
- }
-
- if (!$this->compareValues($value, $comparedValue)) {
- $violationBuilder = $this->context->buildViolation($constraint->message)
- ->setParameter('{{ value }}', $this->formatValue($value, self::OBJECT_TO_STRING | self::PRETTY_DATE))
- ->setParameter('{{ compared_value }}', $this->formatValue($comparedValue, self::OBJECT_TO_STRING | self::PRETTY_DATE))
- ->setParameter('{{ compared_value_type }}', $this->formatTypeOf($comparedValue))
- ->setCode($this->getErrorCode());
-
- $violationBuilder->addViolation();
- }
- }
-
- /**
- * {@inheritdoc}
- */
- protected function compareValues($value1, $value2): bool
- {
- return null === $value2 || $value1 >= $value2;
- }
-
- /**
- * {@inheritdoc}
- */
- protected function getErrorCode(): string
- {
- return GreaterThanOrEqual::TOO_LOW_ERROR;
- }
-}
diff --git a/src/Resources/translations/AndantePeriodBundle.en.xlf b/src/Resources/translations/AndantePeriodBundle.en.xlf
index a909531..16ec926 100644
--- a/src/Resources/translations/AndantePeriodBundle.en.xlf
+++ b/src/Resources/translations/AndantePeriodBundle.en.xlf
@@ -19,17 +19,37 @@
Exclude both start and end
-
- Start date
+
+ Start
-
- End date
+
+ End
Boundary type
+
+
+ La data di inizio dovrebbe essere valida. {{ startDate }} non è una data valida.
+
+
+
+ La data di fine dovrebbe essere valida. {{ endDate }} non è una data valida.
+
+
+
+ La data di inizio dovrebbe essere maggiore o uguale della data di fine.
+
+
+
+ Periodo non valido.
+
+
+
+ Un periodo è obbligatorio.
+