From 35ac0d2b6fcd47582aaeb8bb284d160e4dbad751 Mon Sep 17 00:00:00 2001 From: Tomas Hermanek Date: Mon, 2 Dec 2024 10:15:15 +0100 Subject: [PATCH] Authors job processor. --- src/DataFixtures/AuthorFixtures.php | 3 +- src/Domain/Asset/AssetManager.php | 20 +--- src/Domain/Author/AuthorManager.php | 1 - src/Domain/Author/AuthorProvider.php | 24 +++-- .../JobAuthorCurrentOptimizeProcessor.php | 93 +++++++++---------- src/Entity/Author.php | 14 +-- src/Entity/JobAuthorCurrentOptimize.php | 21 ++--- .../JobAuthorCurrentOptimizeResult.php | 74 +++++++++++++++ src/Repository/AssetRepository.php | 7 +- 9 files changed, 168 insertions(+), 89 deletions(-) create mode 100644 src/Model/ValueObject/JobAuthorCurrentOptimizeResult.php diff --git a/src/DataFixtures/AuthorFixtures.php b/src/DataFixtures/AuthorFixtures.php index 91c655a..44a30b5 100644 --- a/src/DataFixtures/AuthorFixtures.php +++ b/src/DataFixtures/AuthorFixtures.php @@ -8,6 +8,7 @@ use AnzuSystems\CoreDamBundle\Domain\Author\AuthorManager; use AnzuSystems\CoreDamBundle\Entity\Author; use AnzuSystems\CoreDamBundle\Entity\ExtSystem; +use AnzuSystems\CoreDamBundle\Helper\CollectionHelper; use AnzuSystems\CoreDamBundle\Model\Enum\AuthorType; use Doctrine\Common\Collections\ArrayCollection; use Generator; @@ -100,7 +101,7 @@ private function getData(): Generator $childAuthor = (new Author()) ->setId(self::AUTHOR_4) ->setName('AgencyA/AuthorB') - ->setCurrentAuthors(new ArrayCollection([$author5, $author6])) + ->setCurrentAuthors(CollectionHelper::newCollection([$author5, $author6])) ->setExtSystem($cmsExtSystem); $childAuthor->getFlags()->setReviewed(false); diff --git a/src/Domain/Asset/AssetManager.php b/src/Domain/Asset/AssetManager.php index 476d338..25b79d5 100644 --- a/src/Domain/Asset/AssetManager.php +++ b/src/Domain/Asset/AssetManager.php @@ -5,18 +5,18 @@ namespace AnzuSystems\CoreDamBundle\Domain\Asset; use AnzuSystems\CoreDamBundle\Domain\AbstractManager; +use AnzuSystems\CoreDamBundle\Domain\Author\AuthorProvider; use AnzuSystems\CoreDamBundle\Entity\Asset; -use AnzuSystems\CoreDamBundle\Entity\Author; use AnzuSystems\CoreDamBundle\Model\Dto\Asset\AssetAdmUpdateDto; use AnzuSystems\CoreDamBundle\Model\Dto\Asset\FormProvidableMetadataBulkUpdateDto; use Doctrine\Common\Collections\ArrayCollection; -use Doctrine\Common\Collections\Collection; use Doctrine\ORM\NonUniqueResultException; class AssetManager extends AbstractManager { public function __construct( - private readonly AssetPropertiesRefresher $propertiesRefresher + private readonly AssetPropertiesRefresher $propertiesRefresher, + private readonly AuthorProvider $authorProvider, ) { } @@ -89,20 +89,8 @@ public function updateFromMetadataBulkDto( $this->colUpdate( oldCollection: $asset->getAuthors(), newCollection: $dto->getAuthors(), - addElementFn: function (Collection $oldCollection, Author $author): bool { - if (false === $author->getCurrentAuthors()->isEmpty()) { - foreach ($author->getCurrentAuthors() as $currentAuthor) { - $oldCollection->add($currentAuthor); - } - - return true; - } - - $oldCollection->add($author); - - return true; - }, ); + $this->authorProvider->provideCurrentAuthorToColl($asset); return $this->updateExisting($asset, $flush); } diff --git a/src/Domain/Author/AuthorManager.php b/src/Domain/Author/AuthorManager.php index 8c84fae..cd3832c 100644 --- a/src/Domain/Author/AuthorManager.php +++ b/src/Domain/Author/AuthorManager.php @@ -5,7 +5,6 @@ namespace AnzuSystems\CoreDamBundle\Domain\Author; use AnzuSystems\CoreDamBundle\Domain\AbstractManager; -use AnzuSystems\CoreDamBundle\Entity\AssetLicence; use AnzuSystems\CoreDamBundle\Entity\Author; use Doctrine\Common\Collections\Collection; diff --git a/src/Domain/Author/AuthorProvider.php b/src/Domain/Author/AuthorProvider.php index d049aa2..c4de1eb 100644 --- a/src/Domain/Author/AuthorProvider.php +++ b/src/Domain/Author/AuthorProvider.php @@ -41,13 +41,25 @@ public function provideByTitle(string $title, ExtSystem $extSystem): ?Author ); } - public function provideCurrentAuthorToColl(Asset $asset, Author $author): void + public function provideCurrentAuthorToColl(Asset $asset): bool { + $changedCurrentAuthors = false; + foreach ($asset->getAuthors() as $assetAuthor) { + if ($assetAuthor->getCurrentAuthors()->isEmpty()) { + continue; + } - } + $changedCurrentAuthors = true; + + foreach ($assetAuthor->getCurrentAuthors() as $currentAuthor) { + $asset->getAuthors()->add($currentAuthor); + } -// public function () -// { -// -// } + if (false === $assetAuthor->getFlags()->isReviewed()) { + $asset->getAuthors()->removeElement($assetAuthor); + } + } + + return $changedCurrentAuthors; + } } diff --git a/src/Domain/Job/Processor/JobAuthorCurrentOptimizeProcessor.php b/src/Domain/Job/Processor/JobAuthorCurrentOptimizeProcessor.php index ca2f7e8..bada1e3 100644 --- a/src/Domain/Job/Processor/JobAuthorCurrentOptimizeProcessor.php +++ b/src/Domain/Job/Processor/JobAuthorCurrentOptimizeProcessor.php @@ -7,18 +7,15 @@ use AnzuSystems\CommonBundle\Domain\Job\Processor\AbstractJobProcessor; use AnzuSystems\CommonBundle\Entity\Interfaces\JobInterface; use AnzuSystems\CommonBundle\Traits\EntityManagerAwareTrait; +use AnzuSystems\CoreDamBundle\Domain\Author\AuthorProvider; use AnzuSystems\CoreDamBundle\Domain\Image\ImageCopyFacade; +use AnzuSystems\CoreDamBundle\Entity\Asset; use AnzuSystems\CoreDamBundle\Entity\Author; use AnzuSystems\CoreDamBundle\Entity\JobAuthorCurrentOptimize; -use AnzuSystems\CoreDamBundle\Entity\JobImageCopy; -use AnzuSystems\CoreDamBundle\Entity\JobImageCopyItem; -use AnzuSystems\CoreDamBundle\Model\Dto\Image\ImageCopyDto; -use AnzuSystems\CoreDamBundle\Model\Enum\AssetFileCopyStatus; -use AnzuSystems\CoreDamBundle\Model\ValueObject\JobImageCopyResult; +use AnzuSystems\CoreDamBundle\Model\ValueObject\JobAuthorCurrentOptimizeResult; use AnzuSystems\CoreDamBundle\Repository\AssetRepository; use AnzuSystems\CoreDamBundle\Repository\AuthorRepository; use AnzuSystems\CoreDamBundle\Repository\JobImageCopyItemRepository; -use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Throwable; @@ -26,13 +23,14 @@ final class JobAuthorCurrentOptimizeProcessor extends AbstractJobProcessor { use EntityManagerAwareTrait; - private const int ASSET_BULK_SIZE = 10; + private const int ASSET_BULK_SIZE = 500; public function __construct( private readonly ImageCopyFacade $imageCopyFacade, private readonly JobImageCopyItemRepository $jobImageCopyItemRepository, private readonly AssetRepository $assetRepository, private readonly AuthorRepository $authorRepository, + private readonly AuthorProvider $authorProvider, private int $bulkSize = self::ASSET_BULK_SIZE, ) { } @@ -52,60 +50,61 @@ public function setBulkSize(int $bulkSize): void */ public function process(JobInterface $job): void { -// $this->start($job); + $this->start($job); try { - /** @var Collection $currentAuthorColl */ - $authors = new ArrayCollection(array_values( - array_filter( - array_map(fn(string $id): ?Author => $this->authorRepository->find($id), $job->getAuthorIds()), - ) - )); - - foreach ($authors as $author) { - $this->processAuthor($author); - } + $job->isProcessAll() + ? $this->processAll($job) + : $this->processAuthor($job) + ; + $this->entityManager->clear(); } catch (Throwable $e) { $this->finishFail($job, $e->getMessage()); } } - private function processAuthor(Author $author): void + private function processAll(JobAuthorCurrentOptimize $job): void { - $assets = $this->assetRepository->findByAuthor($author); - dd($assets->count()); + $lastId = $job->getLastBatchProcessedRecord(); + $assets = $this->assetRepository->getAll(idFrom: $lastId, limit: $this->bulkSize); + + $this->processAssetsCollection($job, $assets, $lastId); + } + + private function processAuthor(JobAuthorCurrentOptimize $job): void + { + /** @var Author $author */ + $author = $this->authorRepository->find($job->getAuthorId()); + + $lastId = $job->getLastBatchProcessedRecord(); + $assets = $this->assetRepository->findByAuthor($author, $lastId, $this->bulkSize); + + $this->processAssetsCollection($job, $assets, $lastId); } /** - * @param Collection $items + * @param Collection $assets */ - private function finishCycle(JobImageCopy $job, Collection $items, string $lastProcessedRecord = ''): void + private function processAssetsCollection(JobAuthorCurrentOptimize $job, Collection $assets, string $lastId = ''): void { - $previousResult = JobImageCopyResult::fromString($job->getResult()); - $job->setBatchProcessedIterationCount($items->count() + $job->getBatchProcessedIterationCount()); - - $existsCount = $previousResult->getExistsCount(); - $copyCount = $previousResult->getCopyCount(); - $notAllowedCount = $previousResult->getNotAllowedCount(); - - foreach ($items as $item) { - match ($item->getStatus()) { - AssetFileCopyStatus::Copy => $copyCount++, - AssetFileCopyStatus::Exists => $existsCount++, - AssetFileCopyStatus::Unassigned => $notAllowedCount++, - AssetFileCopyStatus::NotAllowed => null - }; + $changedAuthorsCount = 0; + foreach ($assets as $asset) { + if ($this->authorProvider->provideCurrentAuthorToColl($asset)) { + $changedAuthorsCount++; + } + $lastId = (string) $asset->getId(); } - $this->getManagedJob($job)->setResult((new JobImageCopyResult( - copyCount: $copyCount, - existsCount: $existsCount, - notAllowedCount: $notAllowedCount - ))->toString()); - - $items->count() === $this->bulkSize - ? $this->toAwaitingBatchProcess($job, $lastProcessedRecord) - : $this->finishSuccess($job) - ; + $count = $assets->count(); + $resultBefore = JobAuthorCurrentOptimizeResult::fromString($job->getResult()); + $resultNew = new JobAuthorCurrentOptimizeResult( + $resultBefore->getOptimizedCount() + $changedAuthorsCount, + $resultBefore->getTotalCount() + $assets->count(), + ); + $this->getManagedJob($job)->setResult($resultNew->toString()); + + $count === $this->bulkSize + ? $this->toAwaitingBatchProcess($job, $lastId) + : $this->finishSuccess($job); } } diff --git a/src/Entity/Author.php b/src/Entity/Author.php index e602ccd..4140f46 100644 --- a/src/Entity/Author.php +++ b/src/Entity/Author.php @@ -50,7 +50,7 @@ class Author implements UuidIdentifiableInterface, UserTrackingInterface, TimeTr * If asset uses author and has defined currentAuthors, this relation should be replaced * todo current author should be final author without parents! */ - #[ORM\ManyToMany(targetEntity: Author::class, inversedBy: 'childAuthors', fetch: App::DOCTRINE_EXTRA_LAZY)] + #[ORM\ManyToMany(targetEntity: self::class, inversedBy: 'childAuthors', fetch: App::DOCTRINE_EXTRA_LAZY)] #[ORM\JoinTable('author_is_current_author')] #[Serialize(handler: EntityIdHandler::class)] private Collection $currentAuthors; @@ -58,7 +58,7 @@ class Author implements UuidIdentifiableInterface, UserTrackingInterface, TimeTr /** * Inverse side of currentAuthors */ - #[ORM\ManyToMany(targetEntity: Author::class, mappedBy: 'currentAuthors', fetch: App::DOCTRINE_EXTRA_LAZY)] + #[ORM\ManyToMany(targetEntity: self::class, mappedBy: 'currentAuthors', fetch: App::DOCTRINE_EXTRA_LAZY)] #[Serialize(handler: EntityIdHandler::class)] private Collection $childAuthors; @@ -164,6 +164,7 @@ public function getCurrentAuthors(): Collection public function setCurrentAuthors(Collection $currentAuthors): self { $this->currentAuthors = $currentAuthors; + return $this; } @@ -175,7 +176,7 @@ public function getChildAuthors(): Collection return $this->childAuthors; } - public function addChildAuthor(Author $author): self + public function addChildAuthor(self $author): self { if (false === $this->childAuthors->contains($author)) { $this->childAuthors->add($author); @@ -184,7 +185,7 @@ public function addChildAuthor(Author $author): self return $this; } - public function addCurrentAuthor(Author $author): self + public function addCurrentAuthor(self $author): self { if (false === $this->currentAuthors->contains($author)) { $this->currentAuthors->add($author); @@ -199,10 +200,11 @@ public function addCurrentAuthor(Author $author): self public function setChildAuthors(Collection $childAuthors): self { $this->childAuthors = $childAuthors; + return $this; } - public function removeChildAuthor(Author $author): self + public function removeChildAuthor(self $author): self { if ($this->childAuthors->contains($author)) { $this->childAuthors->removeElement($author); @@ -211,7 +213,7 @@ public function removeChildAuthor(Author $author): self return $this; } - public function removeCurrentAuthor(Author $author): self + public function removeCurrentAuthor(self $author): self { if ($this->currentAuthors->contains($author)) { $this->currentAuthors->removeElement($author); diff --git a/src/Entity/JobAuthorCurrentOptimize.php b/src/Entity/JobAuthorCurrentOptimize.php index 7dadeab..a63877a 100644 --- a/src/Entity/JobAuthorCurrentOptimize.php +++ b/src/Entity/JobAuthorCurrentOptimize.php @@ -6,23 +6,20 @@ use AnzuSystems\CommonBundle\Entity\Job; use AnzuSystems\CoreDamBundle\Repository\JobAuthorCurrentOptimizeRepository; -use AnzuSystems\CoreDamBundle\Repository\JobImageCopyRepository; use AnzuSystems\SerializerBundle\Attributes\Serialize; -use AnzuSystems\SerializerBundle\Handler\Handlers\EntityIdHandler; -use Doctrine\Common\Collections\ArrayCollection; -use Doctrine\Common\Collections\Collection; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity(repositoryClass: JobAuthorCurrentOptimizeRepository::class)] class JobAuthorCurrentOptimize extends Job { - #[ORM\Column(type: Types::BOOLEAN)] + #[ORM\Column(type: Types::BOOLEAN, options: ['default' => false])] + #[Serialize] private bool $processAll = false; - #[ORM\Column(type: Types::JSON)] + #[ORM\Column(type: Types::STRING, length: 36, nullable: true)] #[Serialize] - private array $authorIds = []; + private ?string $authorId = null; public function isProcessAll(): bool { @@ -32,17 +29,19 @@ public function isProcessAll(): bool public function setProcessAll(bool $processAll): self { $this->processAll = $processAll; + return $this; } - public function getAuthorIds(): array + public function getAuthorId(): ?string { - return $this->authorIds; + return $this->authorId; } - public function setAuthorIds(array $authorIds): self + public function setAuthorId(?string $authorId): self { - $this->authorIds = $authorIds; + $this->authorId = $authorId; + return $this; } } diff --git a/src/Model/ValueObject/JobAuthorCurrentOptimizeResult.php b/src/Model/ValueObject/JobAuthorCurrentOptimizeResult.php new file mode 100644 index 0000000..e931abd --- /dev/null +++ b/src/Model/ValueObject/JobAuthorCurrentOptimizeResult.php @@ -0,0 +1,74 @@ +optimizedCount, + $this->totalCount, + ); + } + + public static function fromString(string $string): self + { + $parts = explode('|', $string); + + return new self( + isset($parts[0]) ? (int) $parts[0] : 0, + isset($parts[1]) ? (int) $parts[1] : 0, + ); + } + + public function getOptimizedCount(): int + { + return $this->optimizedCount; + } + + public function getTotalCount(): int + { + return $this->totalCount; + } + + public function is(string $value): bool + { + return $this->toString() === $value; + } + + public function isNot(string $value): bool + { + return false === $this->is($value); + } + + public function in(array $values): bool + { + throw new DomainException('Method "in" not supported for OriginExternalProvider.'); + } + + /** + * @param OriginExternalProvider $valueObject + */ + public function equals(ValueObjectInterface $valueObject): bool + { + return $this->is($valueObject->toString()); + } + + public function toString(): string + { + return (string) $this; + } +} diff --git a/src/Repository/AssetRepository.php b/src/Repository/AssetRepository.php index 6b9e449..f625de8 100644 --- a/src/Repository/AssetRepository.php +++ b/src/Repository/AssetRepository.php @@ -13,6 +13,7 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Criteria; +use Doctrine\Common\Collections\Order; use Doctrine\ORM\QueryBuilder; /** @@ -25,13 +26,17 @@ */ final class AssetRepository extends AbstractAnzuRepository { - public function findByAuthor(Author $author): Collection + public function findByAuthor(Author $author, string $fromId = '', int $limit = 100): Collection { return new ArrayCollection( $this->createQueryBuilder('entity') ->innerJoin('entity.authors', 'author') ->where('author.id = :id') + ->andWhere('entity.id > :fromId') ->setParameter('id', $author->getId()) + ->setParameter('fromId', $fromId) + ->addOrderBy('entity.id', Order::Ascending->value) + ->setMaxResults($limit) ->getQuery() ->getResult() );