Skip to content

Commit

Permalink
Adds ability to add multiple participants to chat / clearly state tha…
Browse files Browse the repository at this point in the history
…t users where added or removed (related to #464)
  • Loading branch information
frostieDE committed Nov 24, 2024
1 parent 2a0af26 commit efe2dd2
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 20 deletions.
21 changes: 10 additions & 11 deletions src/Controller/ChatController.php
Original file line number Diff line number Diff line change
Expand Up @@ -238,23 +238,22 @@ public function showChat(Chat $chat, Request $request, ChatSeenByHelper $chatSee
]);
}

$participantsForm = $this->createForm(ChatUserRecipientType::class, null, ['multiple' => false, 'required' => false]);
$participantsForm = $this->createForm(ChatUserRecipientType::class, null, ['multiple' => true, 'required' => false]);
$participantsForm->handleRequest($request);

if($this->isGranted(ChatVoter::Edit, $chat) && $participantsForm->isSubmitted() && $participantsForm->isValid()) {
$newParticipant = $participantsForm->getData();
$newParticipants = $participantsForm->getData();

if(!$chat->getParticipants()->contains($newParticipant)) {
$chat->getParticipants()->add($newParticipant);
$this->chatRepository->persist($chat);

$dispatcher->dispatch(new ChatMessageCreatedEvent($chat->getMessages()->first()));

$this->addFlash('success', 'chat.participants.add.success');
} else {
$this->addFlash('error', 'chat.participants.add.error');
foreach ($newParticipants as $newParticipant) {
if (!$chat->getParticipants()->contains($newParticipant)) {
$chat->getParticipants()->add($newParticipant);
}
}

$this->chatRepository->persist($chat);
//$dispatcher->dispatch(new ChatMessageCreatedEvent($chat->getMessages()->first()));
$this->addFlash('success', 'chat.participants.add.success');

return $this->redirectToRoute('show_chat', [
'uuid' => $chat->getUuid()
]);
Expand Down
77 changes: 77 additions & 0 deletions src/Doctrine/ChatMessageRecipientsSubscriber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

namespace App\Doctrine;

use App\Converter\UserStringConverter;
use App\Entity\Chat;
use App\Entity\ChatMessage;
use App\Entity\User;
use App\EventSubscriber\DoctrineEntityCollector;
use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener;
use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\ORM\Event\PreUpdateEventArgs;
use Doctrine\ORM\Events;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

#[AsDoctrineListener(event: Events::preUpdate)]
class ChatMessageRecipientsSubscriber {

public function __construct(private readonly TokenStorageInterface $tokenStorage,
private readonly TranslatorInterface $translator,
private readonly DoctrineEntityCollector $entityCollector,
private readonly UserStringConverter $userStringConverter) {

}

public function preUpdate(PreUpdateEventArgs $args): void {
$currentUser = $this->tokenStorage->getToken()?->getUser();

if(!$currentUser instanceof User) {
return;
}

$uow = $args->getObjectManager()->getUnitOfWork();

foreach($uow->getScheduledCollectionUpdates() as $collectionUpdate) {
if(!$collectionUpdate->getOwner() instanceof Chat) {
continue;
}

$chat = $collectionUpdate->getOwner();
assert($chat instanceof Chat);

$addedParticipants = [ ];
$removedParticipants = [ ];

foreach($collectionUpdate->getInsertDiff() as $user) {
$addedParticipants[] = $user;
}

foreach($collectionUpdate->getDeleteDiff() as $user) {
$removedParticipants[] = $user;
}

$content = '';

if(count($addedParticipants) > 0) {
$content = $this->translator->trans('chat.participants.success.added', [
'%users%' => implode(', ', array_map(fn(User $user) => $this->userStringConverter->convert($user, includeUsername: false), $addedParticipants)),
]);
}

if(count($removedParticipants) > 0) {
$content .= "\n\n" . $this->translator->trans('chat.participants.success.remove', [
'%users%' => implode(', ', array_map(fn(User $user) => $this->userStringConverter->convert($user, includeUsername: false), $removedParticipants)),
]);
}

$chatMessage = (new ChatMessage())
->setChat($chat)
->setContent(trim($content))
->setCreatedBy($currentUser);

$this->entityCollector->collectForPersist($chatMessage);
}
}
}
63 changes: 63 additions & 0 deletions src/EventSubscriber/DoctrineEntityCollector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

namespace App\EventSubscriber;

use Doctrine\Common\EventArgs;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\TerminateEvent;

/**
* This collector collects entities to be persisted into the database. This
* is useful for entities that need to be persisted during a Doctrine event
* listener.
*
* The documentation states that using EntityManager::flush() is highly
* discouraged during any Doctrine listener.
*/
class DoctrineEntityCollector implements EventSubscriberInterface {

private array $collectedForPersist = [ ];

private array $collectedForRemoval = [ ];

public function __construct(private readonly EntityManagerInterface $em) {

}

public function collectForPersist(object $entity): void {
$this->collectedForPersist[] = $entity;
}

public function collectForRemoval(object $entity): void {
$this->collectedForRemoval[] = $entity;
}

private function persistRemoveAndFlush(): void {
foreach($this->collectedForPersist as $entity) {
$this->em->persist($entity);
}

foreach($this->collectedForRemoval as $entity) {
$this->em->remove($entity);
}

$this->em->flush();
}

public function onKernelTerminate(TerminateEvent $event): void {
$this->persistRemoveAndFlush();
}

public function onConsoleTerminate(ConsoleTerminateEvent $event): void {
$this->persistRemoveAndFlush();
}

public static function getSubscribedEvents(): array {
return [
TerminateEvent::class => ['onKernelTerminate', 10],
ConsoleTerminateEvent::class => ['onConsoleTerminate', 10]
];
}
}
6 changes: 3 additions & 3 deletions src/EventSubscriber/DoctrineEventsCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ public function onKernelTerminate(TerminateEvent $event): void {
$this->dispatchAllEvents();
}

public function onConsoleTermine(ConsoleTerminateEvent $event): void {
public function onConsoleTerminate(ConsoleTerminateEvent $event): void {
$this->dispatchAllEvents();
}

public static function getSubscribedEvents(): array {
return [
TerminateEvent::class => 'onKernelTerminate',
ConsoleTerminateEvent::class => 'onConsoleTermine'
TerminateEvent::class => ['onKernelTerminate', 9 ],
ConsoleTerminateEvent::class => ['onConsoleTerminate', 9]
];
}
}
11 changes: 5 additions & 6 deletions templates/chat/show.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -206,12 +206,11 @@

{{ form_start(participantsForm) }}

<div class="input-group">
{{ form_widget(participantsForm) }}
<button class="btn btn-outline-secondary btn-sm">
<i class="fas fa-plus"></i> {{ 'actions.add'|trans }}
</button>
</div>
{{ form_widget(participantsForm) }}

<button class="btn btn-outline-secondary btn-sm mt-1">
<i class="fas fa-plus"></i> {{ 'actions.add'|trans }}
</button>

{{ form_end(participantsForm) }}
</div>
Expand Down
3 changes: 3 additions & 0 deletions translations/messages.de.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2482,6 +2482,9 @@ chat:
remove:
success: Person erfolgreich aus dem Gespräch entfernt
missing_rights: Teilnehmer können nur von Benutzern mit der Rolle ROLE_CHAT_MOD hinzugefügt werden.
success:
added: "%users% zu diesem Gespräch hinzugefügt."
remove: "%users% aus diesem Gespräch entfernt."
tags:
label: Kategorien
filter: Kategorie
Expand Down

0 comments on commit efe2dd2

Please sign in to comment.