From f970037beecaaa2c4b48c615f05bde223552c842 Mon Sep 17 00:00:00 2001 From: Jalil Arfaoui Date: Sun, 20 Jun 2021 11:09:00 +0200 Subject: [PATCH] perf/save_ratings_count_in_notices_entities --- .env | 7 + composer.json | 27 +- composer.lock | 91 +++++- config/packages/easy_admin.yaml | 20 +- config/packages/messenger.yaml | 14 + migrations/Version20210704210627.php | 54 ++++ src/Controller/AdminApiController.php | 47 ---- src/Controller/Api/V3/PostNoticeRating.http | 9 + .../Api/V3/PostNoticeRatingAction.php | 6 +- src/Entity/Notice.php | 265 +++++++++++------- src/Message/NoticeRated.php | 22 ++ src/MessageHandler/NoticeRatedHandler.php | 45 +++ src/Repository/RatingRepository.php | 15 + src/Serializer/V3/NoticeNormalizer.php | 4 +- symfony.lock | 12 + translations/messages.fr.yml | 18 +- 16 files changed, 475 insertions(+), 181 deletions(-) create mode 100644 config/packages/messenger.yaml create mode 100644 migrations/Version20210704210627.php delete mode 100644 src/Controller/AdminApiController.php create mode 100644 src/Controller/Api/V3/PostNoticeRating.http create mode 100644 src/Message/NoticeRated.php create mode 100644 src/MessageHandler/NoticeRatedHandler.php diff --git a/.env b/.env index 3012f3e0..59a1d856 100644 --- a/.env +++ b/.env @@ -45,3 +45,10 @@ JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem JWT_PASSPHRASE=275fee27732fdd71221f5cbe115f889d ###< lexik/jwt-authentication-bundle ### + +###> symfony/messenger ### +# Choose one of the transports below +# MESSENGER_TRANSPORT_DSN=doctrine://default +# MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages +# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages +###< symfony/messenger ### diff --git a/composer.json b/composer.json index 60a60de2..cd232a09 100755 --- a/composer.json +++ b/composer.json @@ -34,38 +34,39 @@ "symfony/validator": "4.4.*", "symfony/twig-bundle": "4.4.*", "symfony/yaml": "4.4.*", + "symfony/apache-pack": "^1.0", + "symfony/expression-language": "4.4.*", + "symfony/proxy-manager-bridge": "4.4.*", + "symfony/property-access": "4.4.*", + "symfony/property-info": "4.4.*", + "symfony/serializer": "4.4.*", + "symfony/messenger": "4.4.*", + "doctrine/annotations": "^1.0", "doctrine/orm": "^2.3", "doctrine/doctrine-bundle": "^1.2", "doctrine/doctrine-cache-bundle": "^1.4", "doctrine/doctrine-migrations-bundle": "^v1.3.2", + "twig/extra-bundle": "^2.12|^3.0", + "twig/twig": "^2.12|^3.0", "sensio/framework-extra-bundle": "^5.6", "friendsofsymfony/user-bundle": "^2.1.2", "friendsofsymfony/jsrouting-bundle": "^2.6", + "beberlei/doctrineextensions": "^1.2", + "knplabs/doctrine-behaviors": "1.4", + "api-platform/core": "^2.6", "easycorp/easyadmin-bundle": "^2", + "composer/package-versions-deprecated": "^1.11", "ocramius/proxy-manager": "^2.0.2", "marc-mabe/php-enum": "^2.2", - "beberlei/doctrineextensions": "^1.2", "vich/uploader-bundle": "^1.7", "liip/imagine-bundle": "^2.0", "youthweb/urllinker": "^1.2", "sentry/sentry-symfony": "^3.0", - "knplabs/doctrine-behaviors": "1.4", "nelmio/cors-bundle": "1.5.6", "league/uri": "^6.2", "league/uri-components": "^2.2", - "composer/package-versions-deprecated": "^1.11", - "twig/extra-bundle": "^2.12|^3.0", - "twig/twig": "^2.12|^3.0", - "symfony/apache-pack": "^1.0", "ezyang/htmlpurifier": "^4.13", - "api-platform/core": "^2.6", - "symfony/expression-language": "4.4.*", - "symfony/proxy-manager-bridge": "4.4.*", - "doctrine/annotations": "^1.0", "phpdocumentor/reflection-docblock": "^5.2", - "symfony/property-access": "4.4.*", - "symfony/property-info": "4.4.*", - "symfony/serializer": "4.4.*", "lexik/jwt-authentication-bundle": "^2.11" }, "require-dev": { diff --git a/composer.lock b/composer.lock index a295740e..6d341740 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": "c661776a2beedb744bc65753c2774a60", + "content-hash": "b46e79c17007524666a26a9b0d358a17", "packages": [ { "name": "api-platform/core", @@ -7228,6 +7228,93 @@ ], "time": "2020-10-24T11:50:19+00:00" }, + { + "name": "symfony/messenger", + "version": "v4.4.26", + "source": { + "type": "git", + "url": "https://github.com/symfony/messenger.git", + "reference": "de0030fda722e26b4f3cc23622e583c6e985a5a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/messenger/zipball/de0030fda722e26b4f3cc23622e583c6e985a5a5", + "reference": "de0030fda722e26b4f3cc23622e583c6e985a5a5", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "~1.0", + "symfony/polyfill-php80": "^1.15" + }, + "conflict": { + "doctrine/persistence": "<1.3", + "symfony/event-dispatcher": "<4.3", + "symfony/framework-bundle": "<4.4", + "symfony/http-kernel": "<4.4" + }, + "require-dev": { + "doctrine/dbal": "^2.6|^3.0", + "doctrine/persistence": "^1.3|^2", + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4.19|^4.1.8|^5.0", + "symfony/event-dispatcher": "^4.3|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/property-access": "^3.4|^4.0|^5.0", + "symfony/serializer": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/validator": "^3.4|^4.0|^5.0" + }, + "suggest": { + "enqueue/messenger-adapter": "For using the php-enqueue library as a transport." + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Messenger\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Samuel Roze", + "email": "samuel.roze@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps applications send and receive messages to/from other applications or via message queues", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/messenger/tree/v4.4.26" + }, + "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": "2021-06-27T12:18:17+00:00" + }, { "name": "symfony/mime", "version": "v4.4.16", @@ -13488,5 +13575,5 @@ "platform-overrides": { "php": "7.3" }, - "plugin-api-version": "1.1.0" + "plugin-api-version": "2.0.0" } diff --git a/config/packages/easy_admin.yaml b/config/packages/easy_admin.yaml index ff09012b..a39f8394 100644 --- a/config/packages/easy_admin.yaml +++ b/config/packages/easy_admin.yaml @@ -21,6 +21,8 @@ easy_admin: - 'js/message_validator.js' - 'js/filter_table_row.js' - 'js/select2.js' + formats: + datetime: 'd/m/y' entities: Notice: class: App\Entity\Notice @@ -32,17 +34,17 @@ easy_admin: fields: ¬iceListFields - { property: id, label: notices.id, css_class: 'column-id' } - { property: contributor, label: notices.contributor, css_class: 'column-contributor' } - - { property: relayersCount, label: notices.relayers, css_class: 'column-relayers' } + - { property: matchingContexts, label: notices.matchingContexts, css_class: 'column-matchingContexts' } - { property: message, label: notices.message, css_class: 'column-message' } + - { property: relayersCount, label: notices.relayers, css_class: 'column-relayers' } - { property: visibility, label: notices.visibility, css_class: 'column-visibility' } - - { property: matchingContexts, label: notices.matchingContexts, css_class: 'column-matchingContexts' } - - { property: badgedRatingCount, label: notices.badgedRatingCount, css_class: 'graphable column-badgedRatingCount' } - - { property: displayedRatingCount, label: notices.displayedRatingCount, css_class: 'graphable column-displayedRatingCount' } - - { property: unfoldedRatingCount, label: notices.unfoldedRatingCount, css_class: 'graphable column-unfoldedRatingCount' } - - { property: clickedRatingCount, label: notices.clickedRatingCount, css_class: 'graphable column-clickedRatingCount' } - - { property: likedRatingCount, label: notices.likedRatingCount, css_class: 'graphable column-likedRatingCount' } - - { property: dislikedRatingCount, label: notices.dislikedRatingCount, css_class: 'graphable column-dislikedRatingCount' } - - { property: dismissedRatingCount, label: notices.dismissedRatingCount, css_class: 'graphable column-dismissedRatingCount' } + - { property: badgedCount, label: notices.badgedCount, css_class: 'graphable column-badgedCount' } + - { property: displayedCount, label: notices.displayedCount, css_class: 'graphable column-displayedCount' } + - { property: unfoldedCount, label: notices.unfoldedCount, css_class: 'graphable column-unfoldedCount' } + - { property: clickedCount, label: notices.clickedCount, css_class: 'graphable column-clickedCount' } + - { property: likedCount, label: notices.likedCount, css_class: 'graphable column-likedCount' } + - { property: dislikedCount, label: notices.dislikedCount, css_class: 'graphable column-dislikedCount' } + - { property: dismissedCount, label: notices.dismissedCount, css_class: 'graphable column-dismissedCount' } - { property: locale, label: contributors.locale } - { property: expires, label: notices.expires, css_class: 'column-expires' } - { property: created, label: notices.created, css_class: 'column-created' } diff --git a/config/packages/messenger.yaml b/config/packages/messenger.yaml new file mode 100644 index 00000000..6b7319ce --- /dev/null +++ b/config/packages/messenger.yaml @@ -0,0 +1,14 @@ +framework: + messenger: + # Uncomment this (and the failed transport below) to send failed messages to this transport for later handling. + # failure_transport: failed + + transports: + # https://symfony.com/doc/current/messenger.html#transport-configuration + # async: '%env(MESSENGER_TRANSPORT_DSN)%' + # failed: 'doctrine://default?queue_name=failed' + # sync: 'sync://' + + routing: + # Route your messages to the transports + # 'App\Message\YourMessage': async diff --git a/migrations/Version20210704210627.php b/migrations/Version20210704210627.php new file mode 100644 index 00000000..38dbfce4 --- /dev/null +++ b/migrations/Version20210704210627.php @@ -0,0 +1,54 @@ +addSql('ALTER TABLE notice + ADD COLUMN badged_count int DEFAULT 0 NOT NULL, + ADD COLUMN displayed_count int DEFAULT 0 NOT NULL, + ADD COLUMN unfolded_count int DEFAULT 0 NOT NULL, + ADD COLUMN clicked_count int DEFAULT 0 NOT NULL, + ADD COLUMN liked_count int DEFAULT 0 NOT NULL, + ADD COLUMN disliked_count int DEFAULT 0 NOT NULL, + ADD COLUMN dismissed_count int DEFAULT 0 NOT NULL; + '); + + $this->addSql('CREATE INDEX rating_notice_type_index ON rating (notice_id, type);'); + + $this->addSql('UPDATE notice n + SET n.badged_count = (SELECT COUNT(*) FROM rating r WHERE r.notice_id = n.id AND r.type = \'badge\'), + n.displayed_count = (SELECT COUNT(*) FROM rating r WHERE r.notice_id = n.id AND r.type = \'display\'), + n.unfolded_count = (SELECT COUNT(*) FROM rating r WHERE r.notice_id = n.id AND r.type = \'unfold\'), + n.clicked_count = (SELECT COUNT(*) FROM rating r WHERE r.notice_id = n.id AND r.type = \'outbound-click\'), + n.liked_count = (SELECT COUNT(*) FROM rating r WHERE r.notice_id = n.id AND r.type = \'like\') - (SELECT COUNT(*) FROM rating r WHERE r.notice_id = n.id AND r.type = \'unlike\'), + n.disliked_count = (SELECT COUNT(*) FROM rating r WHERE r.notice_id = n.id AND r.type = \'dislike\') - (SELECT COUNT(*) FROM rating r WHERE r.notice_id = n.id AND r.type = \'undislike\'), + n.dismissed_count = (SELECT COUNT(*) FROM rating r WHERE r.notice_id = n.id AND r.type = \'dismiss\') - (SELECT COUNT(*) FROM rating r WHERE r.notice_id = n.id AND r.type = \'undismiss\'); + '); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE rating DROP INDEX rating_notice_type_index'); + + $this->addSql('ALTER TABLE notice + DROP COLUMN badged_count, + DROP COLUMN displayed_count, + DROP COLUMN unfolded_count, + DROP COLUMN clicked_count, + DROP COLUMN liked_count, + DROP COLUMN disliked_count, + DROP COLUMN dismissed_count + '); + } +} diff --git a/src/Controller/AdminApiController.php b/src/Controller/AdminApiController.php deleted file mode 100644 index c9b67bef..00000000 --- a/src/Controller/AdminApiController.php +++ /dev/null @@ -1,47 +0,0 @@ -serializer = $serializer; - - $this->repository = $repository; - } - - /** - * @Route("/matchingcontexts") - */ - public function getMatchingcontextsAction(): JsonResponse - { - $matchingContexts = $this->repository->findAllWithPrivateVisibility(); - - if ( ! $matchingContexts) { - throw new NotFoundHttpException('No matching contexts exists'); - } - - $json = $this->serializer->serialize($matchingContexts, 'json', ['groups' => ['v3:list']]); - - return new JsonResponse($json, 200, [], true); - } -} diff --git a/src/Controller/Api/V3/PostNoticeRating.http b/src/Controller/Api/V3/PostNoticeRating.http new file mode 100644 index 00000000..f386e52e --- /dev/null +++ b/src/Controller/Api/V3/PostNoticeRating.http @@ -0,0 +1,9 @@ +POST http://localhost:8088/api/v3/notices/1028/ratings +Content-Type: application/json + +{ + "ratingType": "badge" +} + + +### diff --git a/src/Controller/Api/V3/PostNoticeRatingAction.php b/src/Controller/Api/V3/PostNoticeRatingAction.php index cbcb14a0..22264412 100644 --- a/src/Controller/Api/V3/PostNoticeRatingAction.php +++ b/src/Controller/Api/V3/PostNoticeRatingAction.php @@ -5,6 +5,7 @@ namespace App\Controller\Api\V3; use App\Entity\Rating; +use App\Message\NoticeRated; use App\Repository\NoticeRepository; use App\Serializer\V3\NormalizerOptions; use Doctrine\ORM\EntityManagerInterface; @@ -14,6 +15,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException; +use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Serializer\SerializerInterface; class PostNoticeRatingAction extends BaseAction @@ -39,7 +41,7 @@ public function __construct(SerializerInterface $serializer, NoticeRepository $n * @Route("/notices/{id}/ratings") * @Method("POST") */ - public function __invoke(Request $request): JsonResponse + public function __invoke(Request $request, MessageBusInterface $bus): JsonResponse { $id = $request->get('id', null); $notice = $this->noticeRepository->getOne((int) $id); @@ -60,6 +62,8 @@ public function __invoke(Request $request): JsonResponse $this->entityManager->persist($rating); $this->entityManager->flush(); + $bus->dispatch(new NoticeRated($notice)); + return new JsonResponse('', 204, [], true); } } diff --git a/src/Entity/Notice.php b/src/Entity/Notice.php index dadf2b91..a0e51d58 100644 --- a/src/Entity/Notice.php +++ b/src/Entity/Notice.php @@ -181,6 +181,62 @@ class Notice */ private $ratings; + /** + * @var int + * + * @ORM\Column(name="badged_count", type="integer", nullable=false, options={"default"=0}) + * @Groups({"create", "read", "update"}) + */ + private $badgedCount = 0; + + /** + * @var int + * + * @ORM\Column(name="displayed_count", type="integer", nullable=false, options={"default"=0}) + * @Groups({"create", "read", "update"}) + */ + private $displayedCount = 0; + + /** + * @var int + * + * @ORM\Column(name="unfolded_count", type="integer", nullable=false, options={"default"=0}) + * @Groups({"create", "read", "update"}) + */ + private $unfoldedCount = 0; + + /** + * @var int + * + * @ORM\Column(name="clicked_count", type="integer", nullable=false, options={"default"=0}) + * @Groups({"create", "read", "update"}) + */ + private $clickedCount = 0; + + /** + * @var int + * + * @ORM\Column(name="liked_count", type="integer", nullable=false, options={"default"=0}) + * @Groups({"create", "read", "update"}) + */ + private $likedCount = 0; + + /** + * @var int + * + * @ORM\Column(name="disliked_count", type="integer", nullable=false, options={"default"=0}) + * @Groups({"create", "read", "update"}) + */ + private $dislikedCount = 0; + + /** + * @var int + * + * @ORM\Column(name="dismissed_count", type="integer", nullable=false, options={"default"=0}) + * @Groups({"create", "read", "update"}) + */ + private $dismissedCount = 0; + /** * Latest update date of the notice, serialized in the ISO8601 format. * @@ -292,6 +348,11 @@ public static function equals(self $notice): Closure }; } + public function __toString(): string + { + return sprintf('(id:%d) [%s] %s', $this->getId(), $this->getContributor(), StringHelper::truncate($this->getMessage(), 45)); + } + public function getId(): ?int { return $this->id; @@ -354,63 +415,6 @@ public function setMessage(string $message): self return $this; } - /** - * Amount of likes the Notice has received. - * - * @Groups({"read"}) - * @ApiProperty( - * readable=true, - * writable=false, - * ) - */ - public function getLikes(): int - { - return $this->getLikedRatingCount(); - } - - public function getLikedRatingCount(): int - { - return $this->getRatingBalance(Rating::LIKE, Rating::UNLIKE); - } - - protected function getRatingBalance(string $typeUp, string $typeDown): int - { - $balance = $this->getRatingCount($typeUp) - $this->getRatingCount($typeDown); - - return $balance > 0 ? $balance : 0; - } - - protected function getRatingCount(string $type): int - { - return $this->getRatings()->filter(function (Rating $rating) use ($type) { - return $rating->getType() === $type; - })->count(); - } - - public function getRatings(): ?Collection - { - return $this->ratings; - } - - /** - * Amount of dislikes the Notice has received. - * - * @Groups({"read"}) - * @ApiProperty( - * readable=true, - * writable=false, - * ) - */ - public function getDislikes(): int - { - return $this->getDislikedRatingCount(); - } - - public function getDislikedRatingCount(): int - { - return $this->getRatingBalance(Rating::DISLIKE, Rating::UNDISLIKE); - } - public function addMatchingContext(MatchingContext $matchingContext): self { $matchingContext->setNotice($this); @@ -425,11 +429,6 @@ public function removeMatchingContext(MatchingContext $matchingContext): void $this->matchingContexts->removeElement($matchingContext); } - public function __toString(): string - { - return sprintf('(id:%d) [%s] %s', $this->getId(), $this->getContributor(), StringHelper::truncate($this->getMessage(), 45)); - } - public function getContributor(): ?Contributor { return $this->contributor; @@ -442,11 +441,6 @@ public function setContributor(Contributor $contributor = null): self return $this; } - public function hasPublicVisibility(): bool - { - return $this->getVisibility() === NoticeVisibility::PUBLIC_VISIBILITY(); - } - public function getVisibility(): ?NoticeVisibility { if ( ! $this->visibility) { @@ -472,9 +466,9 @@ public function setVisibility($visibility): self return $this; } - public function isUnpublished(): bool + public function hasPublicVisibility(): bool { - return null !== $this->getExpires() && $this->isUnpublishedOnExpiration() && $this->getExpires() < new DateTime('now'); + return $this->getVisibility() === NoticeVisibility::PUBLIC_VISIBILITY(); } public function getExpires(): ?DateTimeInterface @@ -507,46 +501,121 @@ public function setNote(?string $note): void $this->note = $note; } - public function getBadgedRatingCount(): int + public function getRatings(): ?Collection + { + return $this->ratings; + } + + /** + * Amount of likes the Notice has received. + * + * @Groups({"read"}) + * @ApiProperty( + * readable=true, + * writable=false, + * ) + */ + public function getLikes(): int + { + return $this->getLikedCount(); + } + + /** + * Amount of dislikes the Notice has received. + * + * @Groups({"read"}) + * @ApiProperty( + * readable=true, + * writable=false, + * ) + */ + public function getDislikes(): int + { + return $this->getDislikedCount(); + } + + public function getBadgedCount(): int + { + return $this->badgedCount; + } + + public function setBadgedCount(int $count): self { - return $this->getRatingCount(Rating::BADGE); + $this->badgedCount = $count; + + return $this; } - public function getDisplayedRatingCount(): int + public function getDisplayedCount(): int { - return $this->getRatingCount(Rating::DISPLAY); + return $this->displayedCount; } - public function getUnfoldedRatingCount(): int + public function setDisplayedCount(int $count): self { - return $this->getRatingCount(Rating::UNFOLD); + $this->displayedCount = $count; + + return $this; } - public function getClickedRatingCount(): int + public function getUnfoldedCount(): int { - return $this->getRatingCount(Rating::OUTBOUND_CLICK); + return $this->unfoldedCount; } - public function getDismissedRatingCount(): int + public function setUnfoldedCount(int $count): self { - return $this->getRatingBalance(Rating::DISMISS, Rating::UNDISMISS); + $this->unfoldedCount = $count; + + return $this; } - public function getReportedRatingCount(): int + public function getClickedCount(): int { - return $this->getRatingCount(Rating::REPORT); + return $this->clickedCount; } - public function addRating(Rating $rating): self + public function setClickedCount(int $count): self { - $this->ratings[] = $rating; + $this->clickedCount = $count; return $this; } - public function removeRating(Rating $rating): void + public function getLikedCount(): int { - $this->ratings->removeElement($rating); + return $this->likedCount; + } + + public function setLikedCount(int $count): self + { + $this->likedCount = $count; + + return $this; + } + + public function getDislikedCount(): int + { + return $this->dislikedCount; + } + + public function setDislikedCount(int $count): self + { + $this->dislikedCount = $count; + + return $this; + } + + public function getDismissedCount(): int + { + return $this->dismissedCount; + } + + public function setDismissedCount(int $count): self + { + $this->dismissedCount = $count; + + return $this; } public function getCreated(): ?DateTime @@ -616,10 +685,10 @@ public function getExampleUrl(): ?string public function getExampleMatchingUrl(): ?string { $first = $this->getMatchingContexts() - ->filter(function (MatchingContext $mc) { - return (bool) $mc->getExampleUrl(); - }) - ->first(); + ->filter(function (MatchingContext $mc) { + return (bool) $mc->getExampleUrl(); + }) + ->first(); if ($first) { return $first->getExampleUrl(); } @@ -642,15 +711,15 @@ public function addRelayer(Contributor $contributor): self public function removeRelayer(Contributor $contributor): self { $this->relays->removeElement( - current( - array_filter( - $this->relays->toArray(), - static function (Relay $relay) use ($contributor) { - return $relay->getRelayedBy()->getId() === $contributor->getId(); - } - ) - ) - ); + current( + array_filter( + $this->relays->toArray(), + static function (Relay $relay) use ($contributor) { + return $relay->getRelayedBy()->getId() === $contributor->getId(); + } + ) + ) + ); return $this; } diff --git a/src/Message/NoticeRated.php b/src/Message/NoticeRated.php new file mode 100644 index 00000000..f1b28860 --- /dev/null +++ b/src/Message/NoticeRated.php @@ -0,0 +1,22 @@ +notice = $notice; + } + + public function getNotice() + { + return $this->notice; + } +} diff --git a/src/MessageHandler/NoticeRatedHandler.php b/src/MessageHandler/NoticeRatedHandler.php new file mode 100644 index 00000000..edda2e6f --- /dev/null +++ b/src/MessageHandler/NoticeRatedHandler.php @@ -0,0 +1,45 @@ +noticeRepository = $noticeRepository; + $this->ratingRepository = $ratingRepository; + $this->em = $em; + } + + public function __invoke(NoticeRated $noticeUpdated): void + { + $this->updateNoticeRatingsCount($noticeUpdated->getNotice()); + } + + protected function updateNoticeRatingsCount(Notice $notice): void + { + $notice + ->setBadgedCount($this->ratingRepository->getNoticeRatingsCountForType($notice, Rating::BADGE)) + ->setDisplayedCount($this->ratingRepository->getNoticeRatingsCountForType($notice, Rating::DISPLAY)) + ->setUnfoldedCount($this->ratingRepository->getNoticeRatingsCountForType($notice, Rating::UNFOLD)) + ->setClickedCount($this->ratingRepository->getNoticeRatingsCountForType($notice, Rating::OUTBOUND_CLICK)) + ->setLikedCount($this->ratingRepository->getNoticeRatingsCountForType($notice, Rating::LIKE, Rating::UNLIKE)) + ->setDislikedCount($this->ratingRepository->getNoticeRatingsCountForType($notice, Rating::DISLIKE, Rating::UNDISLIKE)) + ->setDismissedCount($this->ratingRepository->getNoticeRatingsCountForType($notice, Rating::DISMISS, Rating::UNDISMISS)); + $this->em->flush(); + } +} diff --git a/src/Repository/RatingRepository.php b/src/Repository/RatingRepository.php index 39990bb3..a5750a5b 100644 --- a/src/Repository/RatingRepository.php +++ b/src/Repository/RatingRepository.php @@ -38,6 +38,21 @@ public function __construct(ManagerRegistry $registry, DateTimeImmutable $dateTi $this->to = $dateTime->today(); } + public function getNoticeRatingsCountForType(Notice $notice, string $ratingType, ?string $ratingUndoType = null): int + { + $count = $this->count([ + 'notice' => $notice, + 'type' => $ratingType, + ]); + + $undoCount = $ratingUndoType ? $this->count([ + 'notice' => $notice, + 'type' => $ratingUndoType, + ]) : 0; + + return $count - $undoCount; + } + /** * @param string[] $types * diff --git a/src/Serializer/V3/NoticeNormalizer.php b/src/Serializer/V3/NoticeNormalizer.php index bb8d0d10..c2edd1b6 100644 --- a/src/Serializer/V3/NoticeNormalizer.php +++ b/src/Serializer/V3/NoticeNormalizer.php @@ -82,8 +82,8 @@ public function normalize($notice, $format = null, array $context = []): array 'exampleMatchingUrl' => $notice->getExampleMatchingUrl(), 'screenshot' => $this->getImageAbsoluteUrl($notice, 'screenshotFile'), 'ratings' => [ - 'likes' => $notice->getLikedRatingCount(), - 'dislikes' => $notice->getDislikedRatingCount(), + 'likes' => $notice->getLikedCount(), + 'dislikes' => $notice->getDislikedCount(), ], 'created' => self::formatDateTime($notice->getCreated()), 'modified' => self::formatDateTime($notice->getUpdated()), diff --git a/symfony.lock b/symfony.lock index 85f7c527..55d1a06b 100644 --- a/symfony.lock +++ b/symfony.lock @@ -596,6 +596,18 @@ "ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f" } }, + "symfony/messenger": { + "version": "4.3", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "master", + "version": "4.3", + "ref": "e9a414b113ceadbf4e52abe37bf8f1b443f06ccb" + }, + "files": [ + "config/packages/messenger.yaml" + ] + }, "symfony/mime": { "version": "v4.4.15" }, diff --git a/translations/messages.fr.yml b/translations/messages.fr.yml index 56b935ac..0107cf52 100644 --- a/translations/messages.fr.yml +++ b/translations/messages.fr.yml @@ -42,20 +42,20 @@ title: notices: id: id contributor: Contributeur - relayers: Relayeurs + relayers: 🔃 message: Message visibility: Visibilité note: Note privée screenshot: Capture d’écran screenshot.help: "612x480 pixels, JPG, PNG" - matchingContexts: Ensemble de pages cibles - badgedRatingCount: Badge - displayedRatingCount: Aperçu - unfoldedRatingCount: Détail - clickedRatingCount: Hyperlien - likedRatingCount: Aimé - dislikedRatingCount: Déplu - dismissedRatingCount: Supprimé + matchingContexts: 🎯 + badgedCount: 🟢 + displayedCount: 🗨️ + unfoldedCount: 👁 + clickedCount: 🔗 + likedCount: 👍 + dislikedCount: 👎 + dismissedCount: 🗑️ created: Crée updated: Modifiée expires: Expire