From 32da06dc98312371d230fd70f7c464b5b931d4f6 Mon Sep 17 00:00:00 2001 From: Ambroise Maupate Date: Fri, 7 Jun 2024 18:02:45 +0200 Subject: [PATCH] perf: Do not execute `RealmSerializationGroupNormalizer` if there are no realms setup with a serialization_group. --- lib/RoadizCoreBundle/src/Entity/Realm.php | 2 +- .../src/Realm/RealmResolver.php | 32 +++++++++++++++++++ .../src/Realm/RealmResolverInterface.php | 13 ++++++++ .../src/Repository/RealmRepository.php | 9 ++++++ .../RealmSerializationGroupNormalizer.php | 21 ++++++++---- 5 files changed, 69 insertions(+), 8 deletions(-) diff --git a/lib/RoadizCoreBundle/src/Entity/Realm.php b/lib/RoadizCoreBundle/src/Entity/Realm.php index 69ba3bce..9cf68e49 100644 --- a/lib/RoadizCoreBundle/src/Entity/Realm.php +++ b/lib/RoadizCoreBundle/src/Entity/Realm.php @@ -150,7 +150,7 @@ public function setSerializationGroup(?string $serializationGroup): Realm { $this->serializationGroup = null !== $serializationGroup ? (new AsciiSlugger())->slug($serializationGroup, '_')->lower()->toString() : - (new AsciiSlugger())->slug($this->getName(), '_')->lower()->toString(); + null; return $this; } diff --git a/lib/RoadizCoreBundle/src/Realm/RealmResolver.php b/lib/RoadizCoreBundle/src/Realm/RealmResolver.php index 5fb20cdf..d900db6b 100644 --- a/lib/RoadizCoreBundle/src/Realm/RealmResolver.php +++ b/lib/RoadizCoreBundle/src/Realm/RealmResolver.php @@ -31,6 +31,14 @@ public function getRealms(?Node $node): array return $this->managerRegistry->getRepository(Realm::class)->findByNode($node); } + public function getRealmsWithSerializationGroup(?Node $node): array + { + if (null === $node) { + return []; + } + return $this->managerRegistry->getRepository(Realm::class)->findByNodeWithSerializationGroup($node); + } + public function isGranted(RealmInterface $realm): bool { return $this->security->isGranted(RealmVoter::READ, $realm); @@ -76,4 +84,28 @@ public function getDeniedRealms(): array } return $cacheItem->get(); } + + public function hasRealms(): bool + { + $cacheItem = $this->cache->getItem('app_has_realms'); + if (!$cacheItem->isHit()) { + $hasRealms = $this->managerRegistry->getRepository(Realm::class)->countBy([]) > 0; + $cacheItem->set($hasRealms); + $cacheItem->expiresAfter(new \DateInterval('PT2H')); + $this->cache->save($cacheItem); + } + return $cacheItem->get(); + } + + public function hasRealmsWithSerializationGroup(): bool + { + $cacheItem = $this->cache->getItem('app_has_realms_with_serialization_group'); + if (!$cacheItem->isHit()) { + $hasRealms = $this->managerRegistry->getRepository(Realm::class)->countWithSerializationGroup() > 0; + $cacheItem->set($hasRealms); + $cacheItem->expiresAfter(new \DateInterval('PT2H')); + $this->cache->save($cacheItem); + } + return $cacheItem->get(); + } } diff --git a/lib/RoadizCoreBundle/src/Realm/RealmResolverInterface.php b/lib/RoadizCoreBundle/src/Realm/RealmResolverInterface.php index fd0ca8cb..0124db98 100644 --- a/lib/RoadizCoreBundle/src/Realm/RealmResolverInterface.php +++ b/lib/RoadizCoreBundle/src/Realm/RealmResolverInterface.php @@ -10,11 +10,24 @@ interface RealmResolverInterface { + /** + * @return bool Does current application has realms? + */ + public function hasRealms(): bool; + /** + * @return bool Does current application has realms with serialization groups? + */ + public function hasRealmsWithSerializationGroup(): bool; /** * @param Node|null $node * @return RealmInterface[] */ public function getRealms(?Node $node): array; + /** + * @param Node|null $node + * @return RealmInterface[] + */ + public function getRealmsWithSerializationGroup(?Node $node): array; public function isGranted(RealmInterface $realm): bool; /** diff --git a/lib/RoadizCoreBundle/src/Repository/RealmRepository.php b/lib/RoadizCoreBundle/src/Repository/RealmRepository.php index 21b4c507..25382cba 100644 --- a/lib/RoadizCoreBundle/src/Repository/RealmRepository.php +++ b/lib/RoadizCoreBundle/src/Repository/RealmRepository.php @@ -41,4 +41,13 @@ public function findByNodeAndBehaviour(Node $node, string $realmBehaviour): arra return $qb->getQuery()->getResult(); } + + public function countWithSerializationGroup(): int + { + $qb = $this->createQueryBuilder('r'); + $qb->select($qb->expr()->count('r')) + ->andWhere($qb->expr()->isNotNull('r.serializationGroup')); + + return intval($qb->getQuery()->getSingleScalarResult()); + } } diff --git a/lib/RoadizCoreBundle/src/Serializer/Normalizer/RealmSerializationGroupNormalizer.php b/lib/RoadizCoreBundle/src/Serializer/Normalizer/RealmSerializationGroupNormalizer.php index 8c7ea103..a470c7eb 100644 --- a/lib/RoadizCoreBundle/src/Serializer/Normalizer/RealmSerializationGroupNormalizer.php +++ b/lib/RoadizCoreBundle/src/Serializer/Normalizer/RealmSerializationGroupNormalizer.php @@ -4,14 +4,15 @@ namespace RZ\Roadiz\CoreBundle\Serializer\Normalizer; -use Doctrine\Persistence\ManagerRegistry; use RZ\Roadiz\CoreBundle\Entity\NodesSources; -use RZ\Roadiz\CoreBundle\Entity\Realm; +use RZ\Roadiz\CoreBundle\Model\RealmInterface; +use RZ\Roadiz\CoreBundle\Realm\RealmResolver; use RZ\Roadiz\CoreBundle\Security\Authorization\Voter\RealmVoter; use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +use Symfony\Component\Stopwatch\Stopwatch; final class RealmSerializationGroupNormalizer implements NormalizerInterface, NormalizerAwareInterface { @@ -21,7 +22,8 @@ final class RealmSerializationGroupNormalizer implements NormalizerInterface, No public function __construct( private readonly Security $security, - private readonly ManagerRegistry $managerRegistry + private readonly RealmResolver $realmResolver, + private readonly Stopwatch $stopwatch ) { } @@ -30,12 +32,15 @@ public function __construct( */ public function supportsNormalization(mixed $data, string $format = null, array $context = []): bool { + if (!($data instanceof NodesSources)) { + return false; + } // Make sure we're not called twice if (isset($context[self::ALREADY_CALLED])) { return false; } - return $data instanceof NodesSources; + return $this->realmResolver->hasRealmsWithSerializationGroup(); } public function getSupportedTypes(?string $format): array @@ -51,6 +56,7 @@ public function getSupportedTypes(?string $format): array */ public function normalize(mixed $object, ?string $format = null, array $context = []): mixed { + $this->stopwatch->start('realm-serialization-group-normalizer', 'serializer'); $realms = $this->getAuthorizedRealmsForObject($object); foreach ($realms as $realm) { @@ -60,18 +66,19 @@ public function normalize(mixed $object, ?string $format = null, array $context } $context[self::ALREADY_CALLED] = true; + $this->stopwatch->stop('realm-serialization-group-normalizer'); return $this->normalizer->normalize($object, $format, $context); } /** - * @return Realm[] + * @return RealmInterface[] */ private function getAuthorizedRealmsForObject(NodesSources $object): array { - $realms = $this->managerRegistry->getRepository(Realm::class)->findByNode($object->getNode()); + $realms = $this->realmResolver->getRealmsWithSerializationGroup($object->getNode()); - return array_filter($realms, function (Realm $realm) { + return array_filter($realms, function (RealmInterface $realm) { return $this->security->isGranted(RealmVoter::READ, $realm); }); }