, * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ namespace Chill\CustomFieldsBundle\CustomFields; use Chill\CustomFieldsBundle\Entity\CustomField; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Validator\Constraints\GreaterThanOrEqual; use Symfony\Component\Validator\Constraints\LessThanOrEqual; use Symfony\Bundle\TwigBundle\TwigEngine; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Form\Type\ChillDateType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Validator\Constraints\Callback; use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Form\Extension\Core\Type\TextType; use Chill\CustomFieldsBundle\Form\DataTransformer\CustomFieldDataTransformer; /** * Create a custom date number. * * The date may have a min and max value. * * The date is stored as an unix timestamp. * * @author Julien Fastré */ class CustomFieldDate extends AbstractCustomField { /** * key for the minimal value of the field */ const MIN = 'min'; const MAX = 'max'; const FORMAT = 'format'; const DATE_FORMAT = \DateTime::RFC3339; /** * * @var TwigEngine */ private $templating = NULL; /** * * @var TranslatableStringHelper */ private $translatableStringHelper = NULL; public function __construct(TwigEngine $templating, TranslatableStringHelper $translatableStringHelper) { $this->templating = $templating; $this->translatableStringHelper = $translatableStringHelper; } public function buildForm(FormBuilderInterface $builder, CustomField $customField) { $fieldOptions = $this->prepareFieldOptions($customField); $builder->add( $builder ->create( $customField->getSlug(), ChillDateType::class, $fieldOptions) ->addModelTransformer( new CustomFieldDataTransformer($this, $customField) ) ) ; } /** * prepare the options'form field * * @param CustomField $customField * @param string $type * @return mixed[] */ private function prepareFieldOptions(CustomField $customField) { $options = $customField->getOptions(); /** * @var mixed[] the formField options */ $fieldOptions = array(); // add required $fieldOptions['required'] = False; //add label $fieldOptions['label'] = $this->translatableStringHelper->localize($customField->getName()); // add constraints if required if ($options[self::MIN] !== NULL) { $fieldOptions['constraints'][] = new Callback( function($timestamp, ExecutionContextInterface $context) use ($options) { if ($timestamp === null) { return; } $value = \DateTime::createFromFormat(self::DATE_FORMAT, $timestamp); $after = new \DateTime($options[self::MIN]); if ($value < $after) { $context ->buildViolation('This date must be after or equal to %date%', [ '%date%' => $after->format('d-m-Y') ]) ->addViolation(); } } ); } if ($options[self::MAX] !== NULL) { $fieldOptions['constraints'][] = new Callback( function($timestamp, ExecutionContextInterface $context) use ($options) { if ($timestamp === null) { return; } $value = \DateTime::createFromFormat(self::DATE_FORMAT, $timestamp); $before = new \DateTime($options[self::MAX]); if ($value > $before) { $context ->buildViolation('This date must be before or equal to %date%', [ '%date%' => $before->format('d-m-Y') ]) ->addViolation(); } } ); } return $fieldOptions; } public function buildOptionsForm(FormBuilderInterface $builder) { $validatorFunction = function($value, ExecutionContextInterface $context) { try { $date = new \DateTime($value); } catch (\Exception $e) { $context->buildViolation('The expression "%expression%" is invalid', [ '%expression%' => $value ]) ->addViolation() ; } }; return $builder ->add(self::MIN, TextType::class, array( 'label' => 'Greater or equal than (expression like 1 day ago, 2 years ago, +1 month, today, tomorrow, or date with format YYYY-mm-dd)', 'required' => false, 'constraints' => [ new Callback($validatorFunction) ] )) ->add(self::MAX, TextType::class, array( 'label' => 'Lesser or equal than (expression like 1 day ago, 2 years ago, +1 month, today, tomorrow, or date with format YYYY-mm-dd)', 'required' => false, 'constraints' => [ new Callback($validatorFunction) ] )) ->add(self::FORMAT, ChoiceType::class, [ 'label' => 'Format', 'choices' => [ 'medium' => 'medium', 'long' => 'long', 'short' => 'short' ] ]) ; } public function deserialize($serialized, CustomField $customField) { if (empty($serialized)) { return null; } return \DateTime::createFromFormat(self::DATE_FORMAT, $serialized); } public function getName() { return 'Date field'; } public function render($value, CustomField $customField, $documentType = 'html') { switch ($documentType) { case 'csv': $date = $this->deserialize($value, $customField); if (NULL === $date) { return null; } return $date->format('Y-m-d'); default: $template = 'ChillCustomFieldsBundle:CustomFieldsRendering:date.' .$documentType.'.twig'; return $this->templating ->render($template, array( 'value' => $this->deserialize($value, $customField), 'format' => $customField->getOptions()[self::FORMAT] )); } } public function serialize($date, CustomField $customField) { if ($date === null) { return null; } return $date->format(self::DATE_FORMAT); } }