Passed
Pull Request — master (#5)
by Alex
03:09
created
test/phpunit/Persistence/CascadeSaveServiceTest.php 1 patch
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -348,7 +348,7 @@  discard block
 block discarded – undo
348 348
         $classMetadata->expects($this->once())->method('getName')->willReturn($entityName);
349 349
         $targetMetadata->expects($this->once())->method('getName')->willReturn($mapping['targetEntity']);
350 350
 
351
-        $methodName = 'get' . ucfirst($mapping['fieldName']);
351
+        $methodName = 'get'.ucfirst($mapping['fieldName']);
352 352
 
353 353
         $errorMessage = sprintf(
354 354
             'Failed to find required entity method \'%s::%s\'. The method is required for cascade operations '
@@ -454,7 +454,7 @@  discard block
 block discarded – undo
454 454
         $classMetadata->expects($this->once())->method('getName')->willReturn($entityName);
455 455
         $targetMetadata->expects($this->once())->method('getName')->willReturn($mapping['targetEntity']);
456 456
 
457
-        $methodName = 'get' . ucfirst($mapping['fieldName']);
457
+        $methodName = 'get'.ucfirst($mapping['fieldName']);
458 458
 
459 459
         $errorMessage = sprintf(
460 460
             'The call to resolve entity of type \'%s\' from method call \'%s::%s\' failed: %s',
Please login to merge, or discard this patch.
src/AbstractEntityRepository.php 1 patch
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -1,1 +1,1 @@
 block discarded – undo
1
-<?php

declare(strict_types=1);

namespace Arp\DoctrineEntityRepository;

use Arp\DoctrineEntityRepository\Constant\EntityEventOption;
use Arp\DoctrineEntityRepository\Constant\FlushMode;
use Arp\DoctrineEntityRepository\Constant\QueryServiceOption;
use Arp\DoctrineEntityRepository\Constant\TransactionMode;
use Arp\DoctrineEntityRepository\Exception\EntityNotFoundException;
use Arp\DoctrineEntityRepository\Exception\EntityRepositoryException;
use Arp\DoctrineEntityRepository\Persistence\PersistServiceInterface;
use Arp\DoctrineEntityRepository\Query\QueryServiceInterface;
use Arp\Entity\EntityInterface;
use Psr\Log\LoggerInterface;

/**
 * @author  Alex Patterson <[email protected]>
 * @package Arp\DoctrineEntityRepository
 */
abstract class AbstractEntityRepository implements EntityRepositoryInterface
{
    /**
     * @var string
     */
    protected string $entityName;

    /**
     * @var QueryServiceInterface
     */
    protected QueryServiceInterface $queryService;

    /**
     * @var PersistServiceInterface
     */
    protected PersistServiceInterface $persistService;

    /**
     * @var LoggerInterface
     */
    protected LoggerInterface $logger;

    /**
     * @param string                  $entityName
     * @param QueryServiceInterface   $queryService
     * @param PersistServiceInterface $persistService
     * @param LoggerInterface         $logger
     */
    public function __construct(
        string $entityName,
        QueryServiceInterface $queryService,
        PersistServiceInterface $persistService,
        LoggerInterface $logger
    ) {
        $this->entityName = $entityName;
        $this->queryService = $queryService;
        $this->persistService = $persistService;
        $this->logger = $logger;
    }

    /**
     * Return the fully qualified class name of the mapped entity instance.
     *
     * @return string
     */
    public function getClassName(): string
    {
        return $this->entityName;
    }

    /**
     * Return a single entity instance matching the provided $id.
     *
     * @param string $id
     *
     * @return EntityInterface|null
     *
     * @throws EntityRepositoryException
     */
    public function find($id): ?EntityInterface
    {
        try {
            return $this->queryService->findOneById($id);
        } catch (\Throwable $e) {
            $errorMessage = sprintf('Unable to find entity of type \'%s\': %s', $this->entityName, $e->getMessage());

            $this->logger->error($errorMessage);

            throw new EntityRepositoryException($errorMessage, $e->getCode(), $e);
        }
    }

    /**
     * Return a single entity instance matching the provided $criteria.
     *
     * @param array $criteria The entity filter criteria.
     *
     * @return EntityInterface|null
     *
     * @throws EntityRepositoryException
     */
    public function findOneBy(array $criteria): ?EntityInterface
    {
        try {
            return $this->queryService->findOne($criteria);
        } catch (\Throwable $e) {
            $errorMessage = sprintf('Unable to find entity of type \'%s\': %s', $this->entityName, $e->getMessage());

            $this->logger->error($errorMessage);

            throw new EntityRepositoryException($errorMessage, $e->getCode(), $e);
        }
    }

    /**
     * Return all of the entities within the collection.
     *
     * @return EntityInterface[]
     *
     * @throws EntityRepositoryException
     */
    public function findAll(): array
    {
        return $this->findBy([]);
    }

    /**
     * Return a collection of entities that match the provided $criteria.
     *
     * @param array      $criteria
     * @param array|null $orderBy
     * @param int|null   $limit
     * @param int|null   $offset
     *
     * @return EntityInterface[]|iterable
     *
     * @throws EntityRepositoryException
     */
    public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): iterable
    {
        try {
            $options = [
                QueryServiceOption::LIMIT    => $limit,
                QueryServiceOption::OFFSET   => $offset,
                QueryServiceOption::ORDER_BY => $orderBy,
            ];

            return $this->queryService->findMany($criteria, $options);
        } catch (\Throwable $e) {
            $errorMessage = sprintf(
                'Unable to return a collection of type \'%s\': %s',
                $this->entityName,
                $e->getMessage()
            );

            $this->logger->error($errorMessage);

            throw new EntityRepositoryException($errorMessage, $e->getCode(), $e);
        }
    }

    /**
     * Save a single entity instance.
     *
     * @param EntityInterface $entity
     * @param array           $options
     *
     * @return EntityInterface
     *
     * @throws EntityRepositoryException
     */
    public function save(EntityInterface $entity, array $options = []): EntityInterface
    {
        try {
            return $this->persistService->save($entity, $options);
        } catch (\Throwable $e) {
            $errorMessage = sprintf('Unable to save entity of type \'%s\': %s', $this->entityName, $e->getMessage());

            $this->logger->error($errorMessage);

            throw new EntityRepositoryException($errorMessage, $e->getCode(), $e);
        }
    }

    /**
     * Save a collection of entities in a single transaction.
     *
     * @param iterable|EntityInterface[] $collection The collection of entities that should be saved.
     * @param array                      $options    the optional save options.
     *
     * @return iterable
     *
     * @throws EntityRepositoryException If the save cannot be completed
     */
    public function saveCollection(iterable $collection, array $options = []): iterable
    {
        $flushMode = $options[EntityEventOption::FLUSH_MODE] ?? FlushMode::ENABLED;
        $transactionMode = $options[EntityEventOption::TRANSACTION_MODE] ?? TransactionMode::ENABLED;

        try {
            if (TransactionMode::ENABLED === $transactionMode) {
                $this->persistService->beginTransaction();
            }

            $entities = [];
            $saveOptions = [
                EntityEventOption::FLUSH_MODE       => FlushMode::DISABLED,
                EntityEventOption::TRANSACTION_MODE => TransactionMode::DISABLED
            ];

            foreach ($collection as $entity) {
                $entities[] = $this->save($entity, $saveOptions);
            }

            if (FlushMode::ENABLED === $flushMode) {
                $this->persistService->flush();
            }
            if (TransactionMode::ENABLED === $transactionMode) {
                $this->persistService->commitTransaction();
            }

            return $entities;
        } catch (\Throwable $e) {
            if (TransactionMode::ENABLED === $transactionMode) {
                $this->persistService->rollbackTransaction();
            }

            $errorMessage = sprintf(
                'Unable to save collection of type \'%s\' : %s',
                $this->entityName,
                $e->getMessage()
            );

            $this->logger->error($errorMessage);

            throw new EntityRepositoryException($errorMessage, $e->getCode(), $e);
        }
    }

    /**
     * Delete an entity.
     *
     * @param EntityInterface|string $entity
     * @param array                  $options
     *
     * @return bool
     *
     * @throws EntityRepositoryException
     */
    public function delete($entity, array $options = []): bool
    {
        if (!is_string($entity) && !$entity instanceof EntityInterface) {
            throw new EntityRepositoryException(
                sprintf(
                    'The \'entity\' argument must be a \'string\' or an object of type \'%s\'; '
                    . '\'%s\' provided in \'%s\'',
                    EntityInterface::class,
                    (is_object($entity) ? get_class($entity) : gettype($entity)),
                    __METHOD__
                )
            );
        }

        if (is_string($entity)) {
            $id = $entity;
            $entity = $this->find($id);

            if (null === $entity) {
                $errorMessage = sprintf(
                    'Unable to delete entity \'%s::%s\': The entity could not be found',
                    $this->entityName,
                    $id
                );

                $this->logger->error($errorMessage);

                throw new EntityNotFoundException($errorMessage);
            }
        }

        try {
            return $this->persistService->delete($entity, $options);
        } catch (\Throwable $e) {
            $errorMessage = sprintf(
                'Unable to delete entity of type \'%s\': %s',
                $this->entityName,
                $e->getMessage()
            );

            $this->logger->error($errorMessage);

            throw new EntityRepositoryException($errorMessage, $e->getCode(), $e);
        }
    }

    /**
     * Perform a deletion of a collection of entities.
     *
     * @param iterable|EntityInterface $collection
     * @param array                    $options
     *
     * @return int
     *
     * @throws EntityRepositoryException
     */
    public function deleteCollection(iterable $collection, array $options = []): int
    {
        $flushMode = $options[EntityEventOption::FLUSH_MODE] ?? FlushMode::ENABLED;
        $transactionMode = $options[EntityEventOption::TRANSACTION_MODE] ?? TransactionMode::ENABLED;

        try {
            if (TransactionMode::ENABLED === $transactionMode) {
                $this->persistService->beginTransaction();
            }

            $deleteOptions = [
                EntityEventOption::FLUSH_MODE       => FlushMode::DISABLED,
                EntityEventOption::TRANSACTION_MODE => TransactionMode::DISABLED,
            ];

            $deleted = 0;
            foreach ($collection as $entity) {
                if (true === $this->delete($entity, $deleteOptions)) {
                    $deleted++;
                }
            }

            if (FlushMode::ENABLED === $flushMode) {
                $this->persistService->flush();
            }

            if (TransactionMode::ENABLED === $transactionMode) {
                $this->persistService->commitTransaction();
            }

            return $deleted;
        } catch (\Throwable $e) {
            if (TransactionMode::ENABLED === $transactionMode) {
                $this->persistService->rollbackTransaction();
            }

            $errorMessage = sprintf(
                'Unable to delete collection of type \'%s\' : %s',
                $this->entityName,
                $e->getMessage()
            );

            $this->logger->error($errorMessage);

            throw new EntityRepositoryException($errorMessage, $e->getCode(), $e);
        }
    }

    /**
     * @throws EntityRepositoryException
     */
    public function clear(): void
    {
        try {
            $this->persistService->clear();
        } catch (\Throwable $e) {
            $errorMessage = sprintf(
                'Unable to clear entity of type \'%s\': %s',
                $this->entityName,
                $e->getMessage()
            );

            $this->logger->error($errorMessage);

            throw new EntityRepositoryException($errorMessage, $e->getCode(), $e);
        }
    }

    /**
     * @param EntityInterface $entity
     *
     * @throws EntityRepositoryException
     */
    public function refresh(EntityInterface $entity): void
    {
        try {
            $this->persistService->refresh($entity);
        } catch (\Throwable $e) {
            $errorMessage = sprintf(
                'Unable to refresh entity of type \'%s\': %s',
                $this->entityName,
                $e->getMessage()
            );

            $this->logger->error($errorMessage);

            throw new EntityRepositoryException($errorMessage, $e->getCode(), $e);
        }
    }
}
2 1
\ No newline at end of file
2
+<?php

declare(strict_types=1); namespace Arp\DoctrineEntityRepository; use Arp\DoctrineEntityRepository\Constant\EntityEventOption; use Arp\DoctrineEntityRepository\Constant\FlushMode; use Arp\DoctrineEntityRepository\Constant\QueryServiceOption; use Arp\DoctrineEntityRepository\Constant\TransactionMode; use Arp\DoctrineEntityRepository\Exception\EntityNotFoundException; use Arp\DoctrineEntityRepository\Exception\EntityRepositoryException; use Arp\DoctrineEntityRepository\Persistence\PersistServiceInterface; use Arp\DoctrineEntityRepository\Query\QueryServiceInterface; use Arp\Entity\EntityInterface; use Psr\Log\LoggerInterface; /**
 * @author  Alex Patterson <[email protected]>
 * @package Arp\DoctrineEntityRepository
 */
abstract class AbstractEntityRepository implements EntityRepositoryInterface {
    /**
     * @var string
     */
    protected string $entityName; /**
     * @var QueryServiceInterface
     */
    protected QueryServiceInterface $queryService; /**
     * @var PersistServiceInterface
     */
    protected PersistServiceInterface $persistService; /**
     * @var LoggerInterface
     */
    protected LoggerInterface $logger; /**
     * @param string                  $entityName
     * @param QueryServiceInterface   $queryService
     * @param PersistServiceInterface $persistService
     * @param LoggerInterface         $logger
     */
    public function __construct(string $entityName, QueryServiceInterface $queryService, PersistServiceInterface $persistService, LoggerInterface $logger) {
        $this->entityName = $entityName; $this->queryService = $queryService; $this->persistService = $persistService; $this->logger = $logger; }

    /**
     * Return the fully qualified class name of the mapped entity instance.
     *
     * @return string
     */
    public function getClassName(): string
    {
        return $this->entityName; }

    /**
     * Return a single entity instance matching the provided $id.
     *
     * @param string $id
     *
     * @return EntityInterface|null
     *
     * @throws EntityRepositoryException
     */
    public function find($id): ?EntityInterface
    {
        try {
            return $this->queryService->findOneById($id); } catch (\Throwable $e) {
            $errorMessage = sprintf('Unable to find entity of type \'%s\': %s', $this->entityName, $e->getMessage()); $this->logger->error($errorMessage); throw new EntityRepositoryException($errorMessage, $e->getCode(), $e); }
    }

    /**
     * Return a single entity instance matching the provided $criteria.
     *
     * @param array $criteria The entity filter criteria.
     *
     * @return EntityInterface|null
     *
     * @throws EntityRepositoryException
     */
    public function findOneBy(array $criteria): ?EntityInterface
    {
        try {
            return $this->queryService->findOne($criteria); } catch (\Throwable $e) {
            $errorMessage = sprintf('Unable to find entity of type \'%s\': %s', $this->entityName, $e->getMessage()); $this->logger->error($errorMessage); throw new EntityRepositoryException($errorMessage, $e->getCode(), $e); }
    }

    /**
     * Return all of the entities within the collection.
     *
     * @return EntityInterface[]
     *
     * @throws EntityRepositoryException
     */
    public function findAll(): array
    {
        return $this->findBy([]); }

    /**
     * Return a collection of entities that match the provided $criteria.
     *
     * @param array      $criteria
     * @param array|null $orderBy
     * @param int|null   $limit
     * @param int|null   $offset
     *
     * @return EntityInterface[]|iterable
     *
     * @throws EntityRepositoryException
     */
    public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): iterable
    {
        try {
            $options = [QueryServiceOption::LIMIT    => $limit, QueryServiceOption::OFFSET   => $offset, QueryServiceOption::ORDER_BY => $orderBy, ]; return $this->queryService->findMany($criteria, $options); } catch (\Throwable $e) {
            $errorMessage = sprintf('Unable to return a collection of type \'%s\': %s', $this->entityName, $e->getMessage()); $this->logger->error($errorMessage); throw new EntityRepositoryException($errorMessage, $e->getCode(), $e); }
    }

    /**
     * Save a single entity instance.
     *
     * @param EntityInterface $entity
     * @param array           $options
     *
     * @return EntityInterface
     *
     * @throws EntityRepositoryException
     */
    public function save(EntityInterface $entity, array $options = []): EntityInterface
    {
        try {
            return $this->persistService->save($entity, $options); } catch (\Throwable $e) {
            $errorMessage = sprintf('Unable to save entity of type \'%s\': %s', $this->entityName, $e->getMessage()); $this->logger->error($errorMessage); throw new EntityRepositoryException($errorMessage, $e->getCode(), $e); }
    }

    /**
     * Save a collection of entities in a single transaction.
     *
     * @param iterable|EntityInterface[] $collection The collection of entities that should be saved.
     * @param array                      $options    the optional save options.
     *
     * @return iterable
     *
     * @throws EntityRepositoryException If the save cannot be completed
     */
    public function saveCollection(iterable $collection, array $options = []): iterable
    {
        $flushMode = $options[EntityEventOption::FLUSH_MODE] ?? FlushMode::ENABLED; $transactionMode = $options[EntityEventOption::TRANSACTION_MODE] ?? TransactionMode::ENABLED; try {
            if (TransactionMode::ENABLED === $transactionMode) {
                $this->persistService->beginTransaction(); }

            $entities = []; $saveOptions = [EntityEventOption::FLUSH_MODE       => FlushMode::DISABLED, EntityEventOption::TRANSACTION_MODE => TransactionMode::DISABLED]; foreach ($collection as $entity) {
                $entities[] = $this->save($entity, $saveOptions); }

            if (FlushMode::ENABLED === $flushMode) {
                $this->persistService->flush(); }
            if (TransactionMode::ENABLED === $transactionMode) {
                $this->persistService->commitTransaction(); }

            return $entities; } catch (\Throwable $e) {
            if (TransactionMode::ENABLED === $transactionMode) {
                $this->persistService->rollbackTransaction(); }

            $errorMessage = sprintf('Unable to save collection of type \'%s\' : %s', $this->entityName, $e->getMessage()); $this->logger->error($errorMessage); throw new EntityRepositoryException($errorMessage, $e->getCode(), $e); }
    }

    /**
     * Delete an entity.
     *
     * @param EntityInterface|string $entity
     * @param array                  $options
     *
     * @return bool
     *
     * @throws EntityRepositoryException
     */
    public function delete($entity, array $options = []): bool
    {
        if (!is_string($entity) && !$entity instanceof EntityInterface) {
            throw new EntityRepositoryException(sprintf('The \'entity\' argument must be a \'string\' or an object of type \'%s\'; '.'\'%s\' provided in \'%s\'', EntityInterface::class, (is_object($entity) ? get_class($entity) : gettype($entity)), __METHOD__)); }

        if (is_string($entity)) {
            $id = $entity; $entity = $this->find($id); if (null === $entity) {
                $errorMessage = sprintf('Unable to delete entity \'%s::%s\': The entity could not be found', $this->entityName, $id); $this->logger->error($errorMessage); throw new EntityNotFoundException($errorMessage); }
        }

        try {
            return $this->persistService->delete($entity, $options); } catch (\Throwable $e) {
            $errorMessage = sprintf('Unable to delete entity of type \'%s\': %s', $this->entityName, $e->getMessage()); $this->logger->error($errorMessage); throw new EntityRepositoryException($errorMessage, $e->getCode(), $e); }
    }

    /**
     * Perform a deletion of a collection of entities.
     *
     * @param iterable|EntityInterface $collection
     * @param array                    $options
     *
     * @return int
     *
     * @throws EntityRepositoryException
     */
    public function deleteCollection(iterable $collection, array $options = []): int
    {
        $flushMode = $options[EntityEventOption::FLUSH_MODE] ?? FlushMode::ENABLED; $transactionMode = $options[EntityEventOption::TRANSACTION_MODE] ?? TransactionMode::ENABLED; try {
            if (TransactionMode::ENABLED === $transactionMode) {
                $this->persistService->beginTransaction(); }

            $deleteOptions = [EntityEventOption::FLUSH_MODE       => FlushMode::DISABLED, EntityEventOption::TRANSACTION_MODE => TransactionMode::DISABLED, ]; $deleted = 0; foreach ($collection as $entity) {
                if (true === $this->delete($entity, $deleteOptions)) {
                    $deleted++; }
            }

            if (FlushMode::ENABLED === $flushMode) {
                $this->persistService->flush(); }

            if (TransactionMode::ENABLED === $transactionMode) {
                $this->persistService->commitTransaction(); }

            return $deleted; } catch (\Throwable $e) {
            if (TransactionMode::ENABLED === $transactionMode) {
                $this->persistService->rollbackTransaction(); }

            $errorMessage = sprintf('Unable to delete collection of type \'%s\' : %s', $this->entityName, $e->getMessage()); $this->logger->error($errorMessage); throw new EntityRepositoryException($errorMessage, $e->getCode(), $e); }
    }

    /**
     * @throws EntityRepositoryException
     */
    public function clear(): void
    {
        try {
            $this->persistService->clear(); } catch (\Throwable $e) {
            $errorMessage = sprintf('Unable to clear entity of type \'%s\': %s', $this->entityName, $e->getMessage()); $this->logger->error($errorMessage); throw new EntityRepositoryException($errorMessage, $e->getCode(), $e); }
    }

    /**
     * @param EntityInterface $entity
     *
     * @throws EntityRepositoryException
     */
    public function refresh(EntityInterface $entity): void
    {
        try {
            $this->persistService->refresh($entity); } catch (\Throwable $e) {
            $errorMessage = sprintf('Unable to refresh entity of type \'%s\': %s', $this->entityName, $e->getMessage()); $this->logger->error($errorMessage); throw new EntityRepositoryException($errorMessage, $e->getCode(), $e); }
    }
}
3 3
\ No newline at end of file
Please login to merge, or discard this patch.
src/EntityRepositoryInterface.php 1 patch
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -1,1 +1,1 @@
 block discarded – undo
1
-<?php

declare(strict_types=1);

namespace Arp\DoctrineEntityRepository;

use Arp\DoctrineEntityRepository\Exception\EntityRepositoryException;
use Arp\Entity\EntityInterface;
use Doctrine\Persistence\ObjectRepository;

/**
 * @author  Alex Patterson <[email protected]>
 * @package Arp\DoctrineEntityRepository
 */
interface EntityRepositoryInterface extends ObjectRepository
{
    /**
     * Save a single entity instance.
     *
     * @param EntityInterface $entity
     * @param array           $options
     *
     * @return EntityInterface
     *
     * @throws EntityRepositoryException
     */
    public function save(EntityInterface $entity, array $options = []): EntityInterface;

    /**
     * Save a collection of entities in a single transaction.
     *
     * @param iterable|EntityInterface[] $collection The collection of entities that should be saved.
     * @param array                      $options    the optional save options.
     *
     * @return iterable
     *
     * @throws EntityRepositoryException If the save cannot be completed
     */
    public function saveCollection(iterable $collection, array $options = []): iterable;

    /**
     * Delete an entity.
     *
     * @param EntityInterface|int|string $entity
     * @param array                      $options
     *
     * @return bool
     *
     * @throws EntityRepositoryException
     */
    public function delete($entity, array $options = []): bool;

    /**
     * Perform a deletion of a collection of entities.
     *
     * @param iterable|EntityInterface $collection
     * @param array                    $options
     *
     * @return int
     *
     * @throws EntityRepositoryException
     */
    public function deleteCollection(iterable $collection, array $options = []): int;

    /**
     * @throws EntityRepositoryException
     */
    public function clear(): void;

    /**
     * @param EntityInterface $entity
     *
     * @throws EntityRepositoryException
     */
    public function refresh(EntityInterface $entity): void;
}
2 1
\ No newline at end of file
2
+<?php

declare(strict_types=1); namespace Arp\DoctrineEntityRepository; use Arp\DoctrineEntityRepository\Exception\EntityRepositoryException; use Arp\Entity\EntityInterface; use Doctrine\Persistence\ObjectRepository; /**
 * @author  Alex Patterson <[email protected]>
 * @package Arp\DoctrineEntityRepository
 */
interface EntityRepositoryInterface extends ObjectRepository {
    /**
     * Save a single entity instance.
     *
     * @param EntityInterface $entity
     * @param array           $options
     *
     * @return EntityInterface
     *
     * @throws EntityRepositoryException
     */
    public function save(EntityInterface $entity, array $options = []): EntityInterface; /**
     * Save a collection of entities in a single transaction.
     *
     * @param iterable|EntityInterface[] $collection The collection of entities that should be saved.
     * @param array                      $options    the optional save options.
     *
     * @return iterable
     *
     * @throws EntityRepositoryException If the save cannot be completed
     */
    public function saveCollection(iterable $collection, array $options = []): iterable; /**
     * Delete an entity.
     *
     * @param EntityInterface|int|string $entity
     * @param array                      $options
     *
     * @return bool
     *
     * @throws EntityRepositoryException
     */
    public function delete($entity, array $options = []): bool; /**
     * Perform a deletion of a collection of entities.
     *
     * @param iterable|EntityInterface $collection
     * @param array                    $options
     *
     * @return int
     *
     * @throws EntityRepositoryException
     */
    public function deleteCollection(iterable $collection, array $options = []): int; /**
     * @throws EntityRepositoryException
     */
    public function clear(): void; /**
     * @param EntityInterface $entity
     *
     * @throws EntityRepositoryException
     */
    public function refresh(EntityInterface $entity): void; }
3 3
\ No newline at end of file
Please login to merge, or discard this patch.
src/Persistence/AbstractCascadeService.php 1 patch
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -1,1 +1,1 @@
 block discarded – undo
1
-<?php

declare(strict_types=1);

namespace Arp\DoctrineEntityRepository\Persistence;

use Arp\DoctrineEntityRepository\EntityRepositoryInterface;
use Arp\DoctrineEntityRepository\Persistence\Exception\PersistenceException;
use Arp\Entity\EntityInterface;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Psr\Log\LoggerInterface;

/**
 * @author  Alex Patterson <[email protected]>
 * @package Arp\DoctrineEntityRepository\Persistence
 */
abstract class AbstractCascadeService
{
    /**
     * @var LoggerInterface
     */
    protected LoggerInterface $logger;

    /**
     * @var array
     */
    protected array $options;

    /**
     * @var array
     */
    protected array $collectionOptions;

    /**
     * @param LoggerInterface $logger
     * @param array           $options
     * @param array           $collectionOptions
     */
    public function __construct(LoggerInterface $logger, array $options = [], array $collectionOptions = [])
    {
        $this->logger = $logger;
        $this->options = $options;
        $this->collectionOptions = $collectionOptions;
    }

    /**
     * @param EntityManagerInterface $entityManager
     * @param string                 $entityName
     *
     * @return EntityRepositoryInterface
     * @throws PersistenceException
     * @todo We should implement a way to decorate the call the getRepository() with a concrete implementation
     *       of the EntityRepositoryProviderInterface
     *
     */
    protected function getTargetRepository(
        EntityManagerInterface $entityManager,
        string $entityName
    ): EntityRepositoryInterface {
        try {
            /** @var EntityRepositoryInterface $targetRepository */
            $targetRepository = $entityManager->getRepository($entityName);
        } catch (\Throwable $e) {
            $errorMessage = sprintf(
                'An error occurred while attempting to load the repository for entity class \'%s\' : %s',
                $entityName,
                $e->getMessage()
            );
            $this->logger->error($errorMessage, ['exception' => $e]);

            throw new PersistenceException($errorMessage, $e->getCode(), $e);
        }

        if (null === $targetRepository || !($targetRepository instanceof EntityRepositoryInterface)) {
            $errorMessage = sprintf(
                'The entity repository must be an object of type \'%s\'; \'%s\' returned in \'%s::%s\'',
                EntityRepositoryInterface::class,
                (is_object($targetRepository) ? get_class($targetRepository) : gettype($targetRepository)),
                static::class,
                __FUNCTION__
            );
            $this->logger->error($errorMessage);

            throw new PersistenceException($errorMessage);
        }

        return $targetRepository;
    }

    /**
     * @param EntityInterface $sourceEntity
     * @param string          $fieldName
     * @param ClassMetadata   $sourceMetadata
     * @param ClassMetadata   $targetMetadata
     *
     * @return EntityInterface|EntityInterface[]|iterable
     *
     * @throws PersistenceException
     */
    protected function resolveTargetEntityOrCollection(
        EntityInterface $sourceEntity,
        string $fieldName,
        ClassMetadata $sourceMetadata,
        ClassMetadata $targetMetadata
    ) {
        $methodName = 'get' . ucfirst($fieldName);

        if (!method_exists($sourceEntity, $methodName)) {
            $errorMessage = sprintf(
                'Failed to find required entity method \'%s::%s\'. The method is required for cascade operations '
                . 'of field \'%s\' of target entity \'%s\'',
                $sourceMetadata->getName(),
                $methodName,
                $fieldName,
                $targetMetadata->getName()
            );

            $this->logger->error($errorMessage);

            throw new PersistenceException($errorMessage);
        }

        try {
            $targetEntityOrCollection = $sourceEntity->{$methodName}();
        } catch (\Throwable $e) {
            $errorMessage = sprintf(
                'The call to resolve entity of type \'%s\' from method call \'%s::%s\' failed: %s',
                $targetMetadata->getName(),
                $sourceMetadata->getName(),
                $methodName,
                $e->getMessage()
            );
            $this->logger->error($errorMessage);

            throw new PersistenceException($errorMessage, $e->getCode(), $e);
        }

        return $targetEntityOrCollection;
    }

    /**
     * @param EntityInterface|EntityInterface[]|iterable $entityOrCollection
     * @param array                                      $mapping
     *
     * @return bool
     */
    protected function isValidAssociation($entityOrCollection, array $mapping): bool
    {
        if (null === $entityOrCollection) {
            /**
             * @todo mapping class has a methods to fetch the id field mapping directly
             *
             * Note that we are hard coding the '0' key as the single field the we use as the id/primary key.
             * If we implement EntityInterface correctly we will never have a composite key.
             */
            return isset($mapping['joinColumns'][0]['nullable'])
                ? (bool)$mapping['joinColumns'][0]['nullable']
                : false;
        }

        return (is_callable($entityOrCollection) || $entityOrCollection instanceof EntityInterface);
    }

    /**
     * @param EntityManagerInterface $entityManager
     * @param string                 $entityName
     *
     * @return ClassMetadata
     *
     * @throws PersistenceException
     */
    protected function getClassMetadata(EntityManagerInterface $entityManager, string $entityName): ClassMetadata
    {
        try {
            return $entityManager->getClassMetadata($entityName);
        } catch (\Throwable $e) {
            $errorMessage = sprintf(
                'The entity metadata mapping for class \'%s\' could not be loaded: %s',
                $entityName,
                $e->getMessage()
            );
            $this->logger->error($errorMessage);

            throw new PersistenceException($errorMessage, $e->getCode(), $e);
        }
    }
}
2 1
\ No newline at end of file
2
+<?php

declare(strict_types=1); namespace Arp\DoctrineEntityRepository\Persistence; use Arp\DoctrineEntityRepository\EntityRepositoryInterface; use Arp\DoctrineEntityRepository\Persistence\Exception\PersistenceException; use Arp\Entity\EntityInterface; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\ClassMetadata; use Psr\Log\LoggerInterface; /**
 * @author  Alex Patterson <[email protected]>
 * @package Arp\DoctrineEntityRepository\Persistence
 */
abstract class AbstractCascadeService {
    /**
     * @var LoggerInterface
     */
    protected LoggerInterface $logger; /**
     * @var array
     */
    protected array $options; /**
     * @var array
     */
    protected array $collectionOptions; /**
     * @param LoggerInterface $logger
     * @param array           $options
     * @param array           $collectionOptions
     */
    public function __construct(LoggerInterface $logger, array $options = [], array $collectionOptions = []) {
        $this->logger = $logger; $this->options = $options; $this->collectionOptions = $collectionOptions; }

    /**
     * @param EntityManagerInterface $entityManager
     * @param string                 $entityName
     *
     * @return EntityRepositoryInterface
     * @throws PersistenceException
     * @todo We should implement a way to decorate the call the getRepository() with a concrete implementation
     *       of the EntityRepositoryProviderInterface
     *
     */
    protected function getTargetRepository(EntityManagerInterface $entityManager, string $entityName): EntityRepositoryInterface {
        try {
            /** @var EntityRepositoryInterface $targetRepository */
            $targetRepository = $entityManager->getRepository($entityName); } catch (\Throwable $e) {
            $errorMessage = sprintf('An error occurred while attempting to load the repository for entity class \'%s\' : %s', $entityName, $e->getMessage()); $this->logger->error($errorMessage, ['exception' => $e]); throw new PersistenceException($errorMessage, $e->getCode(), $e); }

        if (null === $targetRepository || !($targetRepository instanceof EntityRepositoryInterface)) {
            $errorMessage = sprintf('The entity repository must be an object of type \'%s\'; \'%s\' returned in \'%s::%s\'', EntityRepositoryInterface::class, (is_object($targetRepository) ? get_class($targetRepository) : gettype($targetRepository)), static::class, __FUNCTION__); $this->logger->error($errorMessage); throw new PersistenceException($errorMessage); }

        return $targetRepository; }

    /**
     * @param EntityInterface $sourceEntity
     * @param string          $fieldName
     * @param ClassMetadata   $sourceMetadata
     * @param ClassMetadata   $targetMetadata
     *
     * @return EntityInterface|EntityInterface[]|iterable
     *
     * @throws PersistenceException
     */
    protected function resolveTargetEntityOrCollection(EntityInterface $sourceEntity, string $fieldName, ClassMetadata $sourceMetadata, ClassMetadata $targetMetadata) {
        $methodName = 'get'.ucfirst($fieldName); if (!method_exists($sourceEntity, $methodName)) {
            $errorMessage = sprintf('Failed to find required entity method \'%s::%s\'. The method is required for cascade operations '.'of field \'%s\' of target entity \'%s\'', $sourceMetadata->getName(), $methodName, $fieldName, $targetMetadata->getName()); $this->logger->error($errorMessage); throw new PersistenceException($errorMessage); }

        try {
            $targetEntityOrCollection = $sourceEntity->{$methodName}(); } catch (\Throwable $e) {
            $errorMessage = sprintf('The call to resolve entity of type \'%s\' from method call \'%s::%s\' failed: %s', $targetMetadata->getName(), $sourceMetadata->getName(), $methodName, $e->getMessage()); $this->logger->error($errorMessage); throw new PersistenceException($errorMessage, $e->getCode(), $e); }

        return $targetEntityOrCollection; }

    /**
     * @param EntityInterface|EntityInterface[]|iterable $entityOrCollection
     * @param array                                      $mapping
     *
     * @return bool
     */
    protected function isValidAssociation($entityOrCollection, array $mapping): bool
    {
        if (null === $entityOrCollection) {
            /**
             * @todo mapping class has a methods to fetch the id field mapping directly
             *
             * Note that we are hard coding the '0' key as the single field the we use as the id/primary key.
             * If we implement EntityInterface correctly we will never have a composite key.
             */
            return isset($mapping['joinColumns'][0]['nullable']) ? (bool) $mapping['joinColumns'][0]['nullable'] : false; }

        return (is_callable($entityOrCollection) || $entityOrCollection instanceof EntityInterface); }

    /**
     * @param EntityManagerInterface $entityManager
     * @param string                 $entityName
     *
     * @return ClassMetadata
     *
     * @throws PersistenceException
     */
    protected function getClassMetadata(EntityManagerInterface $entityManager, string $entityName): ClassMetadata
    {
        try {
            return $entityManager->getClassMetadata($entityName); } catch (\Throwable $e) {
            $errorMessage = sprintf('The entity metadata mapping for class \'%s\' could not be loaded: %s', $entityName, $e->getMessage()); $this->logger->error($errorMessage); throw new PersistenceException($errorMessage, $e->getCode(), $e); }
    }
}
3 3
\ No newline at end of file
Please login to merge, or discard this patch.
src/Persistence/PersistService.php 1 patch
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -168,7 +168,7 @@  discard block
 block discarded – undo
168 168
     {
169 169
         $entityName = $this->getEntityName();
170 170
 
171
-        if (! $entity instanceof $entityName) {
171
+        if (!$entity instanceof $entityName) {
172 172
             throw new PersistenceException(
173 173
                 sprintf(
174 174
                     'The \'entity\' argument must be an object of type \'%s\'; \'%s\' provided in \'%s\'',
@@ -251,7 +251,7 @@  discard block
 block discarded – undo
251 251
     {
252 252
         $entityName = $this->getEntityName();
253 253
 
254
-        if (! $entity instanceof $entityName) {
254
+        if (!$entity instanceof $entityName) {
255 255
             throw new PersistenceException(
256 256
                 sprintf(
257 257
                     'The \'entity\' argument must be an object of type \'%s\'; \'%s\' provided in \'%s\'',
Please login to merge, or discard this patch.
src/Persistence/Event/Listener/CascadeDeleteListener.php 1 patch
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -49,7 +49,7 @@
 block discarded – undo
49 49
         $entity = $event->getEntity();
50 50
 
51 51
         if (null === $entity) {
52
-            $errorMessage= sprintf('Missing required entity in \'%s\'', static::class);
52
+            $errorMessage = sprintf('Missing required entity in \'%s\'', static::class);
53 53
             $this->logger->error($errorMessage);
54 54
 
55 55
             throw new PersistenceException($errorMessage);
Please login to merge, or discard this patch.
src/Persistence/Event/Listener/EntityValidationListener.php 1 patch
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -69,7 +69,7 @@
 block discarded – undo
69 69
             throw new InvalidArgumentException($errorMessage);
70 70
         }
71 71
 
72
-        if (! $entity instanceof EntityInterface || !$entity instanceof $entityName) {
72
+        if (!$entity instanceof EntityInterface || !$entity instanceof $entityName) {
73 73
             $errorMessage = sprintf(
74 74
                 'The entity class of type \'%s\' does not match the expected \'%s\' for event \'%s\'',
75 75
                 (is_object($entity) ? get_class($entity) : gettype($entity)),
Please login to merge, or discard this patch.
src/Persistence/Event/Listener/DateUpdatedListener.php 1 patch
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -23,7 +23,7 @@
 block discarded – undo
23 23
     {
24 24
         $entity = $event->getEntity();
25 25
 
26
-        if (null === $entity || ! $entity instanceof DateUpdatedAwareInterface) {
26
+        if (null === $entity || !$entity instanceof DateUpdatedAwareInterface) {
27 27
             return;
28 28
         }
29 29
 
Please login to merge, or discard this patch.
src/Persistence/Event/Listener/CascadeSaveListener.php 1 patch
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -49,7 +49,7 @@
 block discarded – undo
49 49
         $entity = $event->getEntity();
50 50
 
51 51
         if (null === $entity) {
52
-            $errorMessage= sprintf('Missing required entity in \'%s\'', static::class);
52
+            $errorMessage = sprintf('Missing required entity in \'%s\'', static::class);
53 53
             $this->logger->error($errorMessage);
54 54
 
55 55
             throw new PersistenceException($errorMessage);
Please login to merge, or discard this patch.