Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php
- declare(strict_types=1);
- namespace App\Service;
- use App\Entity\Account;
- use App\Entity\BaseEntity;
- use App\Entity\Commentary;
- use App\Entity\Interface\AccountEntityInterface;
- use App\Entity\Interface\ArchivableEntityInterface;
- use App\Entity\Interface\BaseEntityInterface;
- use App\Entity\Interface\CommittedEntityInterface;
- use App\Entity\Interface\DeletedEntityInterface;
- use App\Entity\Interface\FilterAliasEntityInterface;
- use App\Entity\Interface\FilterExtendedEntityInterface;
- use App\Entity\Interface\SearchTextEntityInterface;
- use App\Entity\Interface\SnapshotableEntityInterface;
- use App\Entity\Interface\TrashableEntityInterface;
- use App\Entity\Model\FilterExtendedFieldValue;
- use App\Entity\Model\SearchTextFilter;
- use App\Enum\Entity\IsArchivedEnum;
- use App\Event\Entity\EntityDeletedEvent;
- use App\Exception\Entity\EntityTypeException;
- use App\Exception\Entity\EntityValidationException;
- use App\Exception\ObjectInUseException;
- use App\Exception\ObjectNotFoundException;
- use App\Exception\ObjectNotImplementException;
- use App\Helper\ArrayHelper;
- use App\Helper\SortingHelper;
- use App\Repository\EntityRepository;
- use App\Repository\Interface\EntityBuildFilterRepositoryInterface;
- use App\Repository\Interface\InvalidatebleCacheRepositoryInterface;
- use App\Repository\Interface\TotalsRepositoryInterface;
- use App\Service\Entity\Interface\EntityServiceInterface;
- use App\Service\Entity\Interface\FilterServiceInterface;
- use App\Service\Entity\Interface\TrashServiceInterface;
- use App\Service\Entity\TrashService;
- use App\Service\Locator\EntityServiceLocator;
- use App\Service\Utility\EntityHelperService;
- use App\Trait\Repository\EntityBuildFilterRepositoryTrait;
- use App\Trait\Service\GetServiceTrait;
- use Doctrine\ORM\EntityManagerInterface;
- use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
- use Symfony\Component\DependencyInjection\ServiceLocator;
- use Symfony\Component\EventDispatcher\EventDispatcherInterface;
- use Symfony\Component\Uid\UuidV7;
- use Symfony\Component\Validator\Constraint;
- use Symfony\Component\Validator\Validator\ValidatorInterface;
- use Symfony\Contracts\Service\Attribute\Required;
- abstract class EntityService implements EntityServiceInterface
- {
- use GetServiceTrait;
- /**
- * @var EntityRepository<BaseEntityInterface>|null
- */
- protected ?EntityRepository $repository = null;
- /**
- * @var ServiceLocator<EntityService>
- */
- protected ServiceLocator $locator;
- protected EventDispatcherInterface $dispatcher;
- protected EntityHelperService $entityHelperService;
- protected TrashService $trashService;
- protected ParameterBagInterface $params;
- protected ValidatorInterface $validator;
- protected EntityManagerInterface $em;
- protected ?string $entityName = null;
- #[Required]
- public function setDependencies(
- EntityServiceLocator $subscriber,
- EventDispatcherInterface $dispatcher,
- EntityHelperService $entityHelper,
- TrashService $trashService,
- ParameterBagInterface $params,
- ValidatorInterface $validator,
- ): void {
- $this->locator = $subscriber->getLocator();
- $this->dispatcher = $dispatcher;
- $this->entityHelperService = $entityHelper;
- $this->trashService = $trashService;
- $this->params = $params;
- $this->validator = $validator;
- }
- #[\Override]
- public function isExists(
- UuidV7|string|null $id = null,
- ?Account $account = null,
- array $criteria = [],
- bool $criteriaAlreadyPrepared = false,
- ): bool {
- if (!$criteriaAlreadyPrepared) {
- $criteria = $this->prepareCriteria(
- criteria: $criteria,
- id: $id,
- account: $account,
- );
- } elseif (null !== $account) {
- $criteria['account'] = $account;
- }
- $repository = $this->getRepository();
- if (method_exists($repository, 'isExistsByFilter')) {
- /* @var EntityBuildFilterRepositoryTrait $repository */
- return $repository->isExistsByFilter($criteria);
- }
- unset($criteria['filter']);
- return $this->getRepository()->isExists($criteria);
- }
- #[\Override]
- public function get(
- UuidV7|string|null $id = null,
- ?Account $account = null,
- array $criteria = [],
- array $orderBy = [],
- bool $criteriaAlreadyPrepared = false,
- ): BaseEntityInterface {
- $entity = $this->find($id, $account, $criteria, $orderBy, $criteriaAlreadyPrepared);
- if (null === $entity) {
- throw new ObjectNotFoundException($this->entityHelperService->getEntity($this), $id);
- }
- return $entity;
- }
- #[\Override]
- public function find(
- UuidV7|string|null $id = null,
- ?Account $account = null,
- array $criteria = [],
- ?array $orderBy = [],
- bool $criteriaAlreadyPrepared = false,
- ): ?BaseEntityInterface {
- if (null === $id && 0 === count($criteria)) {
- return null;
- }
- if (is_string($id) && !empty($id) && !UuidV7::isValid($id)) {
- $exception = new EntityValidationException();
- $exception->addCustomError(sprintf('Error idetificator Uuid format: %s', $id));
- throw $exception;
- }
- if (!$criteriaAlreadyPrepared) {
- $criteria = $this->prepareCriteria(
- criteria: $criteria,
- id: $id,
- account: $account,
- );
- } elseif (null === $id) {
- unset($criteria['id']);
- } else {
- $criteria['id'] = $id;
- }
- unset($criteria['filter']);
- if (null === $orderBy || 0 === count($orderBy)) {
- $orderBy = $this->entityHelperService->getSortingDefault($this);
- }
- $repository = $this->getRepository();
- if ($account && !isset($criteria['id']) && method_exists($repository, 'getByAccount')) {
- $entity = $repository->getByAccount($criteria['account'], 1, 0, $orderBy);
- $entity = $entity[0] ?? null;
- } else {
- $entityClass = $this->entityHelperService->getEntity($this);
- if (null !== $account && is_a($entityClass, AccountEntityInterface::class, true)) {
- $criteria['account'] = $account;
- }
- if ($repository instanceof EntityBuildFilterRepositoryInterface) {
- $entity = $repository->findByFilter($criteria, $orderBy, 1)[0] ?? null;
- } else {
- $entity = $repository->findOneBy($criteria, $orderBy);
- }
- }
- if (null !== $entity && !($entity instanceof BaseEntityInterface)) {
- throw new EntityTypeException(BaseEntity::class);
- }
- return $entity;
- }
- #[\Override]
- public function getAll(
- array $criteria = [],
- ?int $limit = null,
- ?int $offset = null,
- array $orderBy = [],
- bool $criteriaAlreadyPrepared = false,
- ): array {
- if (!$criteriaAlreadyPrepared) {
- $criteria = $this->prepareCriteria(
- criteria: $criteria,
- account: $criteria['account'] ?? null,
- );
- }
- $sortableProperties = $this->entityHelperService->getSortableProperties($this);
- $sortingDefault = $this->entityHelperService->getSortingDefault($this);
- $orderBy = SortingHelper::prepare($orderBy, $sortableProperties, $sortingDefault);
- $repository = $this->getRepository();
- if (
- (!($repository instanceof EntityBuildFilterRepositoryInterface) && isset($criteria['filter']))
- || method_exists($repository, 'getByAccount')
- ) {
- unset($criteria['filter']);
- }
- return match (true) {
- $repository instanceof EntityBuildFilterRepositoryInterface => $repository->findByFilter(
- criteria: $criteria,
- orderBy: $orderBy,
- limit: $limit,
- offset: $offset,
- ),
- method_exists($repository, 'getByAccount') => $repository->getByAccount(
- $criteria['account'],
- $limit,
- $offset,
- $orderBy,
- ),
- default => $repository->findBy(
- $criteria,
- $orderBy,
- $limit,
- $offset,
- ),
- };
- }
- /**
- * @param int|null $chunkSize
- *
- * @see EntityBuildFilterRepositoryTrait::findByFilterIterable()
- */
- public function getAllIterable(
- array $criteria = [],
- ?int $limit = null,
- ?int $offset = null,
- array $orderBy = [],
- bool $criteriaAlreadyPrepared = false,
- ?int $chunkSize = null,
- ): \Generator {
- if (!$criteriaAlreadyPrepared) {
- $criteria = $this->prepareCriteria(
- criteria: $criteria,
- account: $criteria['account'] ?? null,
- );
- }
- $repository = $this->getRepository();
- if (!($repository instanceof EntityBuildFilterRepositoryInterface)) {
- throw new ObjectNotImplementException($repository::class, EntityBuildFilterRepositoryInterface::class);
- }
- return $repository->findByFilterIterable(
- criteria: $criteria,
- orderBy: SortingHelper::prepare($orderBy, $this->entityHelperService->getSortableProperties($this), $this->entityHelperService->getSortingDefault($this)),
- limit: $limit,
- offset: $offset,
- chunkSize: $chunkSize ?? 0,
- );
- }
- #[\Override]
- public function getCount(
- array $criteria = [],
- bool $criteriaAlreadyPrepared = false,
- ): int {
- if (!$criteriaAlreadyPrepared) {
- $criteria = $this->prepareCriteria(
- criteria: $criteria,
- account: $criteria['account'] ?? null,
- );
- }
- $repository = $this->getRepository();
- if (
- method_exists($repository, 'countAllByAccount')
- || (!method_exists($repository, 'getCountByFilter') && isset($criteria['filter']))
- ) {
- unset($criteria['filter']);
- }
- return match (true) {
- method_exists($repository, 'countAllByAccount') => $repository->countAllByAccount($criteria['account']),
- method_exists($repository, 'getCountByFilter') => $repository->getCountByFilter($criteria),
- default => $repository->count($criteria),
- };
- }
- #[\Override]
- public function getSum(
- string $fieldName,
- array $criteria = [],
- bool $criteriaAlreadyPrepared = false,
- ): int {
- if (!$criteriaAlreadyPrepared) {
- $criteria = $this->prepareCriteria(
- criteria: $criteria,
- account: $criteria['account'] ?? null,
- );
- }
- $repository = $this->getRepository();
- unset($criteria['filter']);
- return match (true) {
- method_exists($repository, 'getSumByFilter') => $repository->getSumByFilter($fieldName, $criteria),
- default => throw new \LogicException(sprintf('Count sum method not found for repository "%s".', $repository::class)),
- };
- }
- #[\Override]
- public function getTotals(
- ?Account $account,
- array $criteria = [],
- ): ?array {
- $repository = $this->getRepository();
- if ($account) {
- $criteria['account'] = $account;
- }
- if ($repository instanceof TotalsRepositoryInterface) {
- return $repository->getTotals($criteria);
- }
- return null;
- }
- #[\Override]
- public function delete(
- BaseEntityInterface $entity,
- ?Account $account = null,
- ?bool $ignoreTrash = false,
- bool $flush = true,
- ): void {
- if (
- !$ignoreTrash
- && null !== $account
- && $entity instanceof TrashableEntityInterface
- && $this instanceof TrashServiceInterface
- && !$entity->getIsTrashed()
- ) {
- $this->trash($entity, $account);
- return;
- }
- if (!$this->canDelete($entity)) {
- throw new ObjectInUseException($entity::class);
- }
- $isBeenCommitted = false;
- if ($entity instanceof CommittedEntityInterface) {
- $isBeenCommitted = $entity->getIsCommitted();
- }
- $payload = ($entity instanceof SnapshotableEntityInterface) ? $this->getSnapshot($entity) : [];
- $repository = $this->getRepository();
- if ($entity instanceof DeletedEntityInterface) {
- $entity->delete();
- $repository->update(entity: $entity, flush: $flush);
- } else {
- $repository->delete(entity: $entity, flush: $flush);
- }
- if ($entity instanceof TrashableEntityInterface && $entity->getIsTrashed()) {
- $this->trashService->deleteByEntity($entity, $account);
- }
- $this->dispatcher->dispatch(new EntityDeletedEvent(
- entity: $entity,
- account: $account,
- isBeenCommitted: $isBeenCommitted,
- payload: $payload,
- ));
- }
- #[\Override]
- public function prepareCriteria(
- array $criteria = [],
- UuidV7|string|null $id = null,
- ?Account $account = null,
- string $search = '',
- array $exclude = [],
- bool $isAccurateSearch = false,
- ): array {
- $entityFqcn = $this->entityHelperService->getEntity($this);
- $entity = new $entityFqcn();
- if (null !== $id) {
- $criteria['id'] = $id;
- }
- if ($entity instanceof FilterExtendedEntityInterface) {
- foreach ($entity->getFilterExtendedFields() as $extendedField) {
- if (isset($criteria[$extendedField])) {
- $criteria[$extendedField] = new FilterExtendedFieldValue($criteria[$extendedField]);
- }
- }
- }
- if ($entity instanceof FilterAliasEntityInterface) {
- foreach ($entity->getFilterAliases() as $alias => $normal) {
- if (isset($criteria[$alias])) {
- $val = $criteria[$alias];
- ArrayHelper::assignArrayByPathAndValue(
- arr: $criteria,
- path: $normal,
- value: is_string($val) ? explode(',', $val) : [$val])
- ;
- unset($criteria[$alias]);
- }
- }
- }
- if ($entity instanceof ArchivableEntityInterface) {
- if (!array_key_exists('isArchived', $criteria)) {
- if (null === $id) {
- $criteria['isArchived'] = IsArchivedEnum::false;
- }
- } else {
- $criteria['isArchived'] = IsArchivedEnum::tryFromValue($criteria['isArchived']);
- }
- }
- if ($this instanceof FilterServiceInterface) {
- $criteria = $this->getFilter($entityFqcn, $criteria, ['account']);
- }
- if (null !== $account && $entity instanceof AccountEntityInterface) {
- if (array_key_exists('account', $criteria) && null === $criteria['account']) {
- unset($criteria['account']);
- } else {
- $criteria['account'] = $account;
- }
- }
- if (!empty($search)) {
- if ($entity instanceof SearchTextEntityInterface) {
- $isCommentary = $entity instanceof Commentary;
- $criteria['searchText'] = new SearchTextFilter(
- accountId: $account?->getId()?->toRfc4122(),
- entity: $isCommentary ? ($criteria['entityId'][0] ?? null) : $this->entityHelperService->getName($entityFqcn),
- searchText: $search,
- entityId: $criteria['entityId'][0] ?? null,
- isAccurateSearch: $isAccurateSearch,
- );
- } else {
- $criteria['searchText'] = $search;
- }
- }
- if (property_exists($entity, 'deleted')) {
- if (!array_key_exists('deleted', $criteria)) {
- $criteria['deleted'] = false;
- } elseif (null === $criteria['deleted']) {
- unset($criteria['deleted']);
- }
- }
- if ($entity instanceof TrashableEntityInterface) {
- if (!array_key_exists('isTrashed', $criteria)) {
- if (null === $id) {
- $criteria['isTrashed'] = false;
- }
- } elseif (null === $criteria['isTrashed']) {
- unset($criteria['isTrashed']);
- }
- }
- return $criteria;
- }
- /**
- * @param Constraint[]|Constraint|null $constraints
- */
- #[\Override]
- public function validate(
- BaseEntity $entity,
- Constraint|array|null $constraints = null,
- ): void {
- if (empty($constraints)) {
- return;
- }
- if (!is_array($constraints)) {
- $constraints = [$constraints];
- }
- $exception = new EntityValidationException();
- foreach ($constraints as $constraint) {
- $validationErrors = $this->validator->validate($entity, $constraint);
- if ($validationErrors->count() > 0) {
- foreach ($validationErrors as $error) {
- $exception->addCustomError($error->getMessage());
- }
- }
- }
- if (count($exception->getErrors())) {
- throw $exception;
- }
- }
- public function invalidateCache(
- BaseEntityInterface $entity,
- ): void {
- $repository = $this->entityHelperService->findRepository($this);
- $cache = $repository->getCache();
- if (null !== $cache && $repository instanceof InvalidatebleCacheRepositoryInterface) {
- $repository->invalidateCache($cache, $entity);
- }
- }
- public function refresh(
- BaseEntityInterface $entity,
- ): void {
- $this->getRepository()->refresh(entity: $entity, lock: false);
- }
- /**
- * Write all entities to repository and clear ObjectManager.
- */
- public function detach(
- BaseEntityInterface $entity,
- ): void {
- $this->getRepository()->detach($entity);
- }
- /**
- * Write all entities to repository.
- */
- public function flushAll(): void
- {
- $this->getRepository()->update(flush: true);
- }
- #[\Override]
- public function getSnapshot(
- SnapshotableEntityInterface $entity,
- ): array {
- $data = $this->getRepository()->getPreviousData($entity);
- $fields = $entity->getSnapshotFields();
- foreach (array_keys($data) as $field) {
- if (!in_array($field, $fields, true)) {
- unset($data[$field]);
- }
- }
- return $data;
- }
- /**
- * @return EntityRepository<BaseEntityInterface>
- */
- protected function getRepository(): EntityRepository
- {
- if (null === $this->repository) {
- $this->repository = $this->entityHelperService->findRepository($this);
- }
- return $this->repository;
- }
- public function with(string|array|null $assocList = null): void
- {
- $this->getRepository()->with($assocList);
- }
- protected function canDelete(
- BaseEntityInterface $entity,
- ): bool {
- return true;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment