MontealegreLuis/php-testing-tools

View on GitHub
ewallet/src/Adapters/Doctrine/Application/Messaging/MessageTrackerRepository.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php declare(strict_types=1);
/**
 * PHP version 7.4
 *
 * This source file is subject to the license that is bundled with this package in the file LICENSE.
 */

namespace Adapters\Doctrine\Application\Messaging;

use Adapters\Doctrine\Application\DataStorage\Repository;
use Application\Messaging\EmptyExchange;
use Application\Messaging\InvalidPublishedMessageToTrack;
use Application\Messaging\MessageTracker;
use Application\Messaging\PublishedMessage;
use Doctrine\ORM\NonUniqueResultException;
use Doctrine\ORM\NoResultException;
use Doctrine\ORM\ORMException;

final class MessageTrackerRepository extends Repository implements MessageTracker
{
    /**
     * @throws NonUniqueResultException
     * @throws NoResultException
     */
    public function hasPublishedMessages(string $exchangeName): bool
    {
        $builder = $this->manager->createQueryBuilder();
        $builder
            ->select('COUNT(p)')
            ->from(PublishedMessage::class, 'p')
            ->where('p.exchangeName = :exchangeName')
            ->setParameter('exchangeName', $exchangeName)
        ;

        return $builder->getQuery()->getSingleScalarResult() > 0;
    }

    /**
     * @throws EmptyExchange If no message has been published to this exchange
     * @throws NonUniqueResultException
     */
    public function mostRecentPublishedMessage(string $exchangeName): PublishedMessage
    {
        $builder = $this->manager->createQueryBuilder();
        $builder
            ->select('p')
            ->from(PublishedMessage::class, 'p')
            ->where('p.exchangeName = :exchangeName')
            ->setParameter('exchangeName', $exchangeName);

        $publishedMessage = $builder->getQuery()->getOneOrNullResult();
        if ($publishedMessage === null) {
            throw new EmptyExchange("$exchangeName has no published messages");
        }
        return $publishedMessage;
    }

    /**
     * @throws InvalidPublishedMessageToTrack There can only be either 0 or 1
     * entries associated with an exchange, this exception is thrown if there's
     * already a message but it is not equal to `mostRecentPublishedMessage`
     * @throws NonUniqueResultException
     * @throws ORMException
     */
    public function track(PublishedMessage $mostRecentPublishedMessage): void
    {
        $builder = $this->manager->createQueryBuilder();
        $builder
            ->select('p')
            ->from(PublishedMessage::class, 'p')
            ->where('p.exchangeName = :exchangeName')
            ->setParameter('exchangeName', $mostRecentPublishedMessage->exchangeName());

        $currentMessage = $builder->getQuery()->getOneOrNullResult();
        if ($currentMessage !== null && ! $currentMessage->equals($mostRecentPublishedMessage)) {
            throw InvalidPublishedMessageToTrack::isNotTheMostRecent($mostRecentPublishedMessage, $currentMessage);
        }

        $this->manager->persist($mostRecentPublishedMessage);
        $this->manager->flush($mostRecentPublishedMessage);
    }
}