Feat: Add contacts

This commit is contained in:
Björn Fromme committed 2023-10-16 12:05:18 +02:00
1 parent f5fee787a0
commit 3fd4c6ca54
19 files changed
+658 -2

No files matched your search

@@ -0,0 +1,79 @@
<?php
namespace App\Controller\Admin\System\Contact;
use App\Entity\Contact;
use App\Entity\Upload;
use App\Entity\User;
use App\Form\ContactType;
use App\Model\AjaxModalResponseDto;
use App\Service\Upload\UploadHandler;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
class CreateController extends AbstractController
{
public function __construct(
private readonly UploadHandler $uploadHandler,
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger
) {
}
#[Route('/admin/system/contact/create', name: 'app_admin_system_contact_create')]
#[IsGranted('ROLE_ADMINISTRATIVE')]
public function index(Request $request): JsonResponse
{
$response = new AjaxModalResponseDto();
$contact = new Contact();
$formAction = $this->generateUrl('app_admin_system_contact_create');
// Handle upload independently from form submission to avoid issues with failing validation
$uploadSession = $this->uploadHandler->getUploadSession();
if (true === $request->isMethod('POST') && 0 < $uploadSession->getCount()) {
/** @var User $user */
$user = $this->getUser();
$photo = Upload::fromUploadDto($uploadSession->getUploads()->first(), $user, Upload::TYPE_PHOTO);
$contact->setPhoto($photo);
$this->entityManager->flush();
$this->uploadHandler->moveUploadSessionFilesFromOrphanage(Upload::TYPE_PHOTO, $uploadSession);
$this->uploadHandler->destroyUploadSession();
}
$form = $this->createForm(
ContactType::class,
$contact,
[
'action' => $formAction,
'ajax_submit' => true,
'upload_session' => $uploadSession,
]
);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->entityManager->persist($contact);
$this->entityManager->flush();
$this->addFlash('success', 'Der Ansprechpartner wurde hinzugefügt');
$this->logger->info('Create contact', [
'contact' => $contact->getName(),
]);
$response->setCloseAndRedirect($this->generateUrl('app_admin_system_contact_index'));
} else {
$response->setContent($this->renderView('admin/system/contact/create.html.twig', [
'form' => $form,
]));
}
return $this->json($response);
}
}
@@ -0,0 +1,35 @@
<?php
namespace App\Controller\Admin\System\Contact;
use App\Entity\Contact;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
class DeleteController extends AbstractController
{
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger
) {
}
#[Route('/admin/system/contact/delete/{id}', name: 'app_admin_system_contact_delete')]
#[IsGranted('ROLE_ADMINISTRATIVE')]
public function index(Contact $contact): Response
{
$this->entityManager->remove($contact);
$this->entityManager->flush();
$this->addFlash('success', 'Der Ansprechpartner wurde gelöscht');
$this->logger->info('Delete contact', [
'contact' => $contact->getName(),
]);
return $this->redirectToRoute('app_admin_system_contact_index');
}
}
@@ -0,0 +1,76 @@
<?php
namespace App\Controller\Admin\System\Contact;
use App\Entity\Contact;
use App\Entity\Upload;
use App\Entity\User;
use App\Form\ContactType;
use App\Model\AjaxModalResponseDto;
use App\Service\Upload\UploadHandler;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
class EditController extends AbstractController
{
public function __construct(
private readonly UploadHandler $uploadHandler,
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger
) {
}
#[Route('/admin/system/contact/edit/{id}', name: 'app_admin_system_contact_edit')]
#[IsGranted('ROLE_ADMINISTRATIVE')]
public function index(Contact $contact, Request $request): JsonResponse
{
$response = new AjaxModalResponseDto();
$formAction = $this->generateUrl('app_admin_system_contact_edit', ['id' => $contact->getId()]);
// Handle upload independently from form submission to avoid issues with failing validation
$uploadSession = $this->uploadHandler->getUploadSession();
if (true === $request->isMethod('POST') && 0 < $uploadSession->getCount()) {
/** @var User $user */
$user = $this->getUser();
$photo = Upload::fromUploadDto($uploadSession->getUploads()->first(), $user, Upload::TYPE_PHOTO);
if (null !== $existingPhoto = $contact->getPhoto()) {
$this->entityManager->remove($existingPhoto);
}
$contact->setPhoto($photo);
$this->entityManager->flush();
$this->uploadHandler->moveUploadSessionFilesFromOrphanage(Upload::TYPE_PHOTO, $uploadSession);
$this->uploadHandler->destroyUploadSession();
}
$form = $this->createForm(
ContactType::class,
$contact,
[
'action' => $formAction,
'ajax_submit' => true,
'upload_session' => $uploadSession,
]
);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->entityManager->flush();
$this->addFlash('success', 'Der Ansprechpartner wurde aktualisiert');
$this->logger->info('Edit contact', [
'contact' => $contact->getName(),
]);
$response->setCloseAndRedirect($this->generateUrl('app_admin_system_contact_index'));
} else {
$response->setContent($this->renderView('admin/system/contact/edit.html.twig', [
'form' => $form,
]));
}
return $this->json($response);
}
}
@@ -0,0 +1,29 @@
<?php
namespace App\Controller\Admin\System\Contact;
use App\Repository\ContactRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
class IndexController extends AbstractController
{
public function __construct(private readonly ContactRepository $contactRepository)
{}
#[Route('/admin/system/contact', name: 'app_admin_system_contact_index')]
#[IsGranted('ROLE_ADMINISTRATIVE')]
public function index(): Response
{
$contacts = $this
->contactRepository
->findBy([], ['name' => 'ASC'])
;
return $this->render('admin/system/contact/index.html.twig', [
'contacts' => $contacts,
]);
}
}
+18 -1
View File
@@ -2,15 +2,32 @@
namespace App\Controller\Teamer;
use App\Repository\ContactRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class ContactController extends AbstractController
{
public function __construct(private readonly ContactRepository $contactRepository)
{}
#[Route('/teamer/contact', name: 'app_teamer_contact')]
public function index(): Response
{
return $this->render('teamer/contact/index.html.twig');
$generalContacts = $this
->contactRepository
->getGeneralContacts()
;
$destinationContacts = $this
->contactRepository
->getDestinationContacts()
;
return $this->render('teamer/contact/index.html.twig', [
'generalContacts' => $generalContacts,
'destinationContacts' => $destinationContacts,
]);
}
}
+115
View File
@@ -0,0 +1,115 @@
<?php
namespace App\Entity;
use App\Repository\ContactRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: ContactRepository::class)]
class Contact
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 255)]
#[Assert\NotBlank(message: 'Bitte gib den Namen an')]
private ?string $name = null;
#[ORM\Column(length: 255)]
#[Assert\NotBlank(message: 'Bitte gib die E-Mail-Adresse an')]
#[Assert\Email(message: 'Bitte gib eine gültige E-Mail-Adresse an', mode: 'strict')]
private ?string $email = null;
#[ORM\OneToOne(cascade: ['persist', 'remove'], fetch: 'EAGER')]
#[Assert\NotNull(message: 'Bitte lade ein Foto hoch')]
private ?Upload $photo = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $destination = null;
#[ORM\OneToOne(mappedBy: 'contact', cascade: ['persist', 'remove'], fetch: 'EXTRA_LAZY')]
private ?User $user = null;
public function __toString()
{
return $this->getName();
}
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): static
{
$this->name = $name;
return $this;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): static
{
$this->email = $email;
return $this;
}
public function getPhoto(): ?Upload
{
return $this->photo;
}
public function setPhoto(?Upload $photo): static
{
$this->photo = $photo;
return $this;
}
public function getDestination(): ?string
{
return $this->destination;
}
public function setDestination(?string $destination): static
{
$this->destination = $destination;
return $this;
}
public function getUser(): ?User
{
return $this->user;
}
public function setUser(?User $user): static
{
// unset the owning side of the relation if necessary
if ($user === null && $this->user !== null) {
$this->user->setContact(null);
}
// set the owning side of the relation if necessary
if ($user !== null && $user->getContact() !== $this) {
$user->setContact($this);
}
$this->user = $user;
return $this;
}
}
+1 -1
View File
@@ -115,7 +115,7 @@ class Teamer implements TimestampableEntityInterface
#[ORM\OneToMany(mappedBy: 'teamer', targetEntity: Disposition::class, cascade: ['remove'])]
private Collection $dispositions;
#[ORM\OneToOne(mappedBy: 'teamer')]
#[ORM\OneToOne(mappedBy: 'teamer', fetch: 'EXTRA_LAZY')]
private ?User $user = null;
#[ORM\Column]
+15
View File
@@ -45,6 +45,9 @@ class User implements UserInterface, TimestampableEntityInterface
#[ORM\OneToOne(inversedBy: 'user', cascade: ['persist', 'remove'])]
private ?Teamer $teamer = null;
#[ORM\OneToOne(inversedBy: 'user', cascade: ['persist', 'remove'])]
private ?Contact $contact = null;
public function __construct()
{
$this->uuid = Uuid::v4();
@@ -200,4 +203,16 @@ class User implements UserInterface, TimestampableEntityInterface
return $this;
}
public function getContact(): ?Contact
{
return $this->contact;
}
public function setContact(?Contact $contact): static
{
$this->contact = $contact;
return $this;
}
}
+42
View File
@@ -0,0 +1,42 @@
<?php
namespace App\Form;
use App\Entity\Contact;
use App\Model\UploadSessionDto;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ContactType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name', TextType::class, [
'label' => 'Name',
])
->add('email', EmailType::class, [
'label' => 'E-Mail',
])
->add('destination', TextType::class, [
'label' => 'Destination',
'required' => false,
])
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver
->setDefaults([
'data_class' => Contact::class,
])
->setRequired(['upload_session'])
->setAllowedTypes('upload_session', UploadSessionDto::class)
;
}
}
+4
View File
@@ -87,6 +87,10 @@ class AdminMenuBuilder extends AbstractMenuBuilder
'route' => 'app_admin_system_document_index',
'title' => 'Dokumente',
],
[
'route' => 'app_admin_system_contact_index',
'title' => 'Ansprechpartner',
],
],
],
];
+50
View File
@@ -0,0 +1,50 @@
<?php
namespace App\Repository;
use App\Entity\Contact;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<Contact>
*
* @method Contact|null find($id, $lockMode = null, $lockVersion = null)
* @method Contact|null findOneBy(array $criteria, array $orderBy = null)
* @method Contact[] findAll()
* @method Contact[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class ContactRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Contact::class);
}
public function getGeneralContacts(): array
{
$qb = $this->createQueryBuilder('contact');
return $qb
->leftJoin('contact.photo', 'photo')
->where($qb->expr()->isNull('contact.destination'))
->orderBy('contact.name', 'ASC')
->getQuery()
->getResult()
;
}
public function getDestinationContacts(): array
{
$qb = $this->createQueryBuilder('contact');
return $qb
->leftJoin('contact.photo', 'photo')
->where($qb->expr()->isNotNull('contact.destination'))
->orderBy('contact.name', 'ASC')
->addOrderBy('contact.destination', 'ASC')
->getQuery()
->getResult()
;
}
}