diff --git a/src/Bundle/ChillCalendarBundle/Form/CalendarType.php b/src/Bundle/ChillCalendarBundle/Form/CalendarType.php index 76040d1f4..2827a9035 100644 --- a/src/Bundle/ChillCalendarBundle/Form/CalendarType.php +++ b/src/Bundle/ChillCalendarBundle/Form/CalendarType.php @@ -12,16 +12,15 @@ declare(strict_types=1); namespace Chill\CalendarBundle\Form; use Chill\CalendarBundle\Entity\Calendar; -use Chill\CalendarBundle\Entity\CalendarRange; use Chill\CalendarBundle\Entity\CancelReason; -use Chill\MainBundle\Entity\Location; +use Chill\CalendarBundle\Form\DataTransformer\IdToCalendarRangeDataTransformer; +use Chill\MainBundle\Form\DataTransformer\IdToLocationDataTransformer; +use Chill\MainBundle\Form\DataTransformer\IdToUserDataTransformer; +use Chill\MainBundle\Form\DataTransformer\IdToUsersDataTransformer; use Chill\MainBundle\Form\Type\CommentType; -use Chill\MainBundle\Form\Type\PickUserDynamicType; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Chill\PersonBundle\Entity\Person; -use Chill\ThirdPartyBundle\Entity\ThirdParty; +use Chill\PersonBundle\Form\DataTransformer\PersonsToIdDataTransformer; +use Chill\ThirdPartyBundle\Form\DataTransformer\ThirdPartiesToIdDataTransformer; use DateTimeImmutable; -use Doctrine\Persistence\ObjectManager; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\CallbackTransformer; @@ -32,16 +31,32 @@ use Symfony\Component\OptionsResolver\OptionsResolver; class CalendarType extends AbstractType { - protected ObjectManager $om; + private IdToCalendarRangeDataTransformer $calendarRangeDataTransformer; - protected TranslatableStringHelper $translatableStringHelper; + private IdToLocationDataTransformer $idToLocationDataTransformer; + + private IdToUserDataTransformer $idToUserDataTransformer; + + private IdToUsersDataTransformer $idToUsersDataTransformer; + + private ThirdPartiesToIdDataTransformer $partiesToIdDataTransformer; + + private PersonsToIdDataTransformer $personsToIdDataTransformer; public function __construct( - TranslatableStringHelper $translatableStringHelper, - ObjectManager $om + PersonsToIdDataTransformer $personsToIdDataTransformer, + IdToUserDataTransformer $idToUserDataTransformer, + IdToUsersDataTransformer $idToUsersDataTransformer, + IdToLocationDataTransformer $idToLocationDataTransformer, + ThirdPartiesToIdDataTransformer $partiesToIdDataTransformer, + IdToCalendarRangeDataTransformer $idToCalendarRangeDataTransformer ) { - $this->translatableStringHelper = $translatableStringHelper; - $this->om = $om; + $this->personsToIdDataTransformer = $personsToIdDataTransformer; + $this->idToUserDataTransformer = $idToUserDataTransformer; + $this->idToUsersDataTransformer = $idToUsersDataTransformer; + $this->idToLocationDataTransformer = $idToLocationDataTransformer; + $this->partiesToIdDataTransformer = $partiesToIdDataTransformer; + $this->calendarRangeDataTransformer = $idToCalendarRangeDataTransformer; } public function buildForm(FormBuilderInterface $builder, array $options) @@ -67,11 +82,8 @@ class CalendarType extends AbstractType ]); if ($options['data'] instanceof Calendar && $options['data']->getId() === null) { - $builder->add('mainUser', PickUserDynamicType::class, [ - 'multiple' => false, - 'required' => true, - 'help' => 'chill_calendar.form.The main user is mandatory. He will organize the appointment.', - ]); + $builder->add('mainUser', HiddenType::class); + $builder->get('mainUser')->addModelTransformer($this->idToUserDataTransformer); } $builder->add('startDate', HiddenType::class); @@ -110,89 +122,20 @@ class CalendarType extends AbstractType $builder->add('persons', HiddenType::class); $builder->get('persons') - ->addModelTransformer(new CallbackTransformer( - static function (iterable $personsAsIterable): string { - $personIds = []; - - foreach ($personsAsIterable as $value) { - $personIds[] = $value->getId(); - } - - return implode(',', $personIds); - }, - function (?string $personsAsString): array { - if (null === $personsAsString) { - return []; - } - - return array_map( - fn (string $id): ?Person => $this->om->getRepository(Person::class)->findOneBy(['id' => (int) $id]), - explode(',', $personsAsString) - ); - } - )); - - $builder->add('professionals', HiddenType::class); - $builder->get('professionals') - ->addModelTransformer(new CallbackTransformer( - static function (iterable $thirdpartyAsIterable): string { - $thirdpartyIds = []; - - foreach ($thirdpartyAsIterable as $value) { - $thirdpartyIds[] = $value->getId(); - } - - return implode(',', $thirdpartyIds); - }, - function (?string $thirdpartyAsString): array { - if (null === $thirdpartyAsString) { - return []; - } - - return array_map( - fn (string $id): ?ThirdParty => $this->om->getRepository(ThirdParty::class)->findOneBy(['id' => (int) $id]), - explode(',', $thirdpartyAsString) - ); - } - )); + ->addModelTransformer($this->personsToIdDataTransformer); + /* + $builder->add('professionals', HiddenType::class); + $builder->get('professionals') + ->addModelTransformer($this->partiesToIdDataTransformer); + */ $builder->add('calendarRange', HiddenType::class); $builder->get('calendarRange') - ->addModelTransformer(new CallbackTransformer( - static function (?CalendarRange $calendarRange): ?int { - if (null !== $calendarRange) { - $res = $calendarRange->getId(); - } else { - $res = -1; - } - - return $res; - }, - function (?string $calendarRangeId): ?CalendarRange { - if (null !== $calendarRangeId) { - $res = $this->om->getRepository(CalendarRange::class)->findOneBy(['id' => (int) $calendarRangeId]); - } else { - $res = null; - } - - return $res; - } - )); + ->addModelTransformer($this->calendarRangeDataTransformer); $builder->add('location', HiddenType::class) ->get('location') - ->addModelTransformer(new CallbackTransformer( - static function (?Location $location): string { - if (null === $location) { - return ''; - } - - return $location->getId(); - }, - function (?string $id): ?Location { - return $this->om->getRepository(Location::class)->findOneBy(['id' => (int) $id]); - } - )); + ->addModelTransformer($this->idToLocationDataTransformer); } public function configureOptions(OptionsResolver $resolver) @@ -200,10 +143,6 @@ class CalendarType extends AbstractType $resolver->setDefaults([ 'data_class' => Calendar::class, ]); - - $resolver - ->setRequired(['accompanyingPeriod']) - ->setAllowedTypes('accompanyingPeriod', [\Chill\PersonBundle\Entity\AccompanyingPeriod::class, 'null']); } public function getBlockPrefix() diff --git a/src/Bundle/ChillCalendarBundle/Form/DataTransformer/IdToCalendarRangeDataTransformer.php b/src/Bundle/ChillCalendarBundle/Form/DataTransformer/IdToCalendarRangeDataTransformer.php new file mode 100644 index 000000000..69bb9eca1 --- /dev/null +++ b/src/Bundle/ChillCalendarBundle/Form/DataTransformer/IdToCalendarRangeDataTransformer.php @@ -0,0 +1,23 @@ +personsToIdDataTransformer = $this->buildMultiToIdDataTransformer(PersonsToIdDataTransformer::class, Person::class); + $this->idToUserDataTransformer = $this->buildSingleToIdDataTransformer(IdToUserDataTransformer::class, User::class); + $this->idToUsersDataTransformer = $this->buildMultiToIdDataTransformer(IdToUsersDataTransformer::class, User::class); + $this->idToLocationDataTransformer = $this->buildSingleToIdDataTransformer(IdToLocationDataTransformer::class, Location::class); + $this->partiesToIdDataTransformer = $this->buildMultiToIdDataTransformer(ThirdPartiesToIdDataTransformer::class, ThirdParty::class); + $this->calendarRangeDataTransformer = $this->buildSingleToIdDataTransformer(IdToCalendarRangeDataTransformer::class, CalendarRange::class); + $tokenStorage = $this->prophesize(TokenStorageInterface::class); + $token = $this->prophesize(TokenInterface::class); + $token->getUser()->willReturn(new User()); + $tokenStorage->getToken()->willReturn($token->reveal()); + $this->tokenStorage = $tokenStorage->reveal(); + + parent::setUp(); + } + + public function testSubmitValidData() + { + $formData = [ + 'mainUser' => '1', + 'users' => '2,3', + 'professionnals' => '4,5', + 'startDate' => '2022-05-05 14:00:00', + 'endDate' => '2022-05-05 14:30:00', + 'persons' => '7', + 'calendarRange' => '8', + 'location' => '9', + 'sendSMS' => '1', + ]; + + $calendar = new Calendar(); + $calendar->setMainUser(new class() extends User { + public function getId() + { + return '1'; + } + }); + + $form = $this->factory->create(CalendarType::class, $calendar); + + $form->submit($formData); + + $this->assertTrue($form->isSynchronized()); + $this->assertEquals(DateTimeImmutable::createFromFormat('Y-m-d H:i:s', '2022-05-05 14:00:00'), $calendar->getStartDate()); + $this->assertEquals(DateTimeImmutable::createFromFormat('Y-m-d H:i:s', '2022-05-05 14:30:00'), $calendar->getEndDate()); + $this->assertEquals(7, $calendar->getPersons()->first()->getId()); + $this->assertEquals(8, $calendar->getCalendarRange()->getId()); + $this->assertEquals(9, $calendar->getLocation()->getId()); + $this->assertEquals(true, $calendar->getSendSMS()); + } + + protected function getExtensions() + { + $parents = parent::getExtensions(); + + $calendarType = new CalendarType( + $this->personsToIdDataTransformer, + $this->idToUserDataTransformer, + $this->idToUsersDataTransformer, + $this->idToLocationDataTransformer, + $this->partiesToIdDataTransformer, + $this->calendarRangeDataTransformer + ); + $commentType = new CommentType($this->tokenStorage); + + return array_merge( + parent::getExtensions(), + [new PreloadedExtension([$calendarType, $commentType], [])] + ); + } + + private function buildMultiToIdDataTransformer( + string $classTransformer, + string $objClass + ) { + $transformer = $this->prophesize($classTransformer); + $transformer->transform(Argument::type('array')) + ->will(static function ($args) { + return implode( + ',', + array_map(static function ($p) { return $p->getId(); }, $args[0]) + ); + }); + $transformer->transform(Argument::exact(null)) + ->willReturn([]); + $transformer->transform(Argument::type(Collection::class)) + ->will(static function ($args) { + return implode( + ',', + array_map(static function ($p) { return $p->getId(); }, $args[0]->toArray()) + ); + }); + $transformer->reverseTransform(Argument::type('string')) + ->will(static function ($args) use ($objClass) { + if (null === $args[0]) { + return []; + } + + return array_map( + static function ($id) use ($objClass) { + $obj = new $objClass(); + $reflectionProperty = new ReflectionProperty($objClass, 'id'); + $reflectionProperty->setAccessible(true); + $reflectionProperty->setValue($obj, (int) $id); + + return $obj; + }, + explode(',', $args[0]) + ); + }); + + return $transformer->reveal(); + } + + private function buildSingleToIdDataTransformer( + string $classTransformer, + string $class + ) { + $transformer = $this->prophesize($classTransformer); + $transformer->transform(Argument::type('object')) + ->will(static function ($args) { + return (string) $args[0]->getId(); + }); + $transformer->transform(Argument::exact(null)) + ->willReturn(''); + $transformer->reverseTransform(Argument::type('string')) + ->will(static function ($args) use ($class) { + if (null === $args[0]) { + return null; + } + $obj = new $class(); + $reflectionProperty = new ReflectionProperty($class, 'id'); + $reflectionProperty->setAccessible(true); + $reflectionProperty->setValue($obj, (int) $args[0]); + + return $obj; + }); + + return $transformer->reveal(); + } +} diff --git a/src/Bundle/ChillMainBundle/Form/DataTransformer/IdToEntityDataTransformer.php b/src/Bundle/ChillMainBundle/Form/DataTransformer/IdToEntityDataTransformer.php index 0c433aec5..4e565ef0e 100644 --- a/src/Bundle/ChillMainBundle/Form/DataTransformer/IdToEntityDataTransformer.php +++ b/src/Bundle/ChillMainBundle/Form/DataTransformer/IdToEntityDataTransformer.php @@ -14,6 +14,7 @@ namespace Chill\MainBundle\Form\DataTransformer; use Closure; use Doctrine\Persistence\ObjectRepository; use Symfony\Component\Form\DataTransformerInterface; +use Symfony\Component\Form\Exception\TransformationFailedException; use function call_user_func; /** @@ -59,7 +60,13 @@ class IdToEntityDataTransformer implements DataTransformerInterface return null; } - return $this->repository->findOneBy(['id' => (int) $value]); + $object = $this->repository->findOneBy(['id' => (int) $value]); + + if (null === $object) { + throw new TransformationFailedException('could not find any object by object id'); + } + + return $object; } /** @@ -71,12 +78,22 @@ class IdToEntityDataTransformer implements DataTransformerInterface $ids = []; foreach ($value as $v) { - $ids[] = call_user_func($this->getId, $v); + $ids[] = $id = call_user_func($this->getId, $v); + + if (null === $id) { + throw new TransformationFailedException('id is null'); + } } return implode(',', $ids); } - return call_user_func($this->getId, $value); + $id = call_user_func($this->getId, $value); + + if (null === $id) { + throw new TransformationFailedException('id is null'); + } + + return (string) $id; } } diff --git a/src/Bundle/ChillMainBundle/Form/DataTransformer/IdToLocationDataTransformer.php b/src/Bundle/ChillMainBundle/Form/DataTransformer/IdToLocationDataTransformer.php new file mode 100644 index 000000000..f75316956 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Form/DataTransformer/IdToLocationDataTransformer.php @@ -0,0 +1,22 @@ +om = $om; - } - - /** - * Transforms a string (id) to an object (issue). - * - * @param string $id - * - * @throws TransformationFailedException if object (issue) is not found. - * - * @return Person|null - */ - public function reverseTransform($id) - { - if (!$id) { - return null; - } - - $issue = $this->om - ->getRepository(\Chill\PersonBundle\Entity\Person::class) - ->findOneBy(['id' => $id]); - - if (null === $issue) { - throw new TransformationFailedException(sprintf( - 'An issue with id "%s" does not exist!', - $id - )); - } - - return $issue; - } - - /** - * Transforms an object (issue) to a string (id). - * - * @param Person|null $issue - * - * @return string - */ - public function transform($issue) - { - if (null === $issue) { - return ''; - } - - return $issue->getId(); + parent::__construct($repository, false); } } diff --git a/src/Bundle/ChillPersonBundle/Form/DataTransformer/PersonsToIdDataTransformer.php b/src/Bundle/ChillPersonBundle/Form/DataTransformer/PersonsToIdDataTransformer.php new file mode 100644 index 000000000..b42642a58 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Form/DataTransformer/PersonsToIdDataTransformer.php @@ -0,0 +1,23 @@ +