From 9a358363981030077edd4e51a715794d68b40c1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bar=C3=A1=C5=A1ek?= Date: Mon, 15 Nov 2021 21:58:32 +0100 Subject: [PATCH] Move DB logic to repositories and use EntityManagerInterface. --- .../Entity/AnnouncementRepository.php | 29 +++++++ src/Api/CmsDashboardEndpoint.php | 23 ++---- src/Api/CmsEndpoint.php | 20 ++--- src/Api/CmsInstallEndpoint.php | 4 +- src/Context.php | 6 +- src/MiddleWare/TemplateRenderer.php | 16 ++-- src/Search/CmsGlobalSearchEndpoint.php | 4 +- src/Settings/DoctrineStorage.php | 77 ++++-------------- src/Settings/Entity/OptionRepository.php | 78 +++++++++++++++++++ src/Settings/Settings.php | 20 +++-- .../UserResetPasswordRequestRepository.php | 19 +++++ 11 files changed, 177 insertions(+), 119 deletions(-) diff --git a/src/Announcement/Entity/AnnouncementRepository.php b/src/Announcement/Entity/AnnouncementRepository.php index 6d68b9f..8991cb3 100644 --- a/src/Announcement/Entity/AnnouncementRepository.php +++ b/src/Announcement/Entity/AnnouncementRepository.php @@ -9,4 +9,33 @@ final class AnnouncementRepository extends EntityRepository { + /** + * @return array + */ + public function getFeed(): array + { + /** @phpstan-ignore-next-line */ + return $this->createQueryBuilder('topic') + ->select('PARTIAL topic.{id, pinned, message, showSince}') + ->addSelect('PARTIAL user.{id, username}') + ->leftJoin('topic.user', 'user') + ->where('topic.parent IS NULL') + ->andWhere('topic.active = TRUE') + ->andWhere('topic.showSince >= :now') + ->andWhere('topic.showUntil < :now OR topic.showUntil IS NULL') + ->setParameter('now', date('Y-m-d') . ' 00:00:00') + ->orderBy('topic.pinned', 'DESC') + ->addOrderBy('topic.showSince', 'DESC') + ->getQuery() + ->getArrayResult(); + } } diff --git a/src/Api/CmsDashboardEndpoint.php b/src/Api/CmsDashboardEndpoint.php index 1fb0ae9..39f5406 100644 --- a/src/Api/CmsDashboardEndpoint.php +++ b/src/Api/CmsDashboardEndpoint.php @@ -6,16 +6,17 @@ use Baraja\Cms\Announcement\Entity\Announcement; +use Baraja\Cms\Announcement\Entity\AnnouncementRepository; use Baraja\Cms\User\Entity\User; use Baraja\Cms\User\UserManager; -use Baraja\Doctrine\EntityManager; use Baraja\Localization\Localization; use Baraja\StructuredApi\BaseEndpoint; +use Doctrine\ORM\EntityManagerInterface; final class CmsDashboardEndpoint extends BaseEndpoint { public function __construct( - private EntityManager $entityManager, + private EntityManagerInterface $entityManager, private UserManager $userManager, private Localization $localization, ) { @@ -24,22 +25,12 @@ public function __construct( public function actionFeed(): void { + /** @var AnnouncementRepository $repository */ + $repository = $this->entityManager->getRepository(AnnouncementRepository::class); + $this->sendJson( [ - 'feed' => $this->entityManager->getRepository(Announcement::class) - ->createQueryBuilder('topic') - ->select('PARTIAL topic.{id, pinned, message, showSince}') - ->addSelect('PARTIAL user.{id, username}') - ->leftJoin('topic.user', 'user') - ->where('topic.parent IS NULL') - ->andWhere('topic.active = TRUE') - ->andWhere('topic.showSince >= :now') - ->andWhere('topic.showUntil < :now OR topic.showUntil IS NULL') - ->setParameter('now', date('Y-m-d') . ' 00:00:00') - ->orderBy('topic.pinned', 'DESC') - ->addOrderBy('topic.showSince', 'DESC') - ->getQuery() - ->getArrayResult(), + 'feed' => $repository->getFeed(), ], ); } diff --git a/src/Api/CmsEndpoint.php b/src/Api/CmsEndpoint.php index ad380d8..2f2fbd4 100644 --- a/src/Api/CmsEndpoint.php +++ b/src/Api/CmsEndpoint.php @@ -14,12 +14,13 @@ use Baraja\Cms\User\Entity\CmsUser; use Baraja\Cms\User\Entity\User; use Baraja\Cms\User\Entity\UserResetPasswordRequest; +use Baraja\Cms\User\Entity\UserResetPasswordRequestRepository; use Baraja\Cms\User\UserManager; -use Baraja\Doctrine\EntityManager; use Baraja\Markdown\CommonMarkRenderer; use Baraja\StructuredApi\Attributes\PublicEndpoint; use Baraja\StructuredApi\BaseEndpoint; use Baraja\Url\Url; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\NonUniqueResultException; use Doctrine\ORM\NoResultException; use Nette\Security\AuthenticationException; @@ -32,7 +33,7 @@ public function __construct( private UserManager $userManager, private CloudManager $cloudManager, private Settings $settings, - private EntityManager $entityManager, + private EntityManagerInterface $entityManager, private ContextAccessor $contextAccessor, private CommonMarkRenderer $commonMarkRenderer, ) { @@ -202,18 +203,11 @@ public function postReportProblem(string $locale, string $description, string $u public function postForgotPasswordSetNew(string $token, string $locale, string $password): void { - try { - /** @var UserResetPasswordRequest $request */ - $request = $this->entityManager->getRepository(UserResetPasswordRequest::class) - ->createQueryBuilder('resetRequest') - ->select('resetRequest, user') - ->leftJoin('resetRequest.user', 'user') - ->where('resetRequest.token = :token') - ->setParameter('token', $token) - ->setMaxResults(1) - ->getQuery() - ->getSingleResult(); + /** @var UserResetPasswordRequestRepository $repository */ + $repository = $this->entityManager->getRepository(UserResetPasswordRequestRepository::class); + try { + $request = $repository->getByToken($token); if ($request->isExpired() === true) { $this->sendError('Token has been expired.'); } diff --git a/src/Api/CmsInstallEndpoint.php b/src/Api/CmsInstallEndpoint.php index af10091..984aedd 100644 --- a/src/Api/CmsInstallEndpoint.php +++ b/src/Api/CmsInstallEndpoint.php @@ -8,12 +8,12 @@ use Baraja\BarajaCloud\CloudManager; use Baraja\Cms\Settings; use Baraja\Cms\User\Entity\User; -use Baraja\Doctrine\EntityManager; use Baraja\DynamicConfiguration\Configuration; use Baraja\DynamicConfiguration\ConfigurationSection; use Baraja\StructuredApi\Attributes\PublicEndpoint; use Baraja\StructuredApi\BaseEndpoint; use Baraja\Url\Url; +use Doctrine\ORM\EntityManagerInterface; use Nette\Utils\Strings; use Nette\Utils\Validators; @@ -24,7 +24,7 @@ final class CmsInstallEndpoint extends BaseEndpoint public function __construct( - private EntityManager $entityManager, + private EntityManagerInterface $entityManager, private CloudManager $cloudManager, private Settings $settings, Configuration $configuration, diff --git a/src/Context.php b/src/Context.php index 52fd292..1510475 100644 --- a/src/Context.php +++ b/src/Context.php @@ -14,7 +14,6 @@ use Baraja\Cms\User\UserManagerAccessor; use Baraja\Cms\User\UserMetaManager; use Baraja\Doctrine\Cache\FilesystemCache; -use Baraja\Doctrine\EntityManager; use Baraja\DynamicConfiguration\Configuration; use Baraja\DynamicConfiguration\ConfigurationSection; use Baraja\Localization\Localization; @@ -23,6 +22,7 @@ use Baraja\Plugin\PluginManager; use DeviceDetector\Cache\DoctrineBridge; use DeviceDetector\DeviceDetector; +use Doctrine\ORM\EntityManagerInterface; use Nette\Http\Request; use Nette\Http\Response; use Nette\Security\User; @@ -41,7 +41,7 @@ final class Context implements ContainerInterface public function __construct( private Request $request, private Response $response, - private EntityManager $entityManager, + private EntityManagerInterface $entityManager, private Settings $settings, private User $user, private TranslatorFilter $translatorFilter, @@ -141,7 +141,7 @@ public function getResponse(): Response } - public function getEntityManager(): EntityManager + public function getEntityManager(): EntityManagerInterface { return $this->entityManager; } diff --git a/src/MiddleWare/TemplateRenderer.php b/src/MiddleWare/TemplateRenderer.php index 3f56a3f..ea2b13b 100644 --- a/src/MiddleWare/TemplateRenderer.php +++ b/src/MiddleWare/TemplateRenderer.php @@ -15,6 +15,7 @@ use Baraja\Cms\Settings; use Baraja\Cms\User\Entity\CmsUser; use Baraja\Cms\User\Entity\UserResetPasswordRequest; +use Baraja\Cms\User\Entity\UserResetPasswordRequestRepository; use Baraja\Plugin\BasePlugin; use Baraja\Plugin\CmsPluginPanel; use Baraja\Plugin\Component\PluginComponent; @@ -151,18 +152,11 @@ public function renderLoginOtpAuthTemplate(string $locale): string public function renderResetPasswordTemplate(string $token, string $locale): string { - try { - /** @var UserResetPasswordRequest $request */ - $request = $this->context->getEntityManager()->getRepository(UserResetPasswordRequest::class) - ->createQueryBuilder('resetRequest') - ->select('resetRequest, PARTIAL user.{id, username}') - ->leftJoin('resetRequest.user', 'user') - ->where('resetRequest.token = :token') - ->setParameter('token', $token) - ->setMaxResults(1) - ->getQuery() - ->getSingleResult(); + /** @var UserResetPasswordRequestRepository $repository */ + $repository = $this->context->getEntityManager()->getRepository(UserResetPasswordRequestRepository::class); + try { + $request = $repository->getByToken($token); if ($request->isExpired() === true) { throw new \InvalidArgumentException('Token has been expired.'); } diff --git a/src/Search/CmsGlobalSearchEndpoint.php b/src/Search/CmsGlobalSearchEndpoint.php index 0de1596..49d220c 100644 --- a/src/Search/CmsGlobalSearchEndpoint.php +++ b/src/Search/CmsGlobalSearchEndpoint.php @@ -6,16 +6,16 @@ use Baraja\Cms\LinkGenerator; -use Baraja\Doctrine\EntityManager; use Baraja\Plugin\PluginManager; use Baraja\Search\SearchAccessor; use Baraja\StructuredApi\BaseEndpoint; +use Doctrine\ORM\EntityManagerInterface; final class CmsGlobalSearchEndpoint extends BaseEndpoint { public function __construct( private PluginManager $pluginManager, - private EntityManager $entityManager, + private EntityManagerInterface $entityManager, private ?SearchAccessor $searchAccessor = null, ) { } diff --git a/src/Settings/DoctrineStorage.php b/src/Settings/DoctrineStorage.php index 9bf8444..3c5f68c 100644 --- a/src/Settings/DoctrineStorage.php +++ b/src/Settings/DoctrineStorage.php @@ -5,9 +5,8 @@ namespace Baraja\DoctrineConfiguration; -use Baraja\Doctrine\EntityManager; use Baraja\DynamicConfiguration\Storage; -use Doctrine\ORM\Mapping\MappingException; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\NonUniqueResultException; use Doctrine\ORM\NoResultException; @@ -16,9 +15,15 @@ */ final class DoctrineStorage implements Storage { + private OptionRepository $optionRepository; + + public function __construct( - private EntityManager $entityManager, + private EntityManagerInterface $entityManager, ) { + /** @var OptionRepository $optionRepository */ + $optionRepository = $entityManager->getRepository(OptionRepository::class); + $this->optionRepository = $optionRepository; } @@ -27,15 +32,8 @@ public function __construct( */ public function loadAll(): array { - /** @var array $data */ - $data = $this->entityManager->getRepository(Option::class) - ->createQueryBuilder('option') - ->select('PARTIAL option.{id, key, value}') - ->getQuery() - ->getArrayResult(); - $return = []; - foreach ($data as $item) { + foreach ($this->optionRepository->loadAll() as $item) { $return[$item['key']] = $item['value']; } @@ -45,19 +43,7 @@ public function loadAll(): array public function get(string $key): ?string { - /** @var array $option */ - $option = $this->entityManager->getRepository(Option::class) - ->createQueryBuilder('option') - ->select('PARTIAL option.{id, value}') - ->where('option.key = :key') - ->setParameter('key', $key) - ->setMaxResults(1) - ->getQuery() - ->getArrayResult(); - - return isset($option[0]['value']) === true - ? $option[0]['value'] - : null; + return $this->optionRepository->getAsArray($key); } @@ -71,17 +57,8 @@ public function getMultiple(array $keys): array return []; } - /** @var array $options */ - $options = $this->entityManager->getRepository(Option::class) - ->createQueryBuilder('option') - ->select('PARTIAL option.{id, key, value}') - ->where('option.key IN (:keys)') - ->setParameter('keys', $keys) - ->getQuery() - ->getArrayResult(); - $return = []; - foreach ($options as $option) { + foreach ($this->optionRepository->getMultiple($keys) as $option) { $return[$option['key']] = $option['value']; } @@ -92,7 +69,7 @@ public function getMultiple(array $keys): array public function save(string $key, string $value): void { try { - $option = $this->getOptionEntity($key); + $option = $this->optionRepository->getAsEntity($key); } catch (NoResultException | NonUniqueResultException) { $option = new Option($key, $value); $this->entityManager->persist($option); @@ -105,35 +82,13 @@ public function save(string $key, string $value): void public function remove(string $key): void { try { - $option = $this->getOptionEntity($key); + $option = $this->optionRepository->getAsEntity($key); } catch (NoResultException | NonUniqueResultException) { return; } - try { - $this->entityManager->remove($option); - $this->entityManager->flush(); - $this->entityManager->clear($option); - } catch (MappingException $e) { - throw new \RuntimeException($e->getMessage(), 500, $e); - } - } - - - /** - * @throws NoResultException|NonUniqueResultException - */ - private function getOptionEntity(string $key): Option - { - $option = $this->entityManager->getRepository(Option::class) - ->createQueryBuilder('option') - ->where('option.key = :key') - ->setParameter('key', $key) - ->setMaxResults(1) - ->getQuery() - ->getSingleResult(); - assert($option instanceof Option); - - return $option; + $this->entityManager->remove($option); + $this->entityManager->flush(); + $this->entityManager->clear($option::class); } } diff --git a/src/Settings/Entity/OptionRepository.php b/src/Settings/Entity/OptionRepository.php index dad878f..d3d5b3e 100644 --- a/src/Settings/Entity/OptionRepository.php +++ b/src/Settings/Entity/OptionRepository.php @@ -6,7 +6,85 @@ use Doctrine\ORM\EntityRepository; +use Doctrine\ORM\NonUniqueResultException; +use Doctrine\ORM\NoResultException; final class OptionRepository extends EntityRepository { + /** + * @return array + */ + public function loadAll(): array + { + /** @var array $data */ + $data = $this->createQueryBuilder('option') + ->select('PARTIAL option.{id, key, value}') + ->getQuery() + ->getArrayResult(); + + return $data; + } + + + /** + * @throws NoResultException|NonUniqueResultException + */ + public function getAsEntity(string $key): Option + { + $option = $this->createQueryBuilder('option') + ->where('option.key = :key') + ->setParameter('key', $key) + ->setMaxResults(1) + ->getQuery() + ->getSingleResult(); + assert($option instanceof Option); + + return $option; + } + + + public function getAsArray(string $key): ?string + { + /** @var array $option */ + $option = $this->createQueryBuilder('option') + ->select('PARTIAL option.{id, value}') + ->where('option.key = :key') + ->setParameter('key', $key) + ->setMaxResults(1) + ->getQuery() + ->getArrayResult(); + + return isset($option[0]['value']) === true + ? $option[0]['value'] + : null; + } + + + /** + * @param array $keys + * @return array + */ + public function getMultiple(array $keys): array + { + /** @var array $options */ + $options = $this->createQueryBuilder('option') + ->select('PARTIAL option.{id, key, value}') + ->where('option.key IN (:keys)') + ->setParameter('keys', $keys) + ->getQuery() + ->getArrayResult(); + + return $options; + } + + + public function isOptionExist(): bool + { + $count = $this->createQueryBuilder('option') + ->select('COUNT(option.id)') + ->getQuery() + ->getSingleScalarResult(); + + return is_numeric($count) && $count > 0; + } } diff --git a/src/Settings/Settings.php b/src/Settings/Settings.php index 642d906..13c496c 100644 --- a/src/Settings/Settings.php +++ b/src/Settings/Settings.php @@ -8,14 +8,13 @@ use Baraja\BarajaCloud\CloudManager; use Baraja\Cms\Settings\SystemInfo; use Baraja\Cms\User\UserManagerAccessor; -use Baraja\Doctrine\EntityManager; -use Baraja\DoctrineConfiguration\Option; +use Baraja\DoctrineConfiguration\OptionRepository; use Baraja\DynamicConfiguration\Configuration; use Baraja\DynamicConfiguration\ConfigurationSection; use Baraja\Localization\Localization; +use Doctrine\ORM\EntityManagerInterface; use Nette\Caching\Cache; use Nette\Caching\Storage; -use Nette\Utils\Validators; final class Settings { @@ -25,7 +24,7 @@ final class Settings public function __construct( - private EntityManager $entityManager, + private EntityManagerInterface $entityManager, private Localization $localization, private CloudManager $cloudManager, private UserManagerAccessor $userManager, @@ -92,14 +91,10 @@ public function isDatabaseConnectionOk(): bool return true; } - $status = Validators::isNumericInt( - $this->entityManager->getRepository(Option::class) - ->createQueryBuilder('option') - ->select('COUNT(option.id)') - ->getQuery() - ->getSingleScalarResult(), - ); + /** @var OptionRepository $optionRepository */ + $optionRepository = $this->entityManager->getRepository(OptionRepository::class); + $status = $optionRepository->isOptionExist(); if ($status === true) { $this->cache->save('database-connection', true); } @@ -142,6 +137,9 @@ public function isBasicConfigurationOk(): bool } + /** + * @deprecated since 2021-11-15, in future it will be implemented without cache. + */ public function cleanCache(): void { $this->cache->clean([Cache::ALL => true]); diff --git a/src/User/Entity/UserResetPasswordRequestRepository.php b/src/User/Entity/UserResetPasswordRequestRepository.php index e246e3c..5ce4380 100644 --- a/src/User/Entity/UserResetPasswordRequestRepository.php +++ b/src/User/Entity/UserResetPasswordRequestRepository.php @@ -6,7 +6,26 @@ use Doctrine\ORM\EntityRepository; +use Doctrine\ORM\NonUniqueResultException; +use Doctrine\ORM\NoResultException; final class UserResetPasswordRequestRepository extends EntityRepository { + /** + * @throws NoResultException|NonUniqueResultException + */ + public function getByToken(string $token): UserResetPasswordRequest + { + /** @var UserResetPasswordRequest $request */ + $request = $this->createQueryBuilder('resetRequest') + ->select('resetRequest, user') + ->leftJoin('resetRequest.user', 'user') + ->where('resetRequest.token = :token') + ->setParameter('token', $token) + ->setMaxResults(1) + ->getQuery() + ->getSingleResult(); + + return $request; + } }