From 280d222341d30e39c8ca5a1dc87a2d77a4f3add8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Fr=C3=A9mont?= Date: Tue, 1 Oct 2024 11:23:40 +0200 Subject: [PATCH] Init boolean filter and conference resource --- app/DataFixtures/AppFixtures.php | 6 +- app/Entity/Conference.php | 105 ++++++++++++++++++ app/Entity/Talk.php | 14 +++ app/Factory/ConferenceFactory.php | 58 ++++++++++ app/Factory/TalkFactory.php | 11 ++ app/Form/ConferenceType.php | 42 +++++++ app/Grid/ConferenceGrid.php | 102 +++++++++++++++++ app/Grid/TalkGrid.php | 6 + app/Menu/AdminMenuBuilder.php | 4 + app/Repository/ConferenceRepository.php | 29 +++++ app/Story/DefaultConferencesStory.php | 40 +++++++ ...php => DefaultSyliusCon2024TalksStory.php} | 24 +++- .../config/app/grid/templates.php | 1 + .../shared/grid/filter/boolean.html.twig | 3 + .../config/services/twig/extension.php | 5 + .../Extension/MergeRecursiveExtension.php | 40 +++++++ .../Extension/MergeRecursiveExtensionTest.php | 30 +++++ .../Extension/MergeRecursiveExtensionTest.php | 41 +++++++ .../translations/messages.en.yaml | 2 + tests/Functional/ConferenceTest.php | 66 +++++++++++ translations/messages.en.yaml | 3 + 21 files changed, 629 insertions(+), 3 deletions(-) create mode 100644 app/Entity/Conference.php create mode 100644 app/Factory/ConferenceFactory.php create mode 100644 app/Form/ConferenceType.php create mode 100644 app/Grid/ConferenceGrid.php create mode 100644 app/Repository/ConferenceRepository.php create mode 100644 app/Story/DefaultConferencesStory.php rename app/Story/{DefaultTalksStory.php => DefaultSyliusCon2024TalksStory.php} (89%) create mode 100644 src/BootstrapAdminUi/templates/shared/grid/filter/boolean.html.twig create mode 100644 src/TwigExtra/src/Twig/Extension/MergeRecursiveExtension.php create mode 100644 src/TwigExtra/tests/Integration/Twig/Extension/MergeRecursiveExtensionTest.php create mode 100644 src/TwigExtra/tests/Unit/Twig/Extension/MergeRecursiveExtensionTest.php create mode 100644 tests/Functional/ConferenceTest.php diff --git a/app/DataFixtures/AppFixtures.php b/app/DataFixtures/AppFixtures.php index f0c6da6a..cad5f0e4 100644 --- a/app/DataFixtures/AppFixtures.php +++ b/app/DataFixtures/AppFixtures.php @@ -14,8 +14,9 @@ namespace App\DataFixtures; use App\Story\DefaultBooksStory; +use App\Story\DefaultConferencesStory; use App\Story\DefaultSpeakersStory; -use App\Story\DefaultTalksStory; +use App\Story\DefaultSyliusCon2024TalksStory; use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Persistence\ObjectManager; @@ -24,7 +25,8 @@ class AppFixtures extends Fixture public function load(ObjectManager $manager): void { DefaultBooksStory::load(); + DefaultConferencesStory::load(); DefaultSpeakersStory::load(); - DefaultTalksStory::load(); + DefaultSyliusCon2024TalksStory::load(); } } diff --git a/app/Entity/Conference.php b/app/Entity/Conference.php new file mode 100644 index 00000000..24a93065 --- /dev/null +++ b/app/Entity/Conference.php @@ -0,0 +1,105 @@ +id; + } + + public function getName(): ?string + { + return $this->name; + } + + public function setName(string $name): void + { + $this->name = $name; + } + + public function getStartsAt(): ?\DateTimeImmutable + { + return $this->startsAt; + } + + public function setStartsAt(\DateTimeImmutable $startsAt): void + { + $this->startsAt = $startsAt; + } + + public function getEndsAt(): ?\DateTimeImmutable + { + return $this->endsAt; + } + + public function setEndsAt(\DateTimeImmutable $endsAt): void + { + $this->endsAt = $endsAt; + } + + public function isPastEvent(): ?bool + { + return $this->pastEvent; + } + + public function setPastEvent(bool $pastEvent): void + { + $this->pastEvent = $pastEvent; + } +} diff --git a/app/Entity/Talk.php b/app/Entity/Talk.php index 4ace5f49..010957c7 100644 --- a/app/Entity/Talk.php +++ b/app/Entity/Talk.php @@ -67,6 +67,10 @@ class Talk implements ResourceInterface #[ORM\Column(enumType: Track::class)] private ?Track $track = null; + #[ORM\ManyToOne] + #[ORM\JoinColumn(nullable: false)] + private ?Conference $conference = null; + public function getId(): ?int { return $this->id; @@ -131,4 +135,14 @@ public function setTrack(Track $track): void { $this->track = $track; } + + public function getConference(): ?Conference + { + return $this->conference; + } + + public function setConference(?Conference $conference): void + { + $this->conference = $conference; + } } diff --git a/app/Factory/ConferenceFactory.php b/app/Factory/ConferenceFactory.php new file mode 100644 index 00000000..09f06cf7 --- /dev/null +++ b/app/Factory/ConferenceFactory.php @@ -0,0 +1,58 @@ + + */ +final class ConferenceFactory extends PersistentProxyObjectFactory +{ + public static function class(): string + { + return Conference::class; + } + + public function withName(string $name): self + { + return $this->with(['name' => $name]); + } + + public function withStartingDate(\DateTimeImmutable $startsAt): self + { + return $this->with(['startsAt' => $startsAt]); + } + + public function withEndingDate(\DateTimeImmutable $endsAt): self + { + return $this->with(['endsAt' => $endsAt]); + } + + public function pastEvent(bool $pastEvent): self + { + return $this->with(['pastEvent' => $pastEvent]); + } + + protected function defaults(): array|callable + { + return [ + 'endsAt' => \DateTimeImmutable::createFromMutable(self::faker()->dateTime()), + 'name' => ucfirst(self::faker()->words(2, true)) . ' ' . self::faker()->year(), + 'pastEvent' => self::faker()->boolean(), + 'startsAt' => \DateTimeImmutable::createFromMutable(self::faker()->dateTime()), + ]; + } +} diff --git a/app/Factory/TalkFactory.php b/app/Factory/TalkFactory.php index b73db6fd..4aa11376 100644 --- a/app/Factory/TalkFactory.php +++ b/app/Factory/TalkFactory.php @@ -13,9 +13,11 @@ namespace App\Factory; +use App\Entity\Conference; use App\Entity\Speaker; use App\Entity\Talk; use App\Enum\Track; +use function Zenstruck\Foundry\lazy; use Zenstruck\Foundry\Persistence\PersistentProxyObjectFactory; use Zenstruck\Foundry\Persistence\Proxy; @@ -60,6 +62,14 @@ public function withTrack(Track $track): self return $this->with(['track' => $track]); } + /** + * @param Proxy|Conference $conference + */ + public function withConference(Proxy|Conference $conference): self + { + return $this->with(['conference' => $conference]); + } + protected function defaults(): array|callable { return [ @@ -68,6 +78,7 @@ protected function defaults(): array|callable 'startsAt' => \DateTimeImmutable::createFromMutable(self::faker()->dateTime()), 'endsAt' => \DateTimeImmutable::createFromMutable(self::faker()->dateTime()), 'track' => self::faker()->randomElement(Track::cases()), + 'conference' => lazy(fn () => ConferenceFactory::randomOrCreate()), ]; } } diff --git a/app/Form/ConferenceType.php b/app/Form/ConferenceType.php new file mode 100644 index 00000000..a49b547a --- /dev/null +++ b/app/Form/ConferenceType.php @@ -0,0 +1,42 @@ +add('name') + ->add('startsAt', null, [ + 'widget' => 'single_text', + ]) + ->add('endsAt', null, [ + 'widget' => 'single_text', + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'data_class' => Conference::class, + ]); + } +} diff --git a/app/Grid/ConferenceGrid.php b/app/Grid/ConferenceGrid.php new file mode 100644 index 00000000..d7fcd20d --- /dev/null +++ b/app/Grid/ConferenceGrid.php @@ -0,0 +1,102 @@ +addOrderBy('startsAt', 'desc') + ->addFilter( + BooleanFilter::create('pastEvent') + ->setLabel('app.ui.past_event'), + ) + ->addFilter( + DateFilter::create('startsAt') + ->setLabel('app.ui.starts_at'), + ) + ->addField( + StringField::create('name') + ->setLabel('Name') + ->setSortable(true), + ) + ->addField( + DateTimeField::create('startsAt') + ->setLabel('app.ui.starts_at') + ->setSortable(true), + ) + ->addField( + DateTimeField::create('endsAt') + ->setLabel('app.ui.ends_at') + ->setSortable(true), + ) + ->addActionGroup( + MainActionGroup::create( + CreateAction::create(), + ), + ) + ->addActionGroup( + ItemActionGroup::create( + Action::create('show_talks', 'show') + ->setIcon('list_letters') + ->setLabel('app.ui.show_talks') + ->setOptions([ + 'link' => [ + 'route' => 'app_admin_talk_index', + 'parameters' => [ + 'criteria' => [ + 'conference' => 'resource.id', + ], + ], + ], + ]), + UpdateAction::create(), + DeleteAction::create(), + ), + ) + ->addActionGroup( + BulkActionGroup::create( + DeleteAction::create(), + ), + ) + ; + } + + public function getResourceClass(): string + { + return Conference::class; + } +} diff --git a/app/Grid/TalkGrid.php b/app/Grid/TalkGrid.php index 8f70e79a..9d4d8f72 100644 --- a/app/Grid/TalkGrid.php +++ b/app/Grid/TalkGrid.php @@ -13,6 +13,7 @@ namespace App\Grid; +use App\Entity\Conference; use App\Entity\Speaker; use App\Entity\Talk; use App\Enum\Track; @@ -43,6 +44,11 @@ public function buildGrid(GridBuilderInterface $gridBuilder): void { $gridBuilder ->addOrderBy('startsAt') + ->addFilter( + EntityFilter::create('conference', Conference::class) + ->setLabel('app.ui.conference') + ->addFormOption('choice_label', 'name'), + ) ->addFilter( EntityFilter::create('speaker', Speaker::class) ->setLabel('app.ui.speaker') diff --git a/app/Menu/AdminMenuBuilder.php b/app/Menu/AdminMenuBuilder.php index e89a7918..9c6a09a3 100644 --- a/app/Menu/AdminMenuBuilder.php +++ b/app/Menu/AdminMenuBuilder.php @@ -62,6 +62,10 @@ private function addConfigurationSubMenu(ItemInterface $menu): void ->setLabelAttribute('icon', 'dashboard') ; + $configuration->addChild('conferences', ['route' => 'app_admin_conference_index']) + ->setLabel('app.ui.conferences') + ; + $configuration->addChild('talks', ['route' => 'app_admin_talk_index']) ->setLabel('app.ui.talks') ; diff --git a/app/Repository/ConferenceRepository.php b/app/Repository/ConferenceRepository.php new file mode 100644 index 00000000..9f447fbb --- /dev/null +++ b/app/Repository/ConferenceRepository.php @@ -0,0 +1,29 @@ + + */ +class ConferenceRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Conference::class); + } +} diff --git a/app/Story/DefaultConferencesStory.php b/app/Story/DefaultConferencesStory.php new file mode 100644 index 00000000..148ee3fc --- /dev/null +++ b/app/Story/DefaultConferencesStory.php @@ -0,0 +1,40 @@ +withName('SyliusCon 2024') + ->withStartingDate(new DateTimeImmutable('2024-11-13 09:00:00')) + ->withEndingDate(new DateTimeImmutable('2024-11-13 18:00:00')) + ->pastEvent(false) + ->create() + ; + + ConferenceFactory::new() + ->withName('SyliusCon 2023') + ->withStartingDate(new DateTimeImmutable('2023-11-03 09:00:00')) + ->withEndingDate(new DateTimeImmutable('2023-11-03 18:00:00')) + ->pastEvent(true) + ->create() + ; + } +} diff --git a/app/Story/DefaultTalksStory.php b/app/Story/DefaultSyliusCon2024TalksStory.php similarity index 89% rename from app/Story/DefaultTalksStory.php rename to app/Story/DefaultSyliusCon2024TalksStory.php index bf7a3bf3..fd663b7c 100644 --- a/app/Story/DefaultTalksStory.php +++ b/app/Story/DefaultSyliusCon2024TalksStory.php @@ -14,11 +14,12 @@ namespace App\Story; use App\Enum\Track; +use App\Factory\ConferenceFactory; use App\Factory\SpeakerFactory; use App\Factory\TalkFactory; use Zenstruck\Foundry\Story; -final class DefaultTalksStory extends Story +final class DefaultSyliusCon2024TalksStory extends Story { public function build(): void { @@ -40,6 +41,7 @@ private function createBizTalks(): void ->withStartingDate(new \DateTimeImmutable('2024-11-13 10:00:00')) ->withEndingDate(new \DateTimeImmutable('2024-11-13 10:45:00')) ->withTrack(Track::BIZ) + ->withConference(ConferenceFactory::findOrCreate(['name' => 'SyliusCon 2024'])) ->create() ; @@ -54,6 +56,7 @@ private function createBizTalks(): void ->withStartingDate(new \DateTimeImmutable('2024-11-13 11:00:00')) ->withEndingDate(new \DateTimeImmutable('2024-11-13 11:45:00')) ->withTrack(Track::BIZ) + ->withConference(ConferenceFactory::findOrCreate(['name' => 'SyliusCon 2024'])) ->create() ; @@ -68,6 +71,7 @@ private function createBizTalks(): void ->withStartingDate(new \DateTimeImmutable('2024-11-13 12:00:00')) ->withEndingDate(new \DateTimeImmutable('2024-11-13 12:30:00')) ->withTrack(Track::BIZ) + ->withConference(ConferenceFactory::findOrCreate(['name' => 'SyliusCon 2024'])) ->create() ; @@ -82,6 +86,7 @@ private function createBizTalks(): void ->withStartingDate(new \DateTimeImmutable('2024-11-13 12:45:00')) ->withEndingDate(new \DateTimeImmutable('2024-11-13 13:15:00')) ->withTrack(Track::BIZ) + ->withConference(ConferenceFactory::findOrCreate(['name' => 'SyliusCon 2024'])) ->create() ; @@ -96,6 +101,7 @@ private function createBizTalks(): void ->withStartingDate(new \DateTimeImmutable('2024-11-13 15:45:00')) ->withEndingDate(new \DateTimeImmutable('2024-11-13 16:15:00')) ->withTrack(Track::BIZ) + ->withConference(ConferenceFactory::findOrCreate(['name' => 'SyliusCon 2024'])) ->create() ; @@ -110,6 +116,7 @@ private function createBizTalks(): void ->withStartingDate(new \DateTimeImmutable('2024-11-13 16:30:00')) ->withEndingDate(new \DateTimeImmutable('2024-11-13 17:15:00')) ->withTrack(Track::BIZ) + ->withConference(ConferenceFactory::findOrCreate(['name' => 'SyliusCon 2024'])) ->create() ; @@ -124,6 +131,7 @@ private function createBizTalks(): void ->withStartingDate(new \DateTimeImmutable('2024-11-13 17:30:00')) ->withEndingDate(new \DateTimeImmutable('2024-11-13 18:00:00')) ->withTrack(Track::BIZ) + ->withConference(ConferenceFactory::findOrCreate(['name' => 'SyliusCon 2024'])) ->create() ; } @@ -141,6 +149,7 @@ private function createTechOneTalks(): void ->withStartingDate(new \DateTimeImmutable('2024-11-13 10:00:00')) ->withEndingDate(new \DateTimeImmutable('2024-11-13 10:45:00')) ->withTrack(Track::TECH_ONE) + ->withConference(ConferenceFactory::findOrCreate(['name' => 'SyliusCon 2024'])) ->create() ; @@ -155,6 +164,7 @@ private function createTechOneTalks(): void ->withStartingDate(new \DateTimeImmutable('2024-11-13 11:00:00')) ->withEndingDate(new \DateTimeImmutable('2024-11-13 11:45:00')) ->withTrack(Track::TECH_ONE) + ->withConference(ConferenceFactory::findOrCreate(['name' => 'SyliusCon 2024'])) ->create() ; @@ -169,6 +179,7 @@ private function createTechOneTalks(): void ->withStartingDate(new \DateTimeImmutable('2024-11-13 12:00:00')) ->withEndingDate(new \DateTimeImmutable('2024-11-13 12:30:00')) ->withTrack(Track::TECH_ONE) + ->withConference(ConferenceFactory::findOrCreate(['name' => 'SyliusCon 2024'])) ->create() ; @@ -184,6 +195,7 @@ private function createTechOneTalks(): void ->withStartingDate(new \DateTimeImmutable('2024-11-13 12:45:00')) ->withEndingDate(new \DateTimeImmutable('2024-11-13 13:30:00')) ->withTrack(Track::TECH_ONE) + ->withConference(ConferenceFactory::findOrCreate(['name' => 'SyliusCon 2024'])) ->create() ; @@ -198,6 +210,7 @@ private function createTechOneTalks(): void ->withStartingDate(new \DateTimeImmutable('2024-11-13 15:30:00')) ->withEndingDate(new \DateTimeImmutable('2024-11-13 16:15:00')) ->withTrack(Track::TECH_ONE) + ->withConference(ConferenceFactory::findOrCreate(['name' => 'SyliusCon 2024'])) ->create() ; @@ -213,6 +226,7 @@ private function createTechOneTalks(): void ->withStartingDate(new \DateTimeImmutable('2024-11-13 16:30:00')) ->withEndingDate(new \DateTimeImmutable('2024-11-13 17:15:00')) ->withTrack(Track::TECH_ONE) + ->withConference(ConferenceFactory::findOrCreate(['name' => 'SyliusCon 2024'])) ->create() ; @@ -227,6 +241,7 @@ private function createTechOneTalks(): void ->withStartingDate(new \DateTimeImmutable('2024-11-13 17:30:00')) ->withEndingDate(new \DateTimeImmutable('2024-11-13 18:00:00')) ->withTrack(Track::TECH_ONE) + ->withConference(ConferenceFactory::findOrCreate(['name' => 'SyliusCon 2024'])) ->create() ; } @@ -244,6 +259,7 @@ private function createTechTwoTalks(): void ->withStartingDate(new \DateTimeImmutable('2024-11-13 10:00:00')) ->withEndingDate(new \DateTimeImmutable('2024-11-13 10:45:00')) ->withTrack(Track::TECH_TWO) + ->withConference(ConferenceFactory::findOrCreate(['name' => 'SyliusCon 2024'])) ->create() ; @@ -257,6 +273,7 @@ private function createTechTwoTalks(): void ) ->withStartingDate(new \DateTimeImmutable('2024-11-13 11:00:00')) ->withEndingDate(new \DateTimeImmutable('2024-11-13 11:45:00')) + ->withConference(ConferenceFactory::findOrCreate(['name' => 'SyliusCon 2024'])) ->create() ; @@ -271,6 +288,7 @@ private function createTechTwoTalks(): void ->withStartingDate(new \DateTimeImmutable('2024-11-13 12:00:00')) ->withEndingDate(new \DateTimeImmutable('2024-11-13 12:30:00')) ->withTrack(Track::TECH_TWO) + ->withConference(ConferenceFactory::findOrCreate(['name' => 'SyliusCon 2024'])) ->create() ; @@ -285,6 +303,7 @@ private function createTechTwoTalks(): void ->withStartingDate(new \DateTimeImmutable('2024-11-13 12:45:00')) ->withEndingDate(new \DateTimeImmutable('2024-11-13 13:30:00')) ->withTrack(Track::TECH_TWO) + ->withConference(ConferenceFactory::findOrCreate(['name' => 'SyliusCon 2024'])) ->create() ; @@ -299,6 +318,7 @@ private function createTechTwoTalks(): void ->withStartingDate(new \DateTimeImmutable('2024-11-13 15:30:00')) ->withEndingDate(new \DateTimeImmutable('2024-11-13 16:15:00')) ->withTrack(Track::TECH_TWO) + ->withConference(ConferenceFactory::findOrCreate(['name' => 'SyliusCon 2024'])) ->create() ; @@ -313,6 +333,7 @@ private function createTechTwoTalks(): void ->withStartingDate(new \DateTimeImmutable('2024-11-13 15:30:00')) ->withEndingDate(new \DateTimeImmutable('2024-11-13 17:15:00')) ->withTrack(Track::TECH_TWO) + ->withConference(ConferenceFactory::findOrCreate(['name' => 'SyliusCon 2024'])) ->create() ; @@ -327,6 +348,7 @@ private function createTechTwoTalks(): void ->withStartingDate(new \DateTimeImmutable('2024-11-13 17:30:00')) ->withEndingDate(new \DateTimeImmutable('2024-11-13 18:00:00')) ->withTrack(Track::TECH_TWO) + ->withConference(ConferenceFactory::findOrCreate(['name' => 'SyliusCon 2024'])) ->create() ; } diff --git a/src/BootstrapAdminUi/config/app/grid/templates.php b/src/BootstrapAdminUi/config/app/grid/templates.php index ed385e16..bf1e7843 100644 --- a/src/BootstrapAdminUi/config/app/grid/templates.php +++ b/src/BootstrapAdminUi/config/app/grid/templates.php @@ -26,6 +26,7 @@ 'delete' => '@SyliusBootstrapAdminUi/shared/grid/bulk_action/delete.html.twig', ], 'filter' => [ + 'boolean' => '@SyliusBootstrapAdminUi/shared/grid/filter/boolean.html.twig', 'date' => '@SyliusBootstrapAdminUi/shared/grid/filter/date.html.twig', 'entity' => '@SyliusBootstrapAdminUi/shared/grid/filter/entity.html.twig', 'select' => '@SyliusBootstrapAdminUi/shared/grid/filter/select.html.twig', diff --git a/src/BootstrapAdminUi/templates/shared/grid/filter/boolean.html.twig b/src/BootstrapAdminUi/templates/shared/grid/filter/boolean.html.twig new file mode 100644 index 00000000..4bce6c82 --- /dev/null +++ b/src/BootstrapAdminUi/templates/shared/grid/filter/boolean.html.twig @@ -0,0 +1,3 @@ +{% form_theme form '@SyliusBootstrapAdminUi/shared/form_theme.html.twig' %} + +{{ form_row(form, sylius_test_form_attribute('criterion-enabled')|sylius_merge_recursive({'label': filter.label})) }} diff --git a/src/TwigExtra/config/services/twig/extension.php b/src/TwigExtra/config/services/twig/extension.php index 74dec6c2..47078788 100644 --- a/src/TwigExtra/config/services/twig/extension.php +++ b/src/TwigExtra/config/services/twig/extension.php @@ -13,6 +13,7 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; +use Sylius\TwigExtra\Twig\Extension\MergeRecursiveExtension; use Sylius\TwigExtra\Twig\Extension\RouteExistsExtension; use Sylius\TwigExtra\Twig\Extension\SortByExtension; use Sylius\TwigExtra\Twig\Extension\TestFormAttributeExtension; @@ -21,6 +22,10 @@ return function (ContainerConfigurator $configurator): void { $services = $configurator->services(); + $services->set('sylius_twig_extra.twig.extension.merge_recursive', MergeRecursiveExtension::class) + ->tag(name: 'twig.extension') + ; + $services->set('sylius_twig_extra.twig.extension.sort_by', SortByExtension::class) ->tag(name: 'twig.extension') ; diff --git a/src/TwigExtra/src/Twig/Extension/MergeRecursiveExtension.php b/src/TwigExtra/src/Twig/Extension/MergeRecursiveExtension.php new file mode 100644 index 00000000..0f87fcec --- /dev/null +++ b/src/TwigExtra/src/Twig/Extension/MergeRecursiveExtension.php @@ -0,0 +1,40 @@ + $this->mergeRecursive($firstArray, $secondArray), + ), + ]; + } + + /** + * @param mixed[] ...$arrays + * + * @return mixed[] + */ + public function mergeRecursive(array ...$arrays): array + { + return array_merge_recursive(...$arrays); + } +} diff --git a/src/TwigExtra/tests/Integration/Twig/Extension/MergeRecursiveExtensionTest.php b/src/TwigExtra/tests/Integration/Twig/Extension/MergeRecursiveExtensionTest.php new file mode 100644 index 00000000..0b04b12a --- /dev/null +++ b/src/TwigExtra/tests/Integration/Twig/Extension/MergeRecursiveExtensionTest.php @@ -0,0 +1,30 @@ +bootKernel(); + + $container = $this->getContainer(); + + $this->assertTrue($container->has('sylius_twig_extra.twig.extension.merge_recursive')); + $this->assertInstanceOf(MergeRecursiveExtension::class, $container->get('sylius_twig_extra.twig.extension.merge_recursive')); + } +} diff --git a/src/TwigExtra/tests/Unit/Twig/Extension/MergeRecursiveExtensionTest.php b/src/TwigExtra/tests/Unit/Twig/Extension/MergeRecursiveExtensionTest.php new file mode 100644 index 00000000..3ff2d2d5 --- /dev/null +++ b/src/TwigExtra/tests/Unit/Twig/Extension/MergeRecursiveExtensionTest.php @@ -0,0 +1,41 @@ +assertInstanceOf(ExtensionInterface::class, new MergeRecursiveExtension()); + } + + public function testItMergesArraysRecursively(): void + { + $firstArray = ['color' => ['favorite' => 'red'], 5]; + $secondArray = [10, 'color' => ['favorite' => 'green', 'blue']]; + + $this->assertEquals([ + 'color' => [ + 'favorite' => ['red', 'green'], + 'blue', + ], + 5, + 10, + ], (new MergeRecursiveExtension())->mergeRecursive($firstArray, $secondArray)); + } +} diff --git a/src/UiTranslations/translations/messages.en.yaml b/src/UiTranslations/translations/messages.en.yaml index 99b43f98..1291dc16 100644 --- a/src/UiTranslations/translations/messages.en.yaml +++ b/src/UiTranslations/translations/messages.en.yaml @@ -18,6 +18,7 @@ sylius: from: From info: Info new: New + no_label: No no_results: No results found no_results_adjust_your_search: 'Adjust your search and try again.' pagination: @@ -32,3 +33,4 @@ sylius: update: Update value: Value warning: Warning + yes_label: Yes diff --git a/tests/Functional/ConferenceTest.php b/tests/Functional/ConferenceTest.php new file mode 100644 index 00000000..388ff77f --- /dev/null +++ b/tests/Functional/ConferenceTest.php @@ -0,0 +1,66 @@ +client = self::createClient(); + } + + public function testBrowsingConferences(): void + { + ConferenceFactory::new() + ->withName('SyliusCon 2024') + ->withStartingDate(new \DateTimeImmutable('2024-11-13 09:00:00')) + ->withEndingDate(new \DateTimeImmutable('2024-11-13 18:00:00')) + ->create() + ; + + ConferenceFactory::new() + ->withName('SyliusCon 2023') + ->withStartingDate(new \DateTimeImmutable('2023-11-03 09:00:00')) + ->withEndingDate(new \DateTimeImmutable('2023-11-03 18:00:00')) + ->create() + ; + + $this->client->request('GET', '/admin/conferences'); + + self::assertResponseIsSuccessful(); + + // Validate Header + self::assertSelectorTextContains('h1.page-title', 'Conferences'); + self::assertSelectorExists('a:contains("Create")'); + + // Validate Table header + self::assertSelectorTextContains('.sylius-table-column-name', 'Name'); + self::assertSelectorTextContains('.sylius-table-column-startsAt', 'Starts at'); + self::assertSelectorTextContains('.sylius-table-column-endsAt', 'Ends at'); + self::assertSelectorTextContains('.sylius-table-column-actions', 'Actions'); + + // Validate Table data + self::assertSelectorTextContains('tr.item:first-child', 'SyliusCon 2024'); + self::assertSelectorTextContains('tr.item:first-child', '2024-11-13 09:00:00'); + self::assertSelectorTextContains('tr.item:first-child', '2024-11-13 18:00:00'); + self::assertSelectorExists('tr.item:first-child [data-bs-title=Edit]'); + self::assertSelectorExists('tr.item:first-child [data-bs-title=Delete]'); + + self::assertSelectorTextContains('tr.item:last-child', 'SyliusCon 2023'); + self::assertSelectorTextContains('tr.item:last-child', '2023-11-03 09:00:00'); + self::assertSelectorTextContains('tr.item:last-child', '2023-11-03 18:00:00'); + self::assertSelectorExists('tr.item:last-child [data-bs-title=Edit]'); + self::assertSelectorExists('tr.item:last-child [data-bs-title=Delete]'); + } +} diff --git a/translations/messages.en.yaml b/translations/messages.en.yaml index e81c2b2b..625a8617 100644 --- a/translations/messages.en.yaml +++ b/translations/messages.en.yaml @@ -5,11 +5,14 @@ app: book: Book books: Books company_name: Company name + conference: Conference + conferences: Conferences configuration: Configuration ends_at: Ends at first_name: First name last_name: Last name library: Library + past_event: Past event show_talks: Show talks speaker: Speaker speakers: Speakers