From 2b9b973709581dc45a09f27a1cd8f727748f198f Mon Sep 17 00:00:00 2001 From: Baptiste Leduc Date: Mon, 21 Sep 2026 21:30:50 +0000 Subject: [PATCH] =?UTF-8?q?refactor:=20migration=20de=20l'entit=C3=A9=20Vo?= =?UTF-8?q?te=20de=20Ting=20vers=20Doctrine=20(#2383)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- phpstan-baseline.php | 110 ++++---------- .../Admin/Event/VotesListeAction.php | 2 +- .../Controller/Event/CFP/EditAction.php | 4 +- .../Controller/Event/Event/ShowAction.php | 2 +- .../Controller/Event/Vote/IndexAction.php | 2 +- .../Controller/Event/Vote/NewAction.php | 16 +- .../Controller/Event/Vote/VoteController.php | 4 +- .../Entity/Repository/VoteRepository.php | 117 ++++++++++++++ sources/AppBundle/Event/Entity/Vote.php | 44 ++++++ .../Event/Model/Repository/VoteRepository.php | 143 ------------------ sources/AppBundle/Event/Model/Vote.php | 130 ---------------- sources/AppBundle/Notifier/SlackNotifier.php | 2 +- sources/AppBundle/Slack/MessageFactory.php | 16 +- 13 files changed, 214 insertions(+), 378 deletions(-) create mode 100644 sources/AppBundle/Event/Entity/Repository/VoteRepository.php create mode 100644 sources/AppBundle/Event/Entity/Vote.php delete mode 100644 sources/AppBundle/Event/Model/Repository/VoteRepository.php delete mode 100644 sources/AppBundle/Event/Model/Vote.php diff --git a/phpstan-baseline.php b/phpstan-baseline.php index f85ead6d8..4298617eb 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -3530,7 +3530,7 @@ 'path' => __DIR__ . '/sources/AppBundle/Controller/Admin/Event/Ticket/IndexAction.php', ]; $ignoreErrors[] = [ - 'message' => '#^Parameter \\#1 \\$eventId of method AppBundle\\\\Event\\\\Model\\\\Repository\\\\VoteRepository\\:\\:getVotesByEvent\\(\\) expects int, int\\|null given\\.$#', + 'message' => '#^Parameter \\#1 \\$eventId of method AppBundle\\\\Event\\\\Entity\\\\Repository\\\\VoteRepository\\:\\:getVotesByEvent\\(\\) expects int, int\\|null given\\.$#', 'identifier' => 'argument.type', 'count' => 1, 'path' => __DIR__ . '/sources/AppBundle/Controller/Admin/Event/VotesListeAction.php', @@ -4357,12 +4357,6 @@ 'count' => 2, 'path' => __DIR__ . '/sources/AppBundle/Controller/Event/Event/ShowAction.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Cannot access offset \'votes\' on mixed\\.$#', - 'identifier' => 'offsetAccess.nonOffsetAccessible', - 'count' => 2, - 'path' => __DIR__ . '/sources/AppBundle/Controller/Event/Event/ShowAction.php', -]; $ignoreErrors[] = [ 'message' => '#^Cannot call method getPath\\(\\) on mixed\\.$#', 'identifier' => 'method.nonObject', @@ -4700,38 +4694,38 @@ 'path' => __DIR__ . '/sources/AppBundle/Controller/Event/Vote/IndexAction.php', ]; $ignoreErrors[] = [ - 'message' => '#^Parameter \\#3 \\$vote of method AppBundle\\\\Controller\\\\Event\\\\Vote\\\\VoteController\\:\\:createVoteForm\\(\\) expects AppBundle\\\\Event\\\\Model\\\\Vote, mixed given\\.$#', + 'message' => '#^Parameter \\#3 \\$vote of method AppBundle\\\\Controller\\\\Event\\\\Vote\\\\VoteController\\:\\:createVoteForm\\(\\) expects AppBundle\\\\Event\\\\Entity\\\\Vote, mixed given\\.$#', 'identifier' => 'argument.type', 'count' => 1, 'path' => __DIR__ . '/sources/AppBundle/Controller/Event/Vote/IndexAction.php', ]; $ignoreErrors[] = [ - 'message' => '#^Cannot call method setSubmittedOn\\(\\) on mixed\\.$#', - 'identifier' => 'method.nonObject', + 'message' => '#^Cannot access property \\$submittedOn on mixed\\.$#', + 'identifier' => 'property.nonObject', 'count' => 1, 'path' => __DIR__ . '/sources/AppBundle/Controller/Event/Vote/NewAction.php', ]; $ignoreErrors[] = [ - 'message' => '#^Cannot call method setTalk\\(\\) on mixed\\.$#', - 'identifier' => 'method.nonObject', + 'message' => '#^Cannot access property \\$talk on mixed\\.$#', + 'identifier' => 'property.nonObject', 'count' => 1, 'path' => __DIR__ . '/sources/AppBundle/Controller/Event/Vote/NewAction.php', ]; $ignoreErrors[] = [ - 'message' => '#^Parameter \\#1 \\$user of method AppBundle\\\\Event\\\\Model\\\\Vote\\:\\:setUser\\(\\) expects int, int\\|null given\\.$#', + 'message' => '#^Parameter \\#1 \\$vote of method AppBundle\\\\Event\\\\Entity\\\\Repository\\\\VoteRepository\\:\\:upsert\\(\\) expects AppBundle\\\\Event\\\\Entity\\\\Vote, mixed given\\.$#', 'identifier' => 'argument.type', 'count' => 1, 'path' => __DIR__ . '/sources/AppBundle/Controller/Event/Vote/NewAction.php', ]; $ignoreErrors[] = [ - 'message' => '#^Parameter \\#1 \\$vote of method AppBundle\\\\Event\\\\Model\\\\Repository\\\\VoteRepository\\:\\:upsert\\(\\) expects AppBundle\\\\Event\\\\Model\\\\Vote, mixed given\\.$#', + 'message' => '#^Parameter \\#1 \\$vote of method AppBundle\\\\Notifier\\\\SlackNotifier\\:\\:notifyVote\\(\\) expects AppBundle\\\\Event\\\\Entity\\\\Vote, mixed given\\.$#', 'identifier' => 'argument.type', 'count' => 1, 'path' => __DIR__ . '/sources/AppBundle/Controller/Event/Vote/NewAction.php', ]; $ignoreErrors[] = [ - 'message' => '#^Parameter \\#1 \\$vote of method AppBundle\\\\Notifier\\\\SlackNotifier\\:\\:notifyVote\\(\\) expects AppBundle\\\\Event\\\\Model\\\\Vote, mixed given\\.$#', - 'identifier' => 'argument.type', + 'message' => '#^Property AppBundle\\\\Event\\\\Entity\\\\Vote\\:\\:\\$userId \\(int\\) does not accept int\\|null\\.$#', + 'identifier' => 'assign.propertyType', 'count' => 1, 'path' => __DIR__ . '/sources/AppBundle/Controller/Event/Vote/NewAction.php', ]; @@ -5299,6 +5293,18 @@ 'count' => 1, 'path' => __DIR__ . '/sources/AppBundle/Email/Mailer/Mailer.php', ]; +$ignoreErrors[] = [ + 'message' => '#^Cannot cast mixed to int\\.$#', + 'identifier' => 'cast.int', + 'count' => 7, + 'path' => __DIR__ . '/sources/AppBundle/Event/Entity/Repository/VoteRepository.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Parameter \\#1 \\$datetime of class DateTimeImmutable constructor expects string, mixed given\\.$#', + 'identifier' => 'argument.type', + 'count' => 1, + 'path' => __DIR__ . '/sources/AppBundle/Event/Entity/Repository/VoteRepository.php', +]; $ignoreErrors[] = [ 'message' => '#^Class AppBundle\\\\Event\\\\Form\\\\EventCFPTextType extends generic class Symfony\\\\Component\\\\Form\\\\AbstractType but does not specify its types\\: TData$#', 'identifier' => 'missingType.generics', @@ -7261,60 +7267,6 @@ 'count' => 1, 'path' => __DIR__ . '/sources/AppBundle/Event/Model/Repository/UserBadgeRepository.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Cannot cast mixed to int\\.$#', - 'identifier' => 'cast.int', - 'count' => 1, - 'path' => __DIR__ . '/sources/AppBundle/Event/Model/Repository/VoteRepository.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Method AppBundle\\\\Event\\\\Model\\\\Repository\\\\VoteRepository\\:\\:getNumberOfVotesByEvent\\(\\) has no return type specified\\.$#', - 'identifier' => 'missingType.return', - 'count' => 1, - 'path' => __DIR__ . '/sources/AppBundle/Event/Model/Repository/VoteRepository.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Method AppBundle\\\\Event\\\\Model\\\\Repository\\\\VoteRepository\\:\\:getVotesByEvent\\(\\) return type with generic interface CCMBenchmark\\\\Ting\\\\Repository\\\\CollectionInterface does not specify its types\\: T$#', - 'identifier' => 'missingType.generics', - 'count' => 1, - 'path' => __DIR__ . '/sources/AppBundle/Event/Model/Repository/VoteRepository.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Method AppBundle\\\\Event\\\\Model\\\\Repository\\\\VoteRepository\\:\\:getVotesByTalkWithUser\\(\\) has no return type specified\\.$#', - 'identifier' => 'missingType.return', - 'count' => 1, - 'path' => __DIR__ . '/sources/AppBundle/Event/Model/Repository/VoteRepository.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Method AppBundle\\\\Event\\\\Model\\\\Repository\\\\VoteRepository\\:\\:getVotesByTalkWithUser\\(\\) has parameter \\$talkId with no type specified\\.$#', - 'identifier' => 'missingType.parameter', - 'count' => 1, - 'path' => __DIR__ . '/sources/AppBundle/Event/Model/Repository/VoteRepository.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Method AppBundle\\\\Event\\\\Model\\\\Repository\\\\VoteRepository\\:\\:initMetadata\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#', - 'identifier' => 'missingType.iterableValue', - 'count' => 1, - 'path' => __DIR__ . '/sources/AppBundle/Event/Model/Repository/VoteRepository.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Method AppBundle\\\\Event\\\\Model\\\\Repository\\\\VoteRepository\\:\\:initMetadata\\(\\) should return M of CCMBenchmark\\\\Ting\\\\Repository\\\\Metadata but returns CCMBenchmark\\\\Ting\\\\Repository\\\\Metadata\\\\.$#', - 'identifier' => 'return.type', - 'count' => 1, - 'path' => __DIR__ . '/sources/AppBundle/Event/Model/Repository/VoteRepository.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Parameter \\#1 \\$databaseName of method CCMBenchmark\\\\Ting\\\\Repository\\\\Metadata\\\\:\\:setDatabase\\(\\) expects string, mixed given\\.$#', - 'identifier' => 'argument.type', - 'count' => 1, - 'path' => __DIR__ . '/sources/AppBundle/Event/Model/Repository/VoteRepository.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Parameter \\#1 \\$submittedOn of method AppBundle\\\\Event\\\\Model\\\\Vote\\:\\:setSubmittedOn\\(\\) expects DateTime, DateTime\\|null given\\.$#', - 'identifier' => 'argument.type', - 'count' => 1, - 'path' => __DIR__ . '/sources/AppBundle/Event/Model/Repository/VoteRepository.php', -]; $ignoreErrors[] = [ 'message' => '#^Property AppBundle\\\\Event\\\\Model\\\\Room\\:\\:\\$name \\(string\\) does not accept mixed\\.$#', 'identifier' => 'assign.propertyType', @@ -7387,6 +7339,12 @@ 'count' => 1, 'path' => __DIR__ . '/sources/AppBundle/Event/Model/Talk.php', ]; +$ignoreErrors[] = [ + 'message' => '#^Property AppBundle\\\\Event\\\\Model\\\\Talk\\:\\:\\$votes has unknown class AppBundle\\\\Event\\\\Model\\\\Vote as its type\\.$#', + 'identifier' => 'class.notFound', + 'count' => 1, + 'path' => __DIR__ . '/sources/AppBundle/Event/Model/Talk.php', +]; $ignoreErrors[] = [ 'message' => '#^Method AppBundle\\\\Event\\\\Model\\\\Ticket\\:\\:getTags\\(\\) return type has no value type specified in iterable type array\\.$#', 'identifier' => 'missingType.iterableValue', @@ -7405,12 +7363,6 @@ 'count' => 1, 'path' => __DIR__ . '/sources/AppBundle/Event/Model/TicketType.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Method AppBundle\\\\Event\\\\Model\\\\Vote\\:\\:getId\\(\\) should return int but returns int\\|null\\.$#', - 'identifier' => 'return.type', - 'count' => 1, - 'path' => __DIR__ . '/sources/AppBundle/Event/Model/Vote.php', -]; $ignoreErrors[] = [ 'message' => '#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#', 'identifier' => 'foreach.nonIterable', @@ -9109,12 +9061,6 @@ 'count' => 1, 'path' => __DIR__ . '/sources/AppBundle/Slack/MessageFactory.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Cannot call method getTitle\\(\\) on AppBundle\\\\Event\\\\Model\\\\Talk\\|null\\.$#', - 'identifier' => 'method.nonObject', - 'count' => 2, - 'path' => __DIR__ . '/sources/AppBundle/Slack/MessageFactory.php', -]; $ignoreErrors[] = [ 'message' => '#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#', 'identifier' => 'foreach.nonIterable', diff --git a/sources/AppBundle/Controller/Admin/Event/VotesListeAction.php b/sources/AppBundle/Controller/Admin/Event/VotesListeAction.php index 33bf5327a..e1ca856ae 100644 --- a/sources/AppBundle/Controller/Admin/Event/VotesListeAction.php +++ b/sources/AppBundle/Controller/Admin/Event/VotesListeAction.php @@ -5,7 +5,7 @@ namespace AppBundle\Controller\Admin\Event; use AppBundle\Event\AdminEventSelection; -use AppBundle\Event\Model\Repository\VoteRepository; +use AppBundle\Event\Entity\Repository\VoteRepository; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; diff --git a/sources/AppBundle/Controller/Event/CFP/EditAction.php b/sources/AppBundle/Controller/Event/CFP/EditAction.php index c7cd5df2c..faafeb338 100644 --- a/sources/AppBundle/Controller/Event/CFP/EditAction.php +++ b/sources/AppBundle/Controller/Event/CFP/EditAction.php @@ -12,7 +12,7 @@ use AppBundle\Event\Model\Repository\SpeakerRepository; use AppBundle\Event\Model\Repository\TalkInvitationRepository; use AppBundle\Event\Model\Repository\TalkRepository; -use AppBundle\Event\Model\Repository\VoteRepository; +use AppBundle\Event\Entity\Repository\VoteRepository; use AppBundle\Event\Model\Talk; use AppBundle\Event\Model\TalkInvitation; use AppBundle\Event\Talk\InvitationFormHandler; @@ -98,7 +98,7 @@ public function __invoke(Request $request): RedirectResponse|Response 'invitations' => $this->talkInvitationRepository->getPendingInvitationsByTalkId($talk->getId()), 'speakers' => $this->speakerRepository->getSpeakersByTalk($talk), 'invitationForm' => $invitationForm->createView(), - 'votes' => $this->voteRepository->getVotesByTalkWithUser($talk->getId()), + 'votes' => $this->voteRepository->getVotesByTalkWithUser((int) $talk->getId()), 'sidebar' => $this->sidebarRenderer->render($event), ]); } diff --git a/sources/AppBundle/Controller/Event/Event/ShowAction.php b/sources/AppBundle/Controller/Event/Event/ShowAction.php index 35efb44a5..7bf3aa644 100644 --- a/sources/AppBundle/Controller/Event/Event/ShowAction.php +++ b/sources/AppBundle/Controller/Event/Event/ShowAction.php @@ -6,7 +6,7 @@ use AppBundle\Controller\Event\EventActionHelper; use AppBundle\Event\Model\Repository\TalkRepository; -use AppBundle\Event\Model\Repository\VoteRepository; +use AppBundle\Event\Entity\Repository\VoteRepository; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; diff --git a/sources/AppBundle/Controller/Event/Vote/IndexAction.php b/sources/AppBundle/Controller/Event/Vote/IndexAction.php index 63fbb0d7c..345fa7eac 100644 --- a/sources/AppBundle/Controller/Event/Vote/IndexAction.php +++ b/sources/AppBundle/Controller/Event/Vote/IndexAction.php @@ -7,7 +7,7 @@ use AppBundle\Controller\Event\EventActionHelper; use AppBundle\Event\Model\Repository\TalkRepository; use AppBundle\Event\Model\Talk; -use AppBundle\Event\Model\Vote; +use AppBundle\Event\Entity\Vote; use AppBundle\Security\Authentication; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; diff --git a/sources/AppBundle/Controller/Event/Vote/NewAction.php b/sources/AppBundle/Controller/Event/Vote/NewAction.php index 8e68926c8..4b6d5f2b1 100644 --- a/sources/AppBundle/Controller/Event/Vote/NewAction.php +++ b/sources/AppBundle/Controller/Event/Vote/NewAction.php @@ -5,14 +5,16 @@ namespace AppBundle\Controller\Event\Vote; use AppBundle\Controller\Event\EventActionHelper; +use AppBundle\Event\Entity\Vote; +use AppBundle\Event\Entity\Repository\VoteRepository; use AppBundle\Event\Model\GithubUser; use AppBundle\Event\Model\Repository\TalkRepository; -use AppBundle\Event\Model\Repository\VoteRepository; use AppBundle\Event\Model\Talk; -use AppBundle\Event\Model\Vote; use AppBundle\Notifier\SlackNotifier; use AppBundle\Security\Authentication; -use CCMBenchmark\Ting\Exception; +use DateTime; +use Doctrine\DBAL\Exception as DbalException; +use Doctrine\ORM\Exception\ORMException; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; @@ -40,7 +42,7 @@ public function __invoke(Request $request, string $eventSlug, int $talkId): Json $vote = new Vote(); $user = $this->authentication->getGithubUserOrNull(); if ($user instanceof GithubUser) { - $vote->setUser($user->getId()); + $vote->userId = $user->getId(); } $form = $this->createVoteForm($eventSlug, $talkId, $vote); @@ -65,15 +67,15 @@ public function __invoke(Request $request, string $eventSlug, int $talkId): Json } $vote = $form->getData(); - $vote->setSubmittedOn(new \DateTime()); + $vote->submittedOn = new DateTime(); try { - $vote->setTalk($talk); + $vote->talk = $talk; $this->eventDispatcher->addListener(KernelEvents::TERMINATE, function () use ($vote): void { $this->slackNotifier->notifyVote($vote); }); $this->voteRepository->upsert($vote); - } catch (Exception $e) { + } catch (DbalException|ORMException $e) { return new JsonResponse(['errors' => [$e->getMessage()]], Response::HTTP_INTERNAL_SERVER_ERROR); } diff --git a/sources/AppBundle/Controller/Event/Vote/VoteController.php b/sources/AppBundle/Controller/Event/Vote/VoteController.php index f128cff68..972b4e278 100644 --- a/sources/AppBundle/Controller/Event/Vote/VoteController.php +++ b/sources/AppBundle/Controller/Event/Vote/VoteController.php @@ -4,8 +4,8 @@ namespace AppBundle\Controller\Event\Vote; +use AppBundle\Event\Entity\Vote; use AppBundle\Event\Form\VoteType; -use AppBundle\Event\Model\Vote; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; @@ -14,7 +14,7 @@ abstract class VoteController extends AbstractController { protected function createVoteForm(string $eventSlug, int $talkId, Vote $vote): FormInterface { - $vote->setSessionId($talkId); + $vote->sessionId = $talkId; return $this ->createFormBuilder()->create( diff --git a/sources/AppBundle/Event/Entity/Repository/VoteRepository.php b/sources/AppBundle/Event/Entity/Repository/VoteRepository.php new file mode 100644 index 000000000..c48825af2 --- /dev/null +++ b/sources/AppBundle/Event/Entity/Repository/VoteRepository.php @@ -0,0 +1,117 @@ + + */ +final class VoteRepository extends EntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Vote::class); + } + + /** + * @return array{votes: int} + */ + public function getNumberOfVotesByEvent(Event $event): array + { + $row = $this->getEntityManager()->getConnection()->fetchAssociative( + 'SELECT COUNT(vote.id) AS votes + FROM afup_sessions_vote_github AS vote + LEFT JOIN afup_sessions AS session ON session.session_id = vote.session_id + WHERE session.id_forum = :eventId', + ['eventId' => $event->getId()], + ); + + return ['votes' => (int) ($row['votes'] ?? 0)]; + } + + /** + * Votes d'un évènement avec le titre du talk et le login du votant places + * sous forme de tableaux imbriques consommables par le template Twig. + * + * @return list> + */ + public function getVotesByEvent(int $eventId): array + { + $rows = $this->getEntityManager()->getConnection()->fetchAllAssociative( + 'SELECT vote.id, vote.session_id, vote.user, vote.comment, vote.vote, + session.titre AS talk_titre, + github_user.login AS github_user_login + FROM afup_sessions_vote_github AS vote + LEFT JOIN afup_sessions AS session ON session.session_id = vote.session_id + LEFT JOIN afup_user_github AS github_user ON github_user.id = vote.user + WHERE session.id_forum = :eventId + ORDER BY vote.session_id, vote.submitted_on', + ['eventId' => $eventId], + ); + + $votes = []; + foreach ($rows as $row) { + $votes[] = [ + 'id' => (int) $row['id'], + 'sessionId' => (int) $row['session_id'], + 'userId' => (int) $row['user'], + 'comment' => $row['comment'], + 'vote' => (int) $row['vote'], + 'talk' => ['title' => $row['talk_titre']], + 'githubUser' => ['login' => $row['github_user_login']], + ]; + } + + return $votes; + } + + /** + * Votes d'une proposition avec l'information "membre du staff" du votant. + * + * @return list> + */ + public function getVotesByTalkWithUser(int $talkId): array + { + $rows = $this->getEntityManager()->getConnection()->fetchAllAssociative( + 'SELECT vote.id, vote.submitted_on, vote.comment, vote.vote, + github_user.afup_crew + FROM afup_sessions_vote_github AS vote + LEFT JOIN afup_user_github AS github_user ON github_user.id = vote.user + WHERE vote.session_id = :talkId + ORDER BY vote.submitted_on DESC', + ['talkId' => $talkId], + ); + + $votes = []; + foreach ($rows as $row) { + $votes[] = [ + 'id' => (int) $row['id'], + 'submittedOn' => new \DateTimeImmutable($row['submitted_on']), + 'comment' => $row['comment'], + 'vote' => (int) $row['vote'], + 'githubUser' => ['afupCrew' => (bool) $row['afup_crew']], + ]; + } + + return $votes; + } + + public function upsert(Vote $vote): void + { + /** @var Vote|null $previousVote */ + $previousVote = $this->findOneBy(['userId' => $vote->userId, 'sessionId' => $vote->sessionId]); + if ($previousVote !== null) { + $previousVote->comment = $vote->comment; + $previousVote->submittedOn = $vote->submittedOn; + $previousVote->vote = $vote->vote; + $vote = $previousVote; + } + $this->save($vote); + } +} diff --git a/sources/AppBundle/Event/Entity/Vote.php b/sources/AppBundle/Event/Entity/Vote.php new file mode 100644 index 000000000..4ff312930 --- /dev/null +++ b/sources/AppBundle/Event/Entity/Vote.php @@ -0,0 +1,44 @@ + - */ -class VoteRepository extends Repository implements MetadataInitializer -{ - public function getNumberOfVotesByEvent(Event $event) - { - $query = $this->getQuery('SELECT COUNT(id) AS votes -FROM afup_sessions_vote_github asvg -LEFT JOIN afup_sessions s ON s.session_id = asvg.session_id -WHERE s.id_forum = :event'); - $query->setParams(['event' => $event->getId()]); - return $query->query($this->getCollection(new HydratorArray()))->first(); - } - - /** - * @param int $eventId - * @return CollectionInterface - */ - public function getVotesByEvent($eventId) - { - $query = $this - ->getPreparedQuery(' - SELECT asvg.id, asvg.session_id, submitted_on, asvg.comment, asvg.user, vote, - sessions.titre, sessions.abstract, aug.login, aug.avatar_url - FROM afup_sessions_vote_github asvg - LEFT JOIN afup_sessions sessions ON sessions.session_id = asvg.session_id - LEFT JOIN afup_user_github aug ON aug.id = asvg.user - WHERE sessions.id_forum = :eventId - ORDER BY asvg.session_id, asvg.submitted_on - '); - $query->setParams(['eventId' => (int) $eventId]); - - $hydrator = new HydratorSingleObject(); - $hydrator - ->mapObjectTo('sessions', 'asvg', 'setTalk') - ->mapObjectTo('aug', 'asvg', 'setGithubUser') - ; - return $query->query($this->getCollection($hydrator)); - } - - public function getVotesByTalkWithUser($talkId) - { - $query = $this->getPreparedQuery(' - SELECT asvg.id, asvg.session_id, asvg.submitted_on, asvg.comment, asvg.user, asvg.vote, aug.afup_crew - FROM afup_sessions_vote_github asvg - LEFT JOIN afup_user_github aug ON aug.id = asvg.user - WHERE asvg.session_id = :talkId - ORDER BY asvg.submitted_on DESC - '); - - $query->setParams(['talkId' => (int) $talkId]); - - $hydrator = new HydratorSingleObject(); - $hydrator - ->mapObjectTo('aug', 'asvg', 'setGithubUser') - ; - return $query->query($this->getCollection($hydrator)); - } - - /** - * @inheritDoc - */ - public static function initMetadata(SerializerFactoryInterface $serializerFactory, array $options = []) - { - $metadata = new Metadata($serializerFactory); - - $metadata->setEntity(Vote::class); - $metadata->setConnectionName('main'); - $metadata->setDatabase($options['database']); - $metadata->setTable('afup_sessions_vote_github'); - - $metadata - ->addField([ - 'columnName' => 'id', - 'fieldName' => 'id', - 'primary' => true, - 'autoincrement' => true, - 'type' => 'int', - ]) - ->addField([ - 'columnName' => 'session_id', - 'fieldName' => 'sessionId', - 'type' => 'int', - ]) - ->addField([ - 'columnName' => 'submitted_on', - 'fieldName' => 'submittedOn', - 'type' => 'datetime', - ]) - ->addField([ - 'columnName' => 'comment', - 'fieldName' => 'comment', - 'type' => 'string', - ]) - ->addField([ - 'columnName' => 'user', - 'fieldName' => 'user', - 'type' => 'int', - ]) - ->addField([ - 'columnName' => 'vote', - 'fieldName' => 'vote', - 'type' => 'int', - ]) - ; - - return $metadata; - } - - public function upsert(Vote $vote): void - { - /** - * @var Vote|null $previousVote - */ - $previousVote = $this->getOneBy(['user' => $vote->getUser(), 'sessionId' => $vote->getSessionId()]); - if ($previousVote !== null) { - $previousVote - ->setComment($vote->getComment()) - ->setSubmittedOn($vote->getSubmittedOn()) - ->setVote($vote->getVote()) - ; - $vote = $previousVote; - } - $this->save($vote); - } -} diff --git a/sources/AppBundle/Event/Model/Vote.php b/sources/AppBundle/Event/Model/Vote.php deleted file mode 100644 index bc75adcaa..000000000 --- a/sources/AppBundle/Event/Model/Vote.php +++ /dev/null @@ -1,130 +0,0 @@ -id; - } - - public function setId(int $id): self - { - $this->propertyChanged('id', $this->id, $id); - $this->id = $id; - return $this; - } - - public function getSessionId(): int - { - return $this->sessionId; - } - - public function setSessionId(int $sessionId): self - { - $this->propertyChanged('sessionId', $this->sessionId, $sessionId); - $this->sessionId = $sessionId; - return $this; - } - - public function getUser(): int - { - return $this->user; - } - - public function setUser(int $user): self - { - $this->propertyChanged('user', $this->user, $user); - $this->user = $user; - return $this; - } - - public function getComment(): ?string - { - return $this->comment; - } - - public function setComment(?string $comment): self - { - $this->propertyChanged('comment', $this->comment, $comment); - $this->comment = $comment; - return $this; - } - - public function getVote(): int - { - return $this->vote; - } - - public function setVote(int $vote): self - { - $this->propertyChanged('vote', $this->vote, $vote); - $this->vote = $vote; - return $this; - } - - public function getSubmittedOn(): ?\DateTime - { - return $this->submittedOn; - } - - public function setSubmittedOn(\DateTime $submittedOn): self - { - $this->propertyChanged('submittedOn', $this->submittedOn, $submittedOn); - $this->submittedOn = $submittedOn; - return $this; - } - - public function getGithubUser(): ?GithubUser - { - return $this->githubUser; - } - - public function setGithubUser(GithubUser $githubUser): self - { - $this->githubUser = $githubUser; - return $this; - } - - public function getTalk(): ?Talk - { - return $this->talk; - } - - public function setTalk(Talk $talk): self - { - $this->talk = $talk; - return $this; - } -} diff --git a/sources/AppBundle/Notifier/SlackNotifier.php b/sources/AppBundle/Notifier/SlackNotifier.php index 838495285..f516e2b11 100644 --- a/sources/AppBundle/Notifier/SlackNotifier.php +++ b/sources/AppBundle/Notifier/SlackNotifier.php @@ -4,9 +4,9 @@ namespace AppBundle\Notifier; +use AppBundle\Event\Entity\Vote; use AppBundle\Event\Model\Event; use AppBundle\Event\Model\Talk; -use AppBundle\Event\Model\Vote; use AppBundle\Slack\Message; use AppBundle\Slack\MessageFactory; use JMS\Serializer\SerializerInterface; diff --git a/sources/AppBundle/Slack/MessageFactory.php b/sources/AppBundle/Slack/MessageFactory.php index 19cc4c821..c0279dba8 100644 --- a/sources/AppBundle/Slack/MessageFactory.php +++ b/sources/AppBundle/Slack/MessageFactory.php @@ -5,6 +5,7 @@ namespace AppBundle\Slack; use AppBundle\Association\Model\Repository\UserRepository; +use AppBundle\Event\Entity\Vote; use AppBundle\Event\Model\Event; use AppBundle\Event\Model\EventStats\SalesPilotage; use AppBundle\Event\Model\Repository\EventStatsRepository; @@ -12,7 +13,6 @@ use AppBundle\Event\Model\Repository\TalkToSpeakersRepository; use AppBundle\Event\Model\Repository\TicketTypeRepository; use AppBundle\Event\Model\Talk; -use AppBundle\Event\Model\Vote; use AppBundle\AssembleeGenerale\Entity\Repository\PresenceRepository; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Contracts\Translation\TranslatorInterface; @@ -36,9 +36,9 @@ public function createMessageForVote(Vote $vote): Message ->setTitleLink('https://afup.org/pages/administration/index.php?page=forum_vote_github') ->setFallback(sprintf( 'Nouveau vote sur la conférence "%s". Note: %s. Commentaire: %s', - $vote->getTalk()->getTitle(), - $vote->getVote(), - $vote->getComment(), + $vote->talk?->getTitle() ?? '', + $vote->vote, + $vote->comment, ), ) ->setColor('good') @@ -47,18 +47,18 @@ public function createMessageForVote(Vote $vote): Message $attachment ->addField( - new Field()->setShort(false)->setTitle('Talk')->setValue($vote->getTalk()->getTitle()), + new Field()->setShort(false)->setTitle('Talk')->setValue($vote->talk?->getTitle() ?? ''), ) ->addField( new Field()->setShort(false)->setTitle('Nouveau vote')->setValue( - str_repeat(':star:', $vote->getVote()), + str_repeat(':star:', $vote->vote), ), ) ; - if ($vote->getComment() !== null) { + if ($vote->comment !== null) { $attachment ->addField( - new Field()->setShort(false)->setTitle('Commentaire')->setValue($vote->getComment()), + new Field()->setShort(false)->setTitle('Commentaire')->setValue($vote->comment), ) ; }