From bbf75b4da417acf5b14e41981868be2d72e1cfed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20R=C3=B6=C3=9Fner?= Date: Mon, 9 Mar 2020 22:24:42 +0100 Subject: [PATCH 1/9] rearrange fixtures. --- docker-compose.yaml | 8 ++- src/DataFixtures/AppointmentFixtures.php | 6 ++- src/DataFixtures/AttributeFixtures.php | 34 +++++++++++++ src/DataFixtures/SpeakerFixture.php | 64 ++++++++++++++++++++++++ src/DataFixtures/TalkFixtures.php | 45 ++++++++--------- src/DataFixtures/UserFixture.php | 2 +- 6 files changed, 132 insertions(+), 27 deletions(-) create mode 100644 src/DataFixtures/AttributeFixtures.php create mode 100644 src/DataFixtures/SpeakerFixture.php diff --git a/docker-compose.yaml b/docker-compose.yaml index 35dfa4e..4537299 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -9,9 +9,15 @@ services: MYSQL_ROOT_PASSWORD: password ports: - 3306:3306 + volumes: + - dbdata:/var/lib/mysql mailhog: image: mailhog/mailhog ports: - 1025:1025 - - 8025:8025 \ No newline at end of file + - 8025:8025 + +volumes: + dbdata: + driver: local diff --git a/src/DataFixtures/AppointmentFixtures.php b/src/DataFixtures/AppointmentFixtures.php index c238c2f..9fb58e8 100644 --- a/src/DataFixtures/AppointmentFixtures.php +++ b/src/DataFixtures/AppointmentFixtures.php @@ -10,8 +10,10 @@ use Doctrine\Common\DataFixtures\DependentFixtureInterface; use Doctrine\Common\Persistence\ObjectManager; -class AppointmentFixtures extends Fixture implements DependentFixtureInterface +final class AppointmentFixtures extends Fixture implements DependentFixtureInterface { + public const PHPUGHB_3 = 'appointment:phpughb3'; + public function load(ObjectManager $manager): void { /** @var \App\Entity\Talk $talk */ @@ -28,7 +30,7 @@ public function load(ObjectManager $manager): void $manager->flush(); - $this->addReference('appointment:phpughb3', $appointment); + $this->addReference(self::PHPUGHB_3, $appointment); } /** diff --git a/src/DataFixtures/AttributeFixtures.php b/src/DataFixtures/AttributeFixtures.php new file mode 100644 index 0000000..0becf36 --- /dev/null +++ b/src/DataFixtures/AttributeFixtures.php @@ -0,0 +1,34 @@ +persist($twitterType); + $manager->persist($youtubeType); + $manager->flush(); + + $this->addReference(self::TYPE_TWITTER, $twitterType); + $this->addReference(self::TYPE_YOUTUBE, $youtubeType); + } +} diff --git a/src/DataFixtures/SpeakerFixture.php b/src/DataFixtures/SpeakerFixture.php new file mode 100644 index 0000000..c7785f9 --- /dev/null +++ b/src/DataFixtures/SpeakerFixture.php @@ -0,0 +1,64 @@ +getReference(AttributeFixtures::TYPE_TWITTER); + + $ole = new Speaker('Ole', 'Rößner'); + $oleTwitter = new Attribute($twitterType, 'djbasster'); + + $ole->addAttribute($oleTwitter); + $ole->linkUser($this->getReference(UserFixture::USER_OLE)); + + $denis = new Speaker('Denis', 'Brumann'); + $denisTwitter = new Attribute($twitterType, 'dbrumann'); + + $stephan = new Speaker('Stephan', 'Hochdörfer'); + $stephanTwitter = new Attribute($twitterType, 'shochdoerfer'); + + $manager->persist($ole); + $manager->persist($oleTwitter); + $manager->persist($denis); + $manager->persist($denisTwitter); + $manager->persist($stephan); + $manager->persist($stephanTwitter); + $manager->flush(); + + $this->setReference(self::OLE, $ole); + $this->setReference(self::DENIS, $denis); + $this->setReference(self::STEPHAN, $stephan); + } + + /** + * {@inheritdoc} + */ + public function getDependencies(): array + { + return [ + AttributeFixtures::class, + UserFixture::class, + ]; + } +} diff --git a/src/DataFixtures/TalkFixtures.php b/src/DataFixtures/TalkFixtures.php index bb960f2..ff5081e 100644 --- a/src/DataFixtures/TalkFixtures.php +++ b/src/DataFixtures/TalkFixtures.php @@ -5,41 +5,40 @@ namespace App\DataFixtures; use App\Entity\Attribute; -use App\Entity\AttributeType; -use App\Entity\Speaker; use App\Entity\Talk; use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Common\DataFixtures\DependentFixtureInterface; use Doctrine\Common\Persistence\ObjectManager; -class TalkFixtures extends Fixture implements DependentFixtureInterface +final class TalkFixtures extends Fixture implements DependentFixtureInterface { - public const SPEAKER_OLE = 'speaker:Ole'; public const TALK_SOLID = 'talk:SOLIDe Symfony Apps'; + public const TALK_IMPORTS = 'talk:Imports like a pro'; + public const TALK_DISCO = 'talk:Disco - A fresh look at DI'; public function load(ObjectManager $manager): void { - /** @var \App\Entity\User $oleUser */ - $oleUser = $this->getReference(UserFixture::USER_OLE); - - $twitterType = new AttributeType('twitter', 'twitter'); - $twitterAttr = new Attribute($twitterType, 'djbasster'); - - $speaker = new Speaker('Ole', 'Rößner'); - $speaker->addAttribute($twitterAttr); - $speaker->linkUser($oleUser); - - $talk = new Talk('SOLIDe Symfony Apps', $speaker); - - $manager->persist($twitterType); - $manager->persist($twitterAttr); - $manager->persist($speaker); - $manager->persist($talk); + $solid = new Talk('SOLIDe Symfony Apps', $this->getReference(SpeakerFixture::OLE)); + $imports = new Talk('Imports like a pro', $this->getReference(SpeakerFixture::DENIS)); + $disco = new Talk('Disco - A fresh look at DI', $this->getReference(SpeakerFixture::STEPHAN)); + + $importsVideo = new Attribute( + $this->getReference(AttributeFixtures::TYPE_YOUTUBE), + 'Ansehen', + 'https://youtu.be/tgb5kybJISM' + ); + $imports->addAttribute($importsVideo); + + $manager->persist($solid); + $manager->persist($imports); + $manager->persist($importsVideo); + $manager->persist($disco); $manager->flush(); - $this->addReference(self::SPEAKER_OLE, $speaker); - $this->addReference(self::TALK_SOLID, $talk); + $this->addReference(self::TALK_SOLID, $solid); + $this->addReference(self::TALK_IMPORTS, $imports); + $this->addReference(self::TALK_DISCO, $disco); } /** @@ -47,6 +46,6 @@ public function load(ObjectManager $manager): void */ public function getDependencies(): array { - return [UserFixture::class]; + return [SpeakerFixture::class]; } } diff --git a/src/DataFixtures/UserFixture.php b/src/DataFixtures/UserFixture.php index e4f9076..c566784 100644 --- a/src/DataFixtures/UserFixture.php +++ b/src/DataFixtures/UserFixture.php @@ -8,7 +8,7 @@ use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Common\Persistence\ObjectManager; -class UserFixture extends Fixture +final class UserFixture extends Fixture { public const USER_OLE = 'user:Ole'; From d16ab9ea857afcf720faf862ef77713065d31724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20R=C3=B6=C3=9Fner?= Date: Mon, 9 Mar 2020 22:59:57 +0100 Subject: [PATCH 2/9] introduce Location Entity and re-build static homepage data with fixtures. --- src/DataFixtures/AppointmentFixtures.php | 17 ++- src/DataFixtures/AttributeFixtures.php | 8 ++ src/DataFixtures/LocationFixtures.php | 47 +++++++ src/DataFixtures/TalkFixtures.php | 2 +- src/DataFixtures/UserFixture.php | 2 +- src/Entity/Appointment.php | 47 ++++++- src/Entity/AttributeType.php | 4 +- src/Entity/Location.php | 166 +++++++++++++++++++++++ 8 files changed, 284 insertions(+), 9 deletions(-) create mode 100644 src/DataFixtures/LocationFixtures.php create mode 100644 src/Entity/Location.php diff --git a/src/DataFixtures/AppointmentFixtures.php b/src/DataFixtures/AppointmentFixtures.php index 9fb58e8..92a52c0 100644 --- a/src/DataFixtures/AppointmentFixtures.php +++ b/src/DataFixtures/AppointmentFixtures.php @@ -5,10 +5,11 @@ namespace App\DataFixtures; use App\Entity\Appointment; +use App\Entity\Attribute; use DateTimeImmutable; use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Common\DataFixtures\DependentFixtureInterface; -use Doctrine\Common\Persistence\ObjectManager; +use Doctrine\Persistence\ObjectManager; final class AppointmentFixtures extends Fixture implements DependentFixtureInterface { @@ -18,6 +19,11 @@ public function load(ObjectManager $manager): void { /** @var \App\Entity\Talk $talk */ $talk = $this->getReference(TalkFixtures::TALK_SOLID); + /** @var \App\Entity\Location $teamNeusta */ + $teamNeusta = $this->getReference(LocationFixtures::TEAM_NEUSTA); + $ticketsType = $this->getReference(AttributeFixtures::TYPE_TICKETS); + + $ticketsAttr = new Attribute($ticketsType, 'Anmelden', 'https://www.eventbrite.de/e/php-usergroup-bremen-phpughb-iii-tickets-93670576215'); $appointment = new Appointment( '#PHPUGHB III', @@ -25,8 +31,11 @@ public function load(ObjectManager $manager): void DateTimeImmutable::createFromFormat('Y-m-d H:i', '2020-03-11 18:30') ); $appointment->addTalk($talk); + $appointment->setLocation($teamNeusta); + $appointment->addAttribute($ticketsAttr); $manager->persist($appointment); + $manager->persist($ticketsAttr); $manager->flush(); @@ -38,6 +47,10 @@ public function load(ObjectManager $manager): void */ public function getDependencies(): array { - return [TalkFixtures::class]; + return [ + TalkFixtures::class, + LocationFixtures::class, + AttributeFixtures::class, + ]; } } diff --git a/src/DataFixtures/AttributeFixtures.php b/src/DataFixtures/AttributeFixtures.php index 0becf36..a513a32 100644 --- a/src/DataFixtures/AttributeFixtures.php +++ b/src/DataFixtures/AttributeFixtures.php @@ -15,6 +15,8 @@ final class AttributeFixtures extends Fixture { public const TYPE_TWITTER = 'attribute_type:twitter'; public const TYPE_YOUTUBE = 'attribute_type:youtube'; + public const TYPE_LATLNG = 'attribute_type:latlng'; + public const TYPE_TICKETS = 'attribute_type:tickets'; /** * {@inheritdoc} @@ -23,12 +25,18 @@ public function load(ObjectManager $manager): void { $twitterType = new AttributeType('twitter', 'twitter'); $youtubeType = new AttributeType('youtube', 'youtube'); + $latLngType = new AttributeType('map-marker-alt', 'latlng'); + $ticketsType = new AttributeType('ticket-alt', 'ticket'); $manager->persist($twitterType); $manager->persist($youtubeType); + $manager->persist($latLngType); + $manager->persist($ticketsType); $manager->flush(); $this->addReference(self::TYPE_TWITTER, $twitterType); $this->addReference(self::TYPE_YOUTUBE, $youtubeType); + $this->addReference(self::TYPE_LATLNG, $latLngType); + $this->addReference(self::TYPE_TICKETS, $ticketsType); } } diff --git a/src/DataFixtures/LocationFixtures.php b/src/DataFixtures/LocationFixtures.php new file mode 100644 index 0000000..f83ef77 --- /dev/null +++ b/src/DataFixtures/LocationFixtures.php @@ -0,0 +1,47 @@ +getReference(AttributeFixtures::TYPE_LATLNG); + + $teamNeusta = new Location('team neusta', 'Konsul-Smidt-Str.', '24', '28217', 'Bremen'); + $tnLatLng = new Attribute($latLngType, '8.7742443,53.090925'); + $teamNeusta->addAttribute($tnLatLng); + + $manager->persist($teamNeusta); + $manager->persist($tnLatLng); + $manager->flush(); + + $this->setReference(self::TEAM_NEUSTA, $teamNeusta); + } + + /** + * {@inheritdoc} + */ + public function getDependencies(): array + { + return [ + AttributeFixtures::class, + ]; + } +} diff --git a/src/DataFixtures/TalkFixtures.php b/src/DataFixtures/TalkFixtures.php index ff5081e..c9eeed5 100644 --- a/src/DataFixtures/TalkFixtures.php +++ b/src/DataFixtures/TalkFixtures.php @@ -8,7 +8,7 @@ use App\Entity\Talk; use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Common\DataFixtures\DependentFixtureInterface; -use Doctrine\Common\Persistence\ObjectManager; +use Doctrine\Persistence\ObjectManager; final class TalkFixtures extends Fixture implements DependentFixtureInterface { diff --git a/src/DataFixtures/UserFixture.php b/src/DataFixtures/UserFixture.php index c566784..3ffb0ac 100644 --- a/src/DataFixtures/UserFixture.php +++ b/src/DataFixtures/UserFixture.php @@ -6,7 +6,7 @@ use App\Entity\User; use Doctrine\Bundle\FixturesBundle\Fixture; -use Doctrine\Common\Persistence\ObjectManager; +use Doctrine\Persistence\ObjectManager; final class UserFixture extends Fixture { diff --git a/src/Entity/Appointment.php b/src/Entity/Appointment.php index d5a69c1..d5b2082 100644 --- a/src/Entity/Appointment.php +++ b/src/Entity/Appointment.php @@ -34,9 +34,7 @@ class Appointment private string $title; /** - * @ORM\Column(type="string", length=2000, nullable=true) - * - * @Assert\Length(max="2000") + * @ORM\Column(type="text", nullable=true) */ private ?string $text; @@ -50,12 +48,23 @@ class Appointment */ private Collection $talks; + /** + * @ORM\ManyToOne(targetEntity="App\Entity\Location", inversedBy="appointments") + */ + private ?Location $location = null; + + /** + * @ORM\ManyToMany(targetEntity="App\Entity\Attribute") + */ + private Collection $attributes; + public function __construct(string $title, ?string $text = null, ?DateTimeInterface $dateTime = null) { $this->title = $title; $this->text = $text; $this->dateTime = $dateTime; $this->talks = new ArrayCollection(); + $this->attributes = new ArrayCollection(); } public function getTitle(): string @@ -73,4 +82,36 @@ public function addTalk(Talk $talk): void $this->talks->add($talk); $talk->setAppointment($this); } + + public function getLocation(): ?Location + { + return $this->location; + } + + public function setLocation(?Location $location): void + { + $this->location = $location; + } + + /** + * @return Collection|Attribute[] + */ + public function getAttributes(): Collection + { + return $this->attributes; + } + + public function addAttribute(Attribute $attribute): void + { + if (!$this->attributes->contains($attribute)) { + $this->attributes[] = $attribute; + } + } + + public function removeAttribute(Attribute $attribute): void + { + if ($this->attributes->contains($attribute)) { + $this->attributes->removeElement($attribute); + } + } } diff --git a/src/Entity/AttributeType.php b/src/Entity/AttributeType.php index feacb9d..0a03d37 100644 --- a/src/Entity/AttributeType.php +++ b/src/Entity/AttributeType.php @@ -20,10 +20,10 @@ class AttributeType private ?int $id = null; /** - * @ORM\Column(type="string", length=10) + * @ORM\Column(type="string", length=50) * * @Assert\NotBlank - * @Assert\Length(max="10") + * @Assert\Length(max="50") */ private string $faIcon; diff --git a/src/Entity/Location.php b/src/Entity/Location.php new file mode 100644 index 0000000..5fd2ccb --- /dev/null +++ b/src/Entity/Location.php @@ -0,0 +1,166 @@ +name = $name; + $this->street = $street; + $this->streetNumber = $streetNumber; + $this->zipCode = $zipCode; + $this->city = $city; + $this->appointments = new ArrayCollection(); + $this->attributes = new ArrayCollection(); + } + + public function getId(): ?int + { + return $this->id; + } + + public function getName(): ?string + { + return $this->name; + } + + public function setName(string $name): void + { + $this->name = $name; + } + + public function getStreet(): ?string + { + return $this->street; + } + + public function setStreet(string $street): void + { + $this->street = $street; + } + + public function getStreetNumber(): ?string + { + return $this->streetNumber; + } + + public function setStreetNumber(?string $streetNumber): void + { + $this->streetNumber = $streetNumber; + } + + public function getZipCode(): ?string + { + return $this->zipCode; + } + + public function setZipCode(string $zipCode): void + { + $this->zipCode = $zipCode; + } + + public function getCity(): ?string + { + return $this->city; + } + + public function setCity(string $city): void + { + $this->city = $city; + } + + /** + * @return Collection|Appointment[] + */ + public function getAppointments(): Collection + { + return $this->appointments; + } + + /** + * @return Collection|Attribute[] + */ + public function getAttributes(): Collection + { + return $this->attributes; + } + + public function addAttribute(Attribute $attribute): void + { + if (!$this->attributes->contains($attribute)) { + $this->attributes[] = $attribute; + } + } + + public function removeAttribute(Attribute $attribute): void + { + if ($this->attributes->contains($attribute)) { + $this->attributes->removeElement($attribute); + } + } +} From 6de1cd9335602338e3dc39070f3da05f09f2d1ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20R=C3=B6=C3=9Fner?= Date: Mon, 9 Mar 2020 23:43:33 +0100 Subject: [PATCH 3/9] okay... homepage is kinda dynamic... --- src/Action/HomeAction.php | 7 +- src/DataFixtures/AttributeFixtures.php | 2 +- .../MissingAttributeTypeException.php | 19 +++++ src/Entity/Appointment.php | 31 ++------ src/Entity/Attribute.php | 10 +++ src/Entity/AttributeAware.php | 26 +++++++ src/Entity/AttributeTrait.php | 71 +++++++++++++++++++ src/Entity/AttributeType.php | 10 +++ src/Entity/Location.php | 33 ++------- src/Entity/Speaker.php | 33 ++------- src/Entity/Talk.php | 34 ++------- src/Repository/AppointmentRepository.php | 25 +++++++ templates/home.html.twig | 65 ++++++++++------- tests/Unit/Entity/AttributeAwareTest.php | 55 ++++++++++++++ 14 files changed, 282 insertions(+), 139 deletions(-) create mode 100644 src/Domain/Attribute/Exception/MissingAttributeTypeException.php create mode 100644 src/Entity/AttributeAware.php create mode 100644 src/Entity/AttributeTrait.php create mode 100644 src/Repository/AppointmentRepository.php create mode 100644 tests/Unit/Entity/AttributeAwareTest.php diff --git a/src/Action/HomeAction.php b/src/Action/HomeAction.php index 9181d15..23ed828 100644 --- a/src/Action/HomeAction.php +++ b/src/Action/HomeAction.php @@ -4,6 +4,7 @@ namespace App\Action; +use App\Repository\AppointmentRepository; use Basster\LazyResponseBundle\Response\TemplateResponse; use Symfony\Component\Routing\Annotation\Route; @@ -12,8 +13,10 @@ final class HomeAction /** * @Route("/", name="app_home") */ - public function __invoke(): TemplateResponse + public function __invoke(AppointmentRepository $appointmentRepository): TemplateResponse { - return new TemplateResponse('home.html.twig'); + return new TemplateResponse('home.html.twig', [ + 'appointments' => $appointmentRepository->findAll(), + ]); } } diff --git a/src/DataFixtures/AttributeFixtures.php b/src/DataFixtures/AttributeFixtures.php index a513a32..4524e1d 100644 --- a/src/DataFixtures/AttributeFixtures.php +++ b/src/DataFixtures/AttributeFixtures.php @@ -26,7 +26,7 @@ public function load(ObjectManager $manager): void $twitterType = new AttributeType('twitter', 'twitter'); $youtubeType = new AttributeType('youtube', 'youtube'); $latLngType = new AttributeType('map-marker-alt', 'latlng'); - $ticketsType = new AttributeType('ticket-alt', 'ticket'); + $ticketsType = new AttributeType('calendar-check', 'tickets'); $manager->persist($twitterType); $manager->persist($youtubeType); diff --git a/src/Domain/Attribute/Exception/MissingAttributeTypeException.php b/src/Domain/Attribute/Exception/MissingAttributeTypeException.php new file mode 100644 index 0000000..f90e53d --- /dev/null +++ b/src/Domain/Attribute/Exception/MissingAttributeTypeException.php @@ -0,0 +1,19 @@ +title = $title; $this->text = $text; $this->dateTime = $dateTime; $this->talks = new ArrayCollection(); - $this->attributes = new ArrayCollection(); + $this->initAttributes(); } public function getTitle(): string @@ -94,24 +91,10 @@ public function setLocation(?Location $location): void } /** - * @return Collection|Attribute[] + * @return \Doctrine\Common\Collections\ArrayCollection|\Doctrine\Common\Collections\Collection */ - public function getAttributes(): Collection - { - return $this->attributes; - } - - public function addAttribute(Attribute $attribute): void - { - if (!$this->attributes->contains($attribute)) { - $this->attributes[] = $attribute; - } - } - - public function removeAttribute(Attribute $attribute): void + public function getTalks() { - if ($this->attributes->contains($attribute)) { - $this->attributes->removeElement($attribute); - } + return $this->talks; } } diff --git a/src/Entity/Attribute.php b/src/Entity/Attribute.php index 3f6803a..fed3412 100644 --- a/src/Entity/Attribute.php +++ b/src/Entity/Attribute.php @@ -52,4 +52,14 @@ public function getType(): AttributeType { return $this->type; } + + public function getValue(): string + { + return $this->value; + } + + public function getUrl(): ?string + { + return $this->url; + } } diff --git a/src/Entity/AttributeAware.php b/src/Entity/AttributeAware.php new file mode 100644 index 0000000..c636079 --- /dev/null +++ b/src/Entity/AttributeAware.php @@ -0,0 +1,26 @@ +attributes; + } + + public function addAttribute(Attribute $attribute): void + { + if (!$this->attributes->contains($attribute)) { + $this->attributes[] = $attribute; + } + } + + public function removeAttribute(Attribute $attribute): void + { + if ($this->attributes->contains($attribute)) { + $this->attributes->removeElement($attribute); + } + } + + /** {@inheritdoc} */ + public function getAttribute(string $type): Attribute + { + foreach ($this->attributes as $attribute) { + if (strcasecmp($attribute->getType()->getTitle(), $type) === 0) { + return $attribute; + } + } + + throw new MissingAttributeTypeException($type); + } + + public function hasAttribute(string $type): bool + { + try { + $this->getAttribute($type); + + return true; + } catch (MissingAttributeTypeException $ex) { + return false; + } + } + + private function initAttributes(): void + { + $this->attributes = new ArrayCollection(); + } +} diff --git a/src/Entity/AttributeType.php b/src/Entity/AttributeType.php index 0a03d37..79ab2ba 100644 --- a/src/Entity/AttributeType.php +++ b/src/Entity/AttributeType.php @@ -40,4 +40,14 @@ public function __construct(string $faIcon, string $title) $this->faIcon = $faIcon; $this->title = $title; } + + public function getTitle(): string + { + return $this->title; + } + + public function getFaIcon(): string + { + return $this->faIcon; + } } diff --git a/src/Entity/Location.php b/src/Entity/Location.php index 5fd2ccb..dd2ccbe 100644 --- a/src/Entity/Location.php +++ b/src/Entity/Location.php @@ -10,8 +10,10 @@ /** * @ORM\Entity() */ -class Location +class Location implements AttributeAware { + use AttributeTrait; + /** * @ORM\Id() * @ORM\GeneratedValue() @@ -63,11 +65,6 @@ class Location */ private Collection $appointments; - /** - * @ORM\ManyToMany(targetEntity="App\Entity\Attribute") - */ - private Collection $attributes; - public function __construct(string $name, string $street, string $streetNumber, string $zipCode, string $city) { $this->name = $name; @@ -76,7 +73,7 @@ public function __construct(string $name, string $street, string $streetNumber, $this->zipCode = $zipCode; $this->city = $city; $this->appointments = new ArrayCollection(); - $this->attributes = new ArrayCollection(); + $this->initAttributes(); } public function getId(): ?int @@ -141,26 +138,4 @@ public function getAppointments(): Collection { return $this->appointments; } - - /** - * @return Collection|Attribute[] - */ - public function getAttributes(): Collection - { - return $this->attributes; - } - - public function addAttribute(Attribute $attribute): void - { - if (!$this->attributes->contains($attribute)) { - $this->attributes[] = $attribute; - } - } - - public function removeAttribute(Attribute $attribute): void - { - if ($this->attributes->contains($attribute)) { - $this->attributes->removeElement($attribute); - } - } } diff --git a/src/Entity/Speaker.php b/src/Entity/Speaker.php index a968a1a..272e0f0 100644 --- a/src/Entity/Speaker.php +++ b/src/Entity/Speaker.php @@ -12,8 +12,10 @@ /** * @ORM\Entity() */ -class Speaker +class Speaker implements AttributeAware { + use AttributeTrait; + /** * @ORM\Id() * @ORM\GeneratedValue() @@ -41,17 +43,12 @@ class Speaker */ private Collection $talks; - /** - * @ORM\ManyToMany(targetEntity="App\Entity\Attribute") - */ - private Collection $attributes; - public function __construct(string $firstname, string $lastname) { $this->firstname = $firstname; $this->lastname = $lastname; $this->talks = new ArrayCollection(); - $this->attributes = new ArrayCollection(); + $this->initAttributes(); } public function getId(): ?int @@ -97,26 +94,4 @@ public function addTalk(Talk $talk): void $this->talks[] = $talk; } } - - /** - * @return Collection|Attribute[] - */ - public function getAttributes(): Collection - { - return clone $this->attributes; - } - - public function addAttribute(Attribute $attribute): void - { - if (!$this->attributes->contains($attribute)) { - $this->attributes[] = $attribute; - } - } - - public function removeAttribute(Attribute $attribute): void - { - if ($this->attributes->contains($attribute)) { - $this->attributes->removeElement($attribute); - } - } } diff --git a/src/Entity/Talk.php b/src/Entity/Talk.php index 1790b17..00779f8 100644 --- a/src/Entity/Talk.php +++ b/src/Entity/Talk.php @@ -4,8 +4,6 @@ namespace App\Entity; -use Doctrine\Common\Collections\ArrayCollection; -use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Validator\Constraints as Assert; @@ -15,8 +13,10 @@ * * @UniqueEntity(fields={"title"}) */ -class Talk +class Talk implements AttributeAware { + use AttributeTrait; + /** * @ORM\Column(type="integer", unique=true) * @ORM\Id @@ -43,17 +43,12 @@ class Talk */ private Speaker $speaker; - /** - * @ORM\ManyToMany(targetEntity="App\Entity\Attribute") - */ - private Collection $attributes; - public function __construct(string $title, Speaker $speaker) { $this->title = $title; $this->speaker = $speaker; $speaker->addTalk($this); - $this->attributes = new ArrayCollection(); + $this->initAttributes(); } public function getSpeaker(): ?Speaker @@ -66,25 +61,8 @@ public function setAppointment(Appointment $appointment): void $this->appointment = $appointment; } - /** - * @return Collection|Attribute[] - */ - public function getAttributes(): Collection - { - return clone $this->attributes; - } - - public function addAttribute(Attribute $attribute): void - { - if (!$this->attributes->contains($attribute)) { - $this->attributes[] = $attribute; - } - } - - public function removeAttribute(Attribute $attribute): void + public function getTitle(): string { - if ($this->attributes->contains($attribute)) { - $this->attributes->removeElement($attribute); - } + return $this->title; } } diff --git a/src/Repository/AppointmentRepository.php b/src/Repository/AppointmentRepository.php new file mode 100644 index 0000000..a8cb1c0 --- /dev/null +++ b/src/Repository/AppointmentRepository.php @@ -0,0 +1,25 @@ +findBy([], ['dateTime' => 'desc']); + } +} diff --git a/templates/home.html.twig b/templates/home.html.twig index 7bc927d..78bcdf7 100644 --- a/templates/home.html.twig +++ b/templates/home.html.twig @@ -5,30 +5,43 @@ {% endblock %} {% block content %} -
- Card image cap -
-

Am 23.10.2019 | Wesertower @ hmmh

-
-

Sponsoren

- -
-

Talks

-
Imports like a Pro
-
Denis Brumann
- - -
-
Disco - A fresh look at DI
-
Stephan Hochdörfer
- -
Leider kein Mittschnitt vorhanden
-
-

Teilnahme

- Der Eintritt ist Frei! Wenn ihr uns bei der Planung helfen wollt, dann meldet euch bitte hier an: -
- Anmelden + {% for appointment in appointments %} +
+ Card image cap +
+

Am {{ appointment.dateTime | date('d.m.Y') }} + | {{ appointment.location.name }}

+
+

Sponsoren

+ +
+

Talks

+ {% for talk in appointment.talks %} +
{{ talk.title }}
+
{{ talk.speaker.fullname }}
+ {% if talk.speaker.hasAttribute('twitter') %} + {% set twitterHandle = talk.speaker.getAttribute('twitter').value %} + + {% endif %} + {% for talkAttr in talk.attributes %} + + {% endfor %} +
+ {% endfor %} +
+ {% if appointment.hasAttribute('tickets') %} + {% set tickets = appointment.getAttribute('tickets') %} +

Teilnahme

+ Der Eintritt ist Frei! Wenn ihr uns bei der Planung helfen wollt, dann meldet euch bitte hier an: +
+ {{ tickets.value }} + + {% endif %} +
+
-
-
-{% endblock %} \ No newline at end of file + {% endfor %} +{% endblock %} diff --git a/tests/Unit/Entity/AttributeAwareTest.php b/tests/Unit/Entity/AttributeAwareTest.php new file mode 100644 index 0000000..2224ff6 --- /dev/null +++ b/tests/Unit/Entity/AttributeAwareTest.php @@ -0,0 +1,55 @@ +expectException(MissingAttributeTypeException::class); + + $appointment = new Appointment('Test Appointment'); + $appointment->getAttribute('ticket'); + } + + /** + * @test + */ + public function getAttribute(): void + { + $twitterType = new AttributeType('twitter', 'twitter'); + $twitterAttr = new Attribute($twitterType, 'phpughb'); + + $appointment = new Appointment('Test Appointment'); + $appointment->addAttribute($twitterAttr); + + static::assertSame($twitterAttr, $appointment->getAttribute('twitter')); + } + + /** + * @test + */ + public function hasAttribute(): void + { + $appointment = new Appointment('Test Appointment'); + static::assertFalse($appointment->hasAttribute('twitter')); + } +} From 1df30bea661d457e8ec3bbb063f8168726af06e5 Mon Sep 17 00:00:00 2001 From: Lucas Nothnagel Date: Tue, 24 Mar 2020 22:17:47 +0100 Subject: [PATCH 4/9] Updates test to use sqlite and updates github-ci to create the database --- .env.test | 1 + .github/workflows/php.yml | 6 ++ composer.json | 1 + composer.lock | 74 +++++++++++++++++-- config/bundles.php | 1 + .../test/dama_doctrine_test_bundle.yaml | 4 + phpunit.xml.dist | 6 +- symfony.lock | 12 +++ 8 files changed, 96 insertions(+), 9 deletions(-) create mode 100644 config/packages/test/dama_doctrine_test_bundle.yaml diff --git a/.env.test b/.env.test index d048686..2d25a38 100644 --- a/.env.test +++ b/.env.test @@ -3,3 +3,4 @@ KERNEL_CLASS='App\Kernel' APP_SECRET='$ecretf0rt3st' SYMFONY_DEPRECATIONS_HELPER=999999 PANTHER_APP_ENV=panther +DATABASE_URL=sqlite:///%kernel.project_dir%/var/test.db \ No newline at end of file diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index ac234ab..39b6839 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -19,5 +19,11 @@ jobs: - name: Build webpack run: yarn encore prod + - name: Create database + run: bin/console doctrine:database:create --env test + + - name: Create database schema + run: bin/console doctrine:schema:create --env test + - name: Run test suite run: bin/phpunit diff --git a/composer.json b/composer.json index 2ccc090..746c1a2 100644 --- a/composer.json +++ b/composer.json @@ -23,6 +23,7 @@ "symfony/yaml": "5.0.*" }, "require-dev": { + "dama/doctrine-test-bundle": "^6.3", "doctrine/doctrine-fixtures-bundle": "^3.3", "easycorp/easy-log-handler": "^1.0.7", "friendsofphp/php-cs-fixer": "^2.16", diff --git a/composer.lock b/composer.lock index 46bb123..aec48f7 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e8fada79453fd8b0ecc332e62942ddc4", + "content-hash": "9291532147be5655a18a248f4baa363d", "packages": [ { "name": "basster/lazy-response-bundle", @@ -5419,6 +5419,63 @@ ], "time": "2019-11-06T16:40:04+00:00" }, + { + "name": "dama/doctrine-test-bundle", + "version": "v6.3.2", + "source": { + "type": "git", + "url": "https://github.com/dmaicher/doctrine-test-bundle.git", + "reference": "06932e828b4e8ed8655b9b64ae30428e048b616e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dmaicher/doctrine-test-bundle/zipball/06932e828b4e8ed8655b9b64ae30428e048b616e", + "reference": "06932e828b4e8ed8655b9b64ae30428e048b616e", + "shasum": "" + }, + "require": { + "doctrine/dbal": "^2.9,>=2.9.3", + "doctrine/doctrine-bundle": "^1.11 || ^2.0", + "php": "^7.1", + "symfony/framework-bundle": "^3.4 || ^4.3 || ^5.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "symfony/phpunit-bridge": "^4.3 || ^5.0", + "symfony/yaml": "^3.4 || ^4.3 || ^5.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "7.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "DAMA\\DoctrineTestBundle\\": "src/DAMA/DoctrineTestBundle" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "David Maicher", + "email": "mail@dmaicher.de" + } + ], + "description": "Symfony bundle to isolate doctrine database tests and improve test performance", + "keywords": [ + "doctrine", + "isolation", + "performance", + "symfony", + "tests" + ], + "time": "2020-03-02T20:42:23+00:00" + }, { "name": "doctrine/data-fixtures", "version": "1.4.2", @@ -6360,23 +6417,23 @@ }, { "name": "symfony/phpunit-bridge", - "version": "v5.0.4", + "version": "v5.0.5", "source": { "type": "git", "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "38959f0ef4cea3e003f94c670bca89b2f4d932c5" + "reference": "b8fee53045a55ccbb9209e453bf6fdcf74381959" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/38959f0ef4cea3e003f94c670bca89b2f4d932c5", - "reference": "38959f0ef4cea3e003f94c670bca89b2f4d932c5", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/b8fee53045a55ccbb9209e453bf6fdcf74381959", + "reference": "b8fee53045a55ccbb9209e453bf6fdcf74381959", "shasum": "" }, "require": { "php": ">=5.5.9" }, "conflict": { - "phpunit/phpunit": "<5.4.3" + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0|<6.4,>=6.0" }, "suggest": { "symfony/error-handler": "For tracking deprecated interfaces usages at runtime with DebugClassLoader" @@ -6421,7 +6478,7 @@ ], "description": "Symfony PHPUnit Bridge", "homepage": "https://symfony.com", - "time": "2020-01-31T09:56:42+00:00" + "time": "2020-02-24T15:05:31+00:00" }, { "name": "symfony/process", @@ -6579,5 +6636,6 @@ "ext-ctype": "*", "ext-iconv": "*" }, - "platform-dev": [] + "platform-dev": [], + "plugin-api-version": "1.1.0" } diff --git a/config/bundles.php b/config/bundles.php index 2d23c6a..917925f 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -14,4 +14,5 @@ Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true], Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true], Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true], + DAMA\DoctrineTestBundle\DAMADoctrineTestBundle::class => ['test' => true], ]; diff --git a/config/packages/test/dama_doctrine_test_bundle.yaml b/config/packages/test/dama_doctrine_test_bundle.yaml new file mode 100644 index 0000000..80b0091 --- /dev/null +++ b/config/packages/test/dama_doctrine_test_bundle.yaml @@ -0,0 +1,4 @@ +dama_doctrine_test: + enable_static_connection: true + enable_static_meta_data_cache: true + enable_static_query_cache: true diff --git a/phpunit.xml.dist b/phpunit.xml.dist index d6e204f..5dfff55 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -12,7 +12,7 @@ - + @@ -30,6 +30,10 @@ + + + + diff --git a/symfony.lock b/symfony.lock index 8647c23..0aa054e 100644 --- a/symfony.lock +++ b/symfony.lock @@ -17,6 +17,18 @@ "composer/xdebug-handler": { "version": "1.4.0" }, + "dama/doctrine-test-bundle": { + "version": "4.0", + "recipe": { + "repo": "github.com/symfony/recipes-contrib", + "branch": "master", + "version": "4.0", + "ref": "56eaa387b5e48ebcc7c95a893b47dfa1ad51449c" + }, + "files": [ + "config/packages/test/dama_doctrine_test_bundle.yaml" + ] + }, "doctrine/annotations": { "version": "1.0", "recipe": { From 0c8bf8bc58ab659c3c5f5f5d2e300d309df5da0f Mon Sep 17 00:00:00 2001 From: Lucas Nothnagel Date: Tue, 24 Mar 2020 22:27:21 +0100 Subject: [PATCH 5/9] Installs easyadmin bundle --- composer.json | 1 + composer.lock | 311 ++++++++++++++++++++++++++++++- config/bundles.php | 1 + config/packages/easy_admin.yaml | 6 + config/packages/translation.yaml | 6 + config/routes/easy_admin.yaml | 4 + symfony.lock | 32 ++++ translations/.gitignore | 0 8 files changed, 360 insertions(+), 1 deletion(-) create mode 100644 config/packages/easy_admin.yaml create mode 100644 config/packages/translation.yaml create mode 100644 config/routes/easy_admin.yaml create mode 100644 translations/.gitignore diff --git a/composer.json b/composer.json index 746c1a2..fdb44e9 100644 --- a/composer.json +++ b/composer.json @@ -6,6 +6,7 @@ "ext-ctype": "*", "ext-iconv": "*", "basster/lazy-response-bundle": "^1.1", + "easycorp/easyadmin-bundle": "^2.3", "scriptibus/abstract-collection": "^1.0", "sensio/framework-extra-bundle": "^5.5", "symfony/console": "5.0.*", diff --git a/composer.lock b/composer.lock index aec48f7..731867f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "9291532147be5655a18a248f4baa363d", + "content-hash": "1d9e2e9aece4edf5bcf9afb745d279b0", "packages": [ { "name": "basster/lazy-response-bundle", @@ -1202,6 +1202,90 @@ ], "time": "2020-01-08T19:53:19+00:00" }, + { + "name": "easycorp/easyadmin-bundle", + "version": "v2.3.5", + "source": { + "type": "git", + "url": "https://github.com/EasyCorp/EasyAdminBundle.git", + "reference": "0c24092bc2b89ae20c22b1678ecff77bb606e3b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/EasyCorp/EasyAdminBundle/zipball/0c24092bc2b89ae20c22b1678ecff77bb606e3b4", + "reference": "0c24092bc2b89ae20c22b1678ecff77bb606e3b4", + "shasum": "" + }, + "require": { + "doctrine/common": "^2.8", + "doctrine/doctrine-bundle": "^1.8|^2.0", + "doctrine/orm": "^2.6.3", + "doctrine/persistence": "^1.3.4", + "pagerfanta/pagerfanta": "^1.0.1|^2.0", + "php": "^7.1.3", + "symfony/asset": "^4.2|^5.0", + "symfony/cache": "^4.2|^5.0", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^4.2|^5.0", + "symfony/doctrine-bridge": "^4.2|^5.0", + "symfony/event-dispatcher": "^4.2|^5.0", + "symfony/expression-language": "^4.2|^5.0", + "symfony/finder": "^4.2|^5.0", + "symfony/form": "^4.2|^5.0", + "symfony/framework-bundle": "^4.2|^5.0", + "symfony/http-foundation": "^4.2|^5.0", + "symfony/http-kernel": "^4.3.7|^5.0", + "symfony/polyfill-mbstring": "^1.7", + "symfony/property-access": "^4.2|^5.0", + "symfony/security-bundle": "^4.2|^5.0", + "symfony/translation": "^4.2|^5.0", + "symfony/twig-bridge": "^4.2|^5.0", + "symfony/twig-bundle": "^4.2|^5.0", + "symfony/validator": "^4.2|^5.0", + "twig/twig": "^2.11.3|^3.0" + }, + "require-dev": { + "doctrine/data-fixtures": "^1.3", + "doctrine/doctrine-fixtures-bundle": "^3.0", + "psr/log": "~1.0", + "symfony/browser-kit": "^4.2|^5.0", + "symfony/console": "^4.2|^5.0", + "symfony/css-selector": "^4.2|^5.0", + "symfony/dom-crawler": "^4.2|^5.0", + "symfony/phpunit-bridge": "^4.3.5|^5.0", + "symfony/var-dumper": "^4.2|^5.0", + "symfony/yaml": "^4.2|^5.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "EasyCorp\\Bundle\\EasyAdminBundle\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Project Contributors", + "homepage": "https://github.com/EasyCorp/EasyAdminBundle/blob/master/CONTRIBUTORS.md" + } + ], + "description": "Admin generator for Symfony applications", + "homepage": "https://github.com/EasyCorp/EasyAdminBundle", + "keywords": [ + "admin", + "backend", + "generator" + ], + "time": "2020-01-18T15:07:00+00:00" + }, { "name": "egulias/email-validator", "version": "2.1.17", @@ -1688,6 +1772,75 @@ ], "time": "2020-02-08T19:22:03+00:00" }, + { + "name": "pagerfanta/pagerfanta", + "version": "v2.1.3", + "source": { + "type": "git", + "url": "https://github.com/whiteoctober/Pagerfanta.git", + "reference": "a53ff01d521648d9dbca19b93ac6bc75a59b0972" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/whiteoctober/Pagerfanta/zipball/a53ff01d521648d9dbca19b93ac6bc75a59b0972", + "reference": "a53ff01d521648d9dbca19b93ac6bc75a59b0972", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "doctrine/orm": "~2.3", + "doctrine/phpcr-odm": "1.*", + "jackalope/jackalope-doctrine-dbal": "1.*", + "jmikola/geojson": "~1.0", + "mandango/mandango": "~1.0@dev", + "mandango/mondator": "~1.0@dev", + "phpunit/phpunit": "^6.5", + "propel/propel": "~2.0@dev", + "propel/propel1": "~1.6", + "ruflin/elastica": "~1.3", + "solarium/solarium": "~3.1" + }, + "suggest": { + "doctrine/mongodb-odm": "To use the DoctrineODMMongoDBAdapter.", + "doctrine/orm": "To use the DoctrineORMAdapter.", + "doctrine/phpcr-odm": "To use the DoctrineODMPhpcrAdapter. >= 1.1.0", + "mandango/mandango": "To use the MandangoAdapter.", + "propel/propel": "To use the Propel2Adapter", + "propel/propel1": "To use the PropelAdapter", + "solarium/solarium": "To use the SolariumAdapter." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Pagerfanta\\": "src/Pagerfanta/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Pablo Díez", + "email": "pablodip@gmail.com" + } + ], + "description": "Pagination for PHP", + "keywords": [ + "page", + "pagination", + "paginator", + "paging" + ], + "time": "2019-07-17T20:56:16+00:00" + }, { "name": "psr/cache", "version": "1.0.1", @@ -2735,6 +2888,71 @@ ], "time": "2019-11-18T17:27:11+00:00" }, + { + "name": "symfony/expression-language", + "version": "v5.0.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/expression-language.git", + "reference": "67741ad12ac7fcc157c51d335e66c7b6a475f9b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/expression-language/zipball/67741ad12ac7fcc157c51d335e66c7b6a475f9b2", + "reference": "67741ad12ac7fcc157c51d335e66c7b6a475f9b2", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "symfony/cache": "^4.4|^5.0", + "symfony/service-contracts": "^1.1|^2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\ExpressionLanguage\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony ExpressionLanguage Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-02-24T15:05:31+00:00" + }, { "name": "symfony/filesystem", "version": "v5.0.4", @@ -4543,6 +4761,97 @@ "homepage": "https://symfony.com", "time": "2020-01-04T14:08:26+00:00" }, + { + "name": "symfony/translation", + "version": "v5.0.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "e9b93f42a1fd6aec6a0872d59ee5c8219a7d584b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/e9b93f42a1fd6aec6a0872d59ee5c8219a7d584b", + "reference": "e9b93f42a1fd6aec6a0872d59ee5c8219a7d584b", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation-contracts": "^2" + }, + "conflict": { + "symfony/config": "<4.4", + "symfony/dependency-injection": "<5.0", + "symfony/http-kernel": "<5.0", + "symfony/twig-bundle": "<5.0", + "symfony/yaml": "<4.4" + }, + "provide": { + "symfony/translation-implementation": "2.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^4.4|^5.0", + "symfony/console": "^4.4|^5.0", + "symfony/dependency-injection": "^5.0", + "symfony/finder": "^4.4|^5.0", + "symfony/http-kernel": "^5.0", + "symfony/intl": "^4.4|^5.0", + "symfony/service-contracts": "^1.1.2|^2", + "symfony/yaml": "^4.4|^5.0" + }, + "suggest": { + "psr/log-implementation": "To use logging capability in translator", + "symfony/config": "", + "symfony/yaml": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Translation Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-02-04T07:41:34+00:00" + }, { "name": "symfony/translation-contracts", "version": "v2.0.1", diff --git a/config/bundles.php b/config/bundles.php index 917925f..166acb1 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -15,4 +15,5 @@ Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true], Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true], DAMA\DoctrineTestBundle\DAMADoctrineTestBundle::class => ['test' => true], + EasyCorp\Bundle\EasyAdminBundle\EasyAdminBundle::class => ['all' => true], ]; diff --git a/config/packages/easy_admin.yaml b/config/packages/easy_admin.yaml new file mode 100644 index 0000000..8ad6ecc --- /dev/null +++ b/config/packages/easy_admin.yaml @@ -0,0 +1,6 @@ +#easy_admin: +# entities: +# # List the entity class name you want to manage +# - App\Entity\Product +# - App\Entity\Category +# - App\Entity\User diff --git a/config/packages/translation.yaml b/config/packages/translation.yaml new file mode 100644 index 0000000..05a2b3d --- /dev/null +++ b/config/packages/translation.yaml @@ -0,0 +1,6 @@ +framework: + default_locale: en + translator: + default_path: '%kernel.project_dir%/translations' + fallbacks: + - en diff --git a/config/routes/easy_admin.yaml b/config/routes/easy_admin.yaml new file mode 100644 index 0000000..c62135c --- /dev/null +++ b/config/routes/easy_admin.yaml @@ -0,0 +1,4 @@ +easy_admin_bundle: + resource: '@EasyAdminBundle/Controller/EasyAdminController.php' + prefix: /admin + type: annotation diff --git a/symfony.lock b/symfony.lock index 0aa054e..6ee49fb 100644 --- a/symfony.lock +++ b/symfony.lock @@ -132,6 +132,19 @@ "config/packages/dev/easy_log_handler.yaml" ] }, + "easycorp/easyadmin-bundle": { + "version": "2.0", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "master", + "version": "2.0", + "ref": "0a51040a43c6f2172a3a0135cd15daf2043905d7" + }, + "files": [ + "config/packages/easy_admin.yaml", + "config/routes/easy_admin.yaml" + ] + }, "egulias/email-validator": { "version": "2.1.17" }, @@ -171,6 +184,9 @@ "ocramius/proxy-manager": { "version": "2.7.0" }, + "pagerfanta/pagerfanta": { + "version": "v2.1.3" + }, "php": { "version": "7.4" }, @@ -274,6 +290,9 @@ "symfony/event-dispatcher-contracts": { "version": "v2.0.1" }, + "symfony/expression-language": { + "version": "v5.0.5" + }, "symfony/filesystem": { "version": "v5.0.4" }, @@ -458,6 +477,19 @@ "symfony/test-pack": { "version": "v1.0.6" }, + "symfony/translation": { + "version": "3.3", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "master", + "version": "3.3", + "ref": "2ad9d2545bce8ca1a863e50e92141f0b9d87ffcd" + }, + "files": [ + "config/packages/translation.yaml", + "translations/.gitignore" + ] + }, "symfony/translation-contracts": { "version": "v2.0.1" }, diff --git a/translations/.gitignore b/translations/.gitignore new file mode 100644 index 0000000..e69de29 From 20b8c0054bb8aa856b36ec6334e1938ce1eec065 Mon Sep 17 00:00:00 2001 From: Lucas Nothnagel Date: Tue, 24 Mar 2020 22:40:55 +0100 Subject: [PATCH 6/9] Adds basic backend configuration --- config/packages/easy_admin.yaml | 15 +++++++++------ src/Entity/Appointment.php | 5 +++++ src/Entity/Attribute.php | 5 +++++ src/Entity/AttributeType.php | 5 +++++ src/Entity/Talk.php | 5 +++++ src/Entity/User.php | 10 ++++++++++ src/Entity/UserCreateToken.php | 5 +++++ 7 files changed, 44 insertions(+), 6 deletions(-) diff --git a/config/packages/easy_admin.yaml b/config/packages/easy_admin.yaml index 8ad6ecc..11defb3 100644 --- a/config/packages/easy_admin.yaml +++ b/config/packages/easy_admin.yaml @@ -1,6 +1,9 @@ -#easy_admin: -# entities: -# # List the entity class name you want to manage -# - App\Entity\Product -# - App\Entity\Category -# - App\Entity\User +easy_admin: + entities: + - App\Entity\Appointment + - App\Entity\Attribute + - App\Entity\AttributeType + - App\Entity\Location + - App\Entity\Speaker + - App\Entity\Talk + - App\Entity\User diff --git a/src/Entity/Appointment.php b/src/Entity/Appointment.php index 2c86fbe..ba37c3c 100644 --- a/src/Entity/Appointment.php +++ b/src/Entity/Appointment.php @@ -64,6 +64,11 @@ public function __construct(string $title, ?string $text = null, ?DateTimeInterf $this->initAttributes(); } + public function getId(): ?int + { + return $this->id; + } + public function getTitle(): string { return $this->title; diff --git a/src/Entity/Attribute.php b/src/Entity/Attribute.php index fed3412..528fe4f 100644 --- a/src/Entity/Attribute.php +++ b/src/Entity/Attribute.php @@ -48,6 +48,11 @@ public function __construct(AttributeType $type, string $value, ?string $url = n $this->url = $url; } + public function getId(): ?int + { + return $this->id; + } + public function getType(): AttributeType { return $this->type; diff --git a/src/Entity/AttributeType.php b/src/Entity/AttributeType.php index 79ab2ba..a8b3623 100644 --- a/src/Entity/AttributeType.php +++ b/src/Entity/AttributeType.php @@ -41,6 +41,11 @@ public function __construct(string $faIcon, string $title) $this->title = $title; } + public function getId(): ?int + { + return $this->id; + } + public function getTitle(): string { return $this->title; diff --git a/src/Entity/Talk.php b/src/Entity/Talk.php index 00779f8..ea1b132 100644 --- a/src/Entity/Talk.php +++ b/src/Entity/Talk.php @@ -51,6 +51,11 @@ public function __construct(string $title, Speaker $speaker) $this->initAttributes(); } + public function getId(): ?int + { + return $this->id; + } + public function getSpeaker(): ?Speaker { return $this->speaker; diff --git a/src/Entity/User.php b/src/Entity/User.php index 5495978..6f78de5 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -49,6 +49,11 @@ public function __construct(string $email, string $role) $this->role = $role; } + public function getId(): ?int + { + return $this->id; + } + public function getRoles(): array { return [$this->role]; @@ -78,4 +83,9 @@ public function setEncodedPassword(string $encodedPassword): void { $this->encodedPassword = $encodedPassword; } + + public function __toString() + { + return $this->getUsername(); + } } diff --git a/src/Entity/UserCreateToken.php b/src/Entity/UserCreateToken.php index a1c6f17..d762e18 100644 --- a/src/Entity/UserCreateToken.php +++ b/src/Entity/UserCreateToken.php @@ -44,6 +44,11 @@ public function __construct(string $token, string $email, bool $isAdmin) $this->isAdmin = $isAdmin; } + public function getId(): ?int + { + return $this->id; + } + public function getEmail(): string { return $this->email; From 04ea4b3766b5f2da70cd5741788fae036a9bc642 Mon Sep 17 00:00:00 2001 From: Lucas Nothnagel Date: Tue, 24 Mar 2020 22:52:44 +0100 Subject: [PATCH 7/9] Updates Login --- config/packages/easy_admin.yaml | 1 - src/Action/Admin/DashboardAction.php | 27 ------------------------ src/Security/FormLoginAuthenticator.php | 7 +++++- templates/admin/security/login.html.twig | 10 ++++++--- 4 files changed, 13 insertions(+), 32 deletions(-) delete mode 100644 src/Action/Admin/DashboardAction.php diff --git a/config/packages/easy_admin.yaml b/config/packages/easy_admin.yaml index 11defb3..a4a3360 100644 --- a/config/packages/easy_admin.yaml +++ b/config/packages/easy_admin.yaml @@ -6,4 +6,3 @@ easy_admin: - App\Entity\Location - App\Entity\Speaker - App\Entity\Talk - - App\Entity\User diff --git a/src/Action/Admin/DashboardAction.php b/src/Action/Admin/DashboardAction.php deleted file mode 100644 index e59c5e9..0000000 --- a/src/Action/Admin/DashboardAction.php +++ /dev/null @@ -1,27 +0,0 @@ -twig = $twig; - } - - /** - * @Route("/admin/dashboard", name="app_admin_dashboard") - */ - public function __invoke(): TemplateResponse - { - return new TemplateResponse('admin/dashboard.html.twig'); - } -} diff --git a/src/Security/FormLoginAuthenticator.php b/src/Security/FormLoginAuthenticator.php index 550036e..d6a6efe 100644 --- a/src/Security/FormLoginAuthenticator.php +++ b/src/Security/FormLoginAuthenticator.php @@ -10,6 +10,7 @@ use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException; +use Symfony\Component\Security\Core\Security; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator; @@ -46,6 +47,10 @@ public function getCredentials(Request $request): Credentials $username = $request->request->get(self::POST_USERNAME); $password = $request->request->get(self::POST_PASSWORD); + if ($request->hasSession()) { + $request->getSession()->set(Security::LAST_USERNAME, $username); + } + return new Credentials($username, $password); } @@ -67,7 +72,7 @@ public function checkCredentials($credentials, UserInterface $user): bool public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey): RedirectResponse { - return new RedirectResponse($this->router->generate('app_admin_dashboard')); + return new RedirectResponse($this->router->generate('easyadmin')); } protected function getLoginUrl(): string diff --git a/templates/admin/security/login.html.twig b/templates/admin/security/login.html.twig index 883f6c3..d64077e 100644 --- a/templates/admin/security/login.html.twig +++ b/templates/admin/security/login.html.twig @@ -8,9 +8,6 @@ {% endblock %} {% block body %} - {% if error_message %} - {{ error_message.messageKey|trans }} - {% endif %}
+ {% if error_message %} +
+
+ {{ error_message.messageKey|trans }} +
+ {% endif %} {% endblock %} \ No newline at end of file From 2e64609dae1ce8540af30d5203cf63e68eaf43b5 Mon Sep 17 00:00:00 2001 From: Lucas Nothnagel Date: Tue, 24 Mar 2020 23:13:14 +0100 Subject: [PATCH 8/9] Updates Entities for admin area --- config/packages/easy_admin.yaml | 5 +++++ src/Entity/Appointment.php | 10 ++++++++++ src/Entity/Attribute.php | 5 +++++ src/Entity/AttributeType.php | 5 +++++ src/Entity/Location.php | 5 +++++ src/Entity/Speaker.php | 5 +++++ src/Entity/Talk.php | 10 ++++++++++ src/Entity/User.php | 2 +- 8 files changed, 46 insertions(+), 1 deletion(-) diff --git a/config/packages/easy_admin.yaml b/config/packages/easy_admin.yaml index a4a3360..6431179 100644 --- a/config/packages/easy_admin.yaml +++ b/config/packages/easy_admin.yaml @@ -1,4 +1,9 @@ easy_admin: + site_name: ' PHPUGHB Admin' + user: + name_property_path: 'username' + display_name: true + display_avatar: false entities: - App\Entity\Appointment - App\Entity\Attribute diff --git a/src/Entity/Appointment.php b/src/Entity/Appointment.php index ba37c3c..e2fc015 100644 --- a/src/Entity/Appointment.php +++ b/src/Entity/Appointment.php @@ -102,4 +102,14 @@ public function getTalks() { return $this->talks; } + + public function getText(): ?string + { + return $this->text; + } + + public function __toString(): string + { + return $this->title; + } } diff --git a/src/Entity/Attribute.php b/src/Entity/Attribute.php index 528fe4f..3958494 100644 --- a/src/Entity/Attribute.php +++ b/src/Entity/Attribute.php @@ -67,4 +67,9 @@ public function getUrl(): ?string { return $this->url; } + + public function __toString(): string + { + return sprintf('%s -> %s', $this->type, $this->value); + } } diff --git a/src/Entity/AttributeType.php b/src/Entity/AttributeType.php index a8b3623..5352abd 100644 --- a/src/Entity/AttributeType.php +++ b/src/Entity/AttributeType.php @@ -55,4 +55,9 @@ public function getFaIcon(): string { return $this->faIcon; } + + public function __toString(): string + { + return $this->title; + } } diff --git a/src/Entity/Location.php b/src/Entity/Location.php index dd2ccbe..5ed2ce0 100644 --- a/src/Entity/Location.php +++ b/src/Entity/Location.php @@ -138,4 +138,9 @@ public function getAppointments(): Collection { return $this->appointments; } + + public function __toString(): string + { + return $this->name; + } } diff --git a/src/Entity/Speaker.php b/src/Entity/Speaker.php index 272e0f0..e1869ef 100644 --- a/src/Entity/Speaker.php +++ b/src/Entity/Speaker.php @@ -94,4 +94,9 @@ public function addTalk(Talk $talk): void $this->talks[] = $talk; } } + + public function __toString(): string + { + return sprintf('%s %s', $this->firstname, $this->lastname); + } } diff --git a/src/Entity/Talk.php b/src/Entity/Talk.php index ea1b132..b7cca18 100644 --- a/src/Entity/Talk.php +++ b/src/Entity/Talk.php @@ -66,8 +66,18 @@ public function setAppointment(Appointment $appointment): void $this->appointment = $appointment; } + public function getAppointment(): ?Appointment + { + return $this->appointment; + } + public function getTitle(): string { return $this->title; } + + public function __toString(): string + { + return $this->title; + } } diff --git a/src/Entity/User.php b/src/Entity/User.php index 6f78de5..771850a 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -84,7 +84,7 @@ public function setEncodedPassword(string $encodedPassword): void $this->encodedPassword = $encodedPassword; } - public function __toString() + public function __toString(): string { return $this->getUsername(); } From 5045d04ee46d6024c7fc62c2fdf5a2f6e7a82860 Mon Sep 17 00:00:00 2001 From: Lucas Nothnagel Date: Tue, 24 Mar 2020 23:17:54 +0100 Subject: [PATCH 9/9] Fixes tests --- src/Action/Admin/Security/LoginAction.php | 2 +- templates/includes/_footer.html.twig | 2 +- tests/Functional/RestrictedPagesSmokeTest.php | 2 +- tests/Unit/Action/Admin/Security/LoginActionTest.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Action/Admin/Security/LoginAction.php b/src/Action/Admin/Security/LoginAction.php index dd3bbab..581f734 100755 --- a/src/Action/Admin/Security/LoginAction.php +++ b/src/Action/Admin/Security/LoginAction.php @@ -31,7 +31,7 @@ public function __construct( public function __invoke(): LazyResponseInterface { if ($this->tokenStorage->getToken()->getUser() instanceof User) { - return new RedirectResponse('app_admin_dashboard'); + return new RedirectResponse('easyadmin'); } $error = $this->authenticationUtils->getLastAuthenticationError(); diff --git a/templates/includes/_footer.html.twig b/templates/includes/_footer.html.twig index f6bf05e..c85c61b 100644 --- a/templates/includes/_footer.html.twig +++ b/templates/includes/_footer.html.twig @@ -2,6 +2,6 @@ \ No newline at end of file diff --git a/tests/Functional/RestrictedPagesSmokeTest.php b/tests/Functional/RestrictedPagesSmokeTest.php index c1a6e4d..394dba4 100644 --- a/tests/Functional/RestrictedPagesSmokeTest.php +++ b/tests/Functional/RestrictedPagesSmokeTest.php @@ -27,6 +27,6 @@ public function restrictedPagesRedirectedToLogin(string $path): void public function provideRestrictedPages(): iterable { - yield 'Admin Dashboard' => ['/admin/dashboard']; + yield 'Admin Dashboard' => ['/admin/']; } } diff --git a/tests/Unit/Action/Admin/Security/LoginActionTest.php b/tests/Unit/Action/Admin/Security/LoginActionTest.php index 96683ce..c85e4aa 100644 --- a/tests/Unit/Action/Admin/Security/LoginActionTest.php +++ b/tests/Unit/Action/Admin/Security/LoginActionTest.php @@ -35,7 +35,7 @@ protected function setUp(): void */ public function redirectToDashboardWhenTokenStorageContainsUser(): void { - $expectedRouteName = 'app_admin_dashboard'; + $expectedRouteName = 'easyadmin'; $token = $this->prophesize(TokenInterface::class); $this->tokenStorage