diff --git a/config/forms/event_details.xml b/config/forms/event_details.xml index c30baef..2de73ca 100644 --- a/config/forms/event_details.xml +++ b/config/forms/event_details.xml @@ -24,7 +24,7 @@ - + app.location diff --git a/config/packages/sulu_admin.yaml b/config/packages/sulu_admin.yaml index 46a5f0e..31184bc 100644 --- a/config/packages/sulu_admin.yaml +++ b/config/packages/sulu_admin.yaml @@ -38,3 +38,17 @@ sulu_admin: icon: fa-calendar label: 'app.events' overlay_title: 'app.events' + + single_selection: + single_location_selection: + default_type: list_overlay + resource_key: locations + types: + list_overlay: + adapter: table + list_key: locations + display_properties: + - name + icon: fa-home + empty_text: 'app.location.no_selections' + overlay_title: 'app.locations' diff --git a/src/Controller/Admin/EventController.php b/src/Controller/Admin/EventController.php index d9a428f..4c9274b 100644 --- a/src/Controller/Admin/EventController.php +++ b/src/Controller/Admin/EventController.php @@ -7,6 +7,7 @@ use App\Common\DoctrineListRepresentationFactory; use App\Entity\Event; use App\Repository\EventRepository; +use App\Repository\LocationRepository; use FOS\RestBundle\Controller\Annotations as Rest; use FOS\RestBundle\Controller\Annotations\RouteResource; use FOS\RestBundle\Routing\ClassResourceInterface; @@ -23,6 +24,11 @@ */ class EventController extends AbstractRestController implements ClassResourceInterface { + /** + * @var DoctrineListRepresentationFactory + */ + private $doctrineListRepresentationFactory; + /** * @var EventRepository */ @@ -34,20 +40,22 @@ class EventController extends AbstractRestController implements ClassResourceInt private $mediaRepository; /** - * @var DoctrineListRepresentationFactory + * @var LocationRepository */ - private $doctrineListRepresentationFactory; + private $locationRepository; public function __construct( + DoctrineListRepresentationFactory $doctrineListRepresentationFactory, EventRepository $repository, MediaRepositoryInterface $mediaRepository, - DoctrineListRepresentationFactory $doctrineListRepresentationFactory, + LocationRepository $locationRepository, ViewHandlerInterface $viewHandler, ?TokenStorageInterface $tokenStorage = null ) { + $this->doctrineListRepresentationFactory = $doctrineListRepresentationFactory; $this->repository = $repository; $this->mediaRepository = $mediaRepository; - $this->doctrineListRepresentationFactory = $doctrineListRepresentationFactory; + $this->locationRepository = $locationRepository; parent::__construct($viewHandler, $tokenStorage); } @@ -159,8 +167,10 @@ protected function mapDataToEntity(array $data, Event $entity): void $entity->setEndDate(new \DateTimeImmutable($endDate)); } - if ($location = $data['location'] ?? null) { - $entity->setLocation($location); + if ($locationId = $data['locationId'] ?? null) { + $entity->setLocation( + $this->locationRepository->findById((int) $locationId) + ); } } diff --git a/src/DataFixtures/ORM/AppFixtures.php b/src/DataFixtures/ORM/AppFixtures.php index 727b5c4..c156957 100644 --- a/src/DataFixtures/ORM/AppFixtures.php +++ b/src/DataFixtures/ORM/AppFixtures.php @@ -5,6 +5,7 @@ namespace App\DataFixtures\ORM; use App\Entity\Event; +use App\Entity\Location; use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; @@ -56,7 +57,8 @@ public function load(ObjectManager $manager): void */ private function loadEvents(ObjectManager $manager, array $images): void { - $repository = $manager->getRepository(Event::class); + $eventRepository = $manager->getRepository(Event::class); + $locationRepository = $manager->getRepository(Location::class); $data = [ [ @@ -132,18 +134,30 @@ private function loadEvents(ObjectManager $manager, array $images): void ]; foreach ($data as $item) { - $event = $repository->create(self::LOCALE); + $location = null; + if ($item['location']) { + $location = $locationRepository->create(); + $location->setName($item['location']); + $location->setStreet(''); + $location->setNumber(''); + $location->setCity(''); + $location->setCountryCode(''); + $location->setPostalCode(''); + $locationRepository->save($location); + } + + $event = $eventRepository->create(self::LOCALE); $event->setTitle($item['title']); $event->setImage($images[$item['image']] ?? null); - $event->setLocation($item['location']); + $event->setLocation($location); $event->setTeaser($item['teaser']); $event->setDescription('

' . $item['description'] . '

'); $event->setStartDate(new \DateTimeImmutable($item['startDate'])); $event->setEndDate(new \DateTimeImmutable($item['endDate'])); $event->setEnabled($item['enabled']); - $repository->save($event); + $eventRepository->save($event); } } diff --git a/src/Entity/Event.php b/src/Entity/Event.php index 060dc54..9ccd12e 100644 --- a/src/Entity/Event.php +++ b/src/Entity/Event.php @@ -48,9 +48,10 @@ class Event private $endDate; /** - * @var string|null + * @var Location|null * - * @ORM\Column(type="string", nullable=true) + * @ORM\ManyToOne(targetEntity="App\Entity\Location") + * @ORM\JoinColumn(onDelete="SET NULL") */ private $location; @@ -124,18 +125,30 @@ public function setEndDate(?\DateTimeImmutable $endDate): self return $this; } - public function getLocation(): ?string + public function getLocation(): ?Location { return $this->location; } - public function setLocation(?string $location): self + public function setLocation(?Location $location): self { $this->location = $location; return $this; } + /** + * @Serializer\VirtualProperty + */ + public function getLocationId(): ?int + { + if (!$this->location) { + return null; + } + + return $this->location->getId(); + } + public function getImage(): ?MediaInterface { return $this->image; diff --git a/tests/Functional/Controller/Admin/EventControllerTest.php b/tests/Functional/Controller/Admin/EventControllerTest.php index 4618321..5d68acc 100644 --- a/tests/Functional/Controller/Admin/EventControllerTest.php +++ b/tests/Functional/Controller/Admin/EventControllerTest.php @@ -5,6 +5,7 @@ namespace App\Tests\Functional\Controller\Admin; use App\Tests\Functional\Traits\EventTrait; +use App\Tests\Functional\Traits\LocationTrait; use Sulu\Bundle\TestBundle\Testing\SuluTestCase; use Symfony\Bundle\FrameworkBundle\KernelBrowser; use Symfony\Component\HttpFoundation\Response; @@ -12,6 +13,7 @@ class EventControllerTest extends SuluTestCase { use EventTrait; + use LocationTrait; /** * @var KernelBrowser @@ -64,6 +66,8 @@ public function testGet(): void public function testPost(): void { + $location = $this->createLocation('Sulu HQ'); + $this->client->request( 'POST', '/admin/api/events?locale=de', @@ -73,7 +77,7 @@ public function testPost(): void 'startDate' => '2019-01-01 12:00', 'endDate' => '2019-01-02 12:00', 'description' => 'Sulu is really awesome', - 'location' => 'Dornbirn', + 'locationId' => $location->getId(), ] ); @@ -90,7 +94,7 @@ public function testPost(): void $this->assertSame('2019-01-01T12:00:00', $result['startDate']); $this->assertSame('2019-01-02T12:00:00', $result['endDate']); $this->assertSame('Sulu is really awesome', $result['description']); - $this->assertSame('Dornbirn', $result['location']); + $this->assertSame($location->getId(), $result['locationId']); $result = $this->findEventById($result['id'], 'de'); @@ -103,7 +107,7 @@ public function testPost(): void $this->assertNotNull($result->getEndDate()); $this->assertSame('2019-01-02T12:00:00', $result->getEndDate()->format('Y-m-d\TH:i:s')); $this->assertSame('Sulu is really awesome', $result->getDescription()); - $this->assertSame('Dornbirn', $result->getLocation()); + $this->assertSame($location->getId(), $result->getLocationId()); } public function testPostNullValues(): void @@ -146,6 +150,7 @@ public function testPostNullValues(): void public function testPut(): void { $event = $this->createEvent('Symfony', 'de'); + $location = $this->createLocation('Sulu HQ'); $this->client->request( 'PUT', @@ -156,7 +161,7 @@ public function testPut(): void 'startDate' => '2019-01-01 12:00', 'endDate' => '2019-01-02 12:00', 'description' => 'Symfony Live is really awesome', - 'location' => 'Dornbirn', + 'locationId' => $location->getId(), ] ); @@ -173,7 +178,7 @@ public function testPut(): void $this->assertSame('2019-01-01T12:00:00', $result['startDate']); $this->assertSame('2019-01-02T12:00:00', $result['endDate']); $this->assertSame('Symfony Live is really awesome', $result['description']); - $this->assertSame('Dornbirn', $result['location']); + $this->assertSame($location->getId(), $result['locationId']); $result = $this->findEventById($result['id'], 'de'); @@ -186,7 +191,7 @@ public function testPut(): void $this->assertNotNull($result->getEndDate()); $this->assertSame('2019-01-02T12:00:00', $result->getEndDate()->format('Y-m-d\TH:i:s')); $this->assertSame('Symfony Live is really awesome', $result->getDescription()); - $this->assertSame('Dornbirn', $result->getLocation()); + $this->assertSame($location->getId(), $result->getLocationId()); } public function testPutNullValues(): void diff --git a/tests/Unit/Entity/EventTest.php b/tests/Unit/Entity/EventTest.php index a88d8ae..2108679 100644 --- a/tests/Unit/Entity/EventTest.php +++ b/tests/Unit/Entity/EventTest.php @@ -6,11 +6,18 @@ use App\Entity\Event; use App\Entity\EventTranslation; +use App\Entity\Location; use PHPUnit\Framework\TestCase; +use Prophecy\Prophecy\ObjectProphecy; use Sulu\Bundle\MediaBundle\Entity\MediaInterface; class EventTest extends TestCase { + /** + * @var Location|ObjectProphecy + */ + private $location; + /** * @var Event */ @@ -18,6 +25,8 @@ class EventTest extends TestCase protected function setUp(): void { + $this->location = $this->prophesize(Location::class); + $this->event = new Event(); $this->event->setLocale('de'); } @@ -51,9 +60,14 @@ public function testEndDate(): void public function testLocation(): void { + $this->location->getId()->willReturn(42); + $this->assertNull($this->event->getLocation()); - $this->assertSame($this->event, $this->event->setLocation('Amsterdam')); - $this->assertSame('Amsterdam', $this->event->getLocation()); + $this->assertNull($this->event->getLocationId()); + $this->assertSame($this->event, $this->event->setLocation($this->location->reveal())); + $this->assertNotNull($this->event->getLocation()); + $this->assertSame($this->location->reveal(), $this->event->getLocation()); + $this->assertSame(42, $this->event->getLocationId()); } public function testImage(): void diff --git a/translations/admin.de.json b/translations/admin.de.json index ac72ae7..071d38b 100644 --- a/translations/admin.de.json +++ b/translations/admin.de.json @@ -8,5 +8,6 @@ "app.enable_event": "Veranstaltungen aktivieren", "app.enabled": "Aktiviert", "app.location": "Standort", - "app.locations": "Standorte" + "app.locations": "Standorte", + "app.location.no_selections": "Kein Standord ausgewählt" } diff --git a/translations/admin.en.json b/translations/admin.en.json index b073ae1..52a386b 100644 --- a/translations/admin.en.json +++ b/translations/admin.en.json @@ -8,5 +8,6 @@ "app.enable_event": "Enable event", "app.enabled": "Enabled", "app.location": "Location", - "app.locations": "Locations" + "app.locations": "Locations", + "app.location.no_selections": "No location selected" }