Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature authors job #96

Merged
merged 6 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions src/Controller/Api/Adm/V1/JobController.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use AnzuSystems\CommonBundle\Model\OpenApi\Response\OAResponseValidation;
use AnzuSystems\Contracts\AnzuApp;
use AnzuSystems\Contracts\Exception\AppReadOnlyModeException;
use AnzuSystems\CoreDamBundle\Entity\JobAuthorCurrentOptimize;
use AnzuSystems\CoreDamBundle\Entity\JobImageCopy;
use AnzuSystems\CoreDamBundle\Entity\JobPodcastSynchronizer;
use AnzuSystems\CoreDamBundle\Security\Permission\DamPermissions;
Expand All @@ -25,8 +26,6 @@
final class JobController extends AbstractJobController
{
/**
* Create JobPodcastSynchronizer item.
*
* @throws ValidationException
* @throws AppReadOnlyModeException
*/
Expand All @@ -43,8 +42,6 @@ public function createPodcastSynchronizer(#[SerializeParam] JobPodcastSynchroniz
}

/**
* Create JobPodcastSynchronizer item.
*
* @throws ValidationException
* @throws AppReadOnlyModeException
*/
Expand All @@ -60,6 +57,22 @@ public function createImageCopyJob(#[SerializeParam] JobImageCopy $job): JsonRes
);
}

/**
* @throws ValidationException
* @throws AppReadOnlyModeException
*/
#[Route('/author-current-optimize', 'create_job_author_current_optimize', methods: [Request::METHOD_POST])]
#[OARequest(JobAuthorCurrentOptimize::class), OAResponseCreated(JobAuthorCurrentOptimize::class), OAResponseValidation]
public function createAuthorCurrentJob(#[SerializeParam] JobAuthorCurrentOptimize $job): JsonResponse
{
AnzuApp::throwOnReadOnlyMode();
$this->denyAccessUnlessGranted($this->getCreateAcl());

return $this->createdResponse(
$this->jobFacade->create($job)
);
}

protected function getCreateAcl(): string
{
return DamPermissions::DAM_JOB_CREATE;
Expand Down
33 changes: 33 additions & 0 deletions src/DataFixtures/AuthorFixtures.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
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 Generator;
use Symfony\Component\Console\Helper\ProgressBar;

Expand All @@ -20,6 +22,10 @@ final class AuthorFixtures extends AbstractFixtures
public const string AUTHOR_2 = '19a0dba5-459b-422e-ac8e-a3c1cbd20d36';
public const string AUTHOR_3 = '7470b436-6e03-4417-9b92-50af90aa09bf';

public const string AUTHOR_4 = '7470b436-6e03-4427-9b92-50af90aa09bf';
public const string AUTHOR_5 = '7470b436-6e03-4437-9b92-50af90aa09bf';
public const string AUTHOR_6 = '7470b436-6e03-4447-9b92-50af90aa09bf';

public function __construct(
private readonly AuthorManager $manager,
) {
Expand Down Expand Up @@ -71,6 +77,33 @@ private function getData(): Generator
->setName('Malka Raisa')
->setExtSystem($cmsExtSystem);
$author->getFlags()->setReviewed(true);

yield $author;

$author5 = (new Author())
->setId(self::AUTHOR_5)
->setType(AuthorType::Agency)
->setName('AgencyA')
->setExtSystem($cmsExtSystem);
$author5->getFlags()->setReviewed(true);

yield $author5;

$author6 = (new Author())
->setId(self::AUTHOR_6)
->setName('AuthorB')
->setExtSystem($cmsExtSystem);
$author6->getFlags()->setReviewed(true);

yield $author6;

$childAuthor = (new Author())
->setId(self::AUTHOR_4)
->setName('AgencyA/AuthorB')
->setCurrentAuthors(CollectionHelper::newCollection([$author5, $author6]))
->setExtSystem($cmsExtSystem);
$childAuthor->getFlags()->setReviewed(false);

yield $childAuthor;
}
}
5 changes: 4 additions & 1 deletion src/Domain/Asset/AssetManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace AnzuSystems\CoreDamBundle\Domain\Asset;

use AnzuSystems\CoreDamBundle\Domain\AbstractManager;
use AnzuSystems\CoreDamBundle\Domain\Author\AuthorProvider;
use AnzuSystems\CoreDamBundle\Entity\Asset;
use AnzuSystems\CoreDamBundle\Model\Dto\Asset\AssetAdmUpdateDto;
use AnzuSystems\CoreDamBundle\Model\Dto\Asset\FormProvidableMetadataBulkUpdateDto;
Expand All @@ -14,7 +15,8 @@
class AssetManager extends AbstractManager
{
public function __construct(
private readonly AssetPropertiesRefresher $propertiesRefresher
private readonly AssetPropertiesRefresher $propertiesRefresher,
private readonly AuthorProvider $authorProvider,
) {
}

Expand Down Expand Up @@ -88,6 +90,7 @@ public function updateFromMetadataBulkDto(
oldCollection: $asset->getAuthors(),
newCollection: $dto->getAuthors(),
);
$this->authorProvider->provideCurrentAuthorToColl($asset);

return $this->updateExisting($asset, $flush);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Domain/Asset/AssetSysFacade.php
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ public function setupKeywords(AssetFile $assetFile, AssetFileSysUrlCreateDto $dt
public function setupAuthors(AssetFile $assetFile, AssetFileSysUrlCreateDto $dto): void
{
foreach ($dto->getAuthors() as $authorName) {
$author = $this->authorProvider->provideAuthor($authorName, $assetFile->getExtSystem());
$author = $this->authorProvider->provideByTitle($authorName, $assetFile->getExtSystem());
if ($author instanceof Author) {
$assetFile->getAsset()->addAuthor($author);
}
Expand Down
52 changes: 52 additions & 0 deletions src/Domain/Author/AuthorManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,22 @@

use AnzuSystems\CoreDamBundle\Domain\AbstractManager;
use AnzuSystems\CoreDamBundle\Entity\Author;
use Doctrine\Common\Collections\Collection;

final class AuthorManager extends AbstractManager
{
public function create(Author $author, bool $flush = true): Author
{
$this->trackCreation($author);
$this->entityManager->persist($author);

foreach ($author->getChildAuthors() as $childAuthor) {
$childAuthor->addCurrentAuthor($author);
}
foreach ($author->getCurrentAuthors() as $childAuthor) {
$childAuthor->addChildAuthor($author);
}

$this->flush($flush);

return $author;
Expand All @@ -27,6 +36,49 @@ public function update(Author $author, Author $newAuthor, bool $flush = true): A
->setFlags($newAuthor->getFlags())
->setType($newAuthor->getType())
;

$this->colUpdate(
oldCollection: $author->getChildAuthors(),
newCollection: $newAuthor->getChildAuthors(),
addElementFn: function (Collection $oldCollection, Author $newChildAuthor) use ($author): bool {
if (false === $oldCollection->contains($newChildAuthor)) {
$oldCollection->add($newChildAuthor);
}
$newChildAuthor->addCurrentAuthor($author);

return true;
},
removeElementFn: function (Collection $oldCollection, Author $oldChildAuthor) use ($author): bool {
if ($oldCollection->contains($oldChildAuthor)) {
$oldCollection->removeElement($oldChildAuthor);
}
$oldChildAuthor->removeCurrentAuthor($author);

return true;
}
);

$this->colUpdate(
oldCollection: $author->getCurrentAuthors(),
newCollection: $newAuthor->getCurrentAuthors(),
addElementFn: function (Collection $oldCollection, Author $newCurrentAuthor) use ($author): bool {
if (false === $oldCollection->contains($newCurrentAuthor)) {
$oldCollection->add($newCurrentAuthor);
}
$newCurrentAuthor->addChildAuthor($author);

return true;
},
removeElementFn: function (Collection $oldCollection, Author $oldCurrentAuthor) use ($author): bool {
if ($oldCollection->contains($oldCurrentAuthor)) {
$oldCollection->removeElement($oldCurrentAuthor);
}
$oldCurrentAuthor->removeChildAuthor($author);

return true;
}
);

$this->flush($flush);

return $author;
Expand Down
25 changes: 24 additions & 1 deletion src/Domain/Author/AuthorProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace AnzuSystems\CoreDamBundle\Domain\Author;

use AnzuSystems\CoreDamBundle\Entity\Asset;
use AnzuSystems\CoreDamBundle\Entity\Author;
use AnzuSystems\CoreDamBundle\Entity\ExtSystem;
use AnzuSystems\CoreDamBundle\Helper\StringHelper;
Expand All @@ -17,7 +18,7 @@ public function __construct(
) {
}

public function provideAuthor(string $title, ExtSystem $extSystem): ?Author
public function provideByTitle(string $title, ExtSystem $extSystem): ?Author
{
$title = StringHelper::parseString(input: $title, length: Author::NAME_MAX_LENGTH);
if (empty($title)) {
Expand All @@ -39,4 +40,26 @@ public function provideAuthor(string $title, ExtSystem $extSystem): ?Author
->setName($title),
);
}

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);
}

if (false === $assetAuthor->getFlags()->isReviewed()) {
$asset->getAuthors()->removeElement($assetAuthor);
}
}

return $changedCurrentAuthors;
}
}
110 changes: 110 additions & 0 deletions src/Domain/Job/Processor/JobAuthorCurrentOptimizeProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?php

declare(strict_types=1);

namespace AnzuSystems\CoreDamBundle\Domain\Job\Processor;

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\Model\ValueObject\JobAuthorCurrentOptimizeResult;
use AnzuSystems\CoreDamBundle\Repository\AssetRepository;
use AnzuSystems\CoreDamBundle\Repository\AuthorRepository;
use AnzuSystems\CoreDamBundle\Repository\JobImageCopyItemRepository;
use Doctrine\Common\Collections\Collection;
use Throwable;

final class JobAuthorCurrentOptimizeProcessor extends AbstractJobProcessor
{
use EntityManagerAwareTrait;

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,
) {
}

public static function getSupportedJob(): string
{
return JobAuthorCurrentOptimize::class;
}

public function setBulkSize(int $bulkSize): void
{
$this->bulkSize = $bulkSize;
}

/**
* @param JobAuthorCurrentOptimize $job
*/
public function process(JobInterface $job): void
{
$this->start($job);

try {
$job->isProcessAll()
? $this->processAll($job)
: $this->processAuthor($job)
;
$this->entityManager->clear();
} catch (Throwable $e) {
$this->finishFail($job, $e->getMessage());
}
}

private function processAll(JobAuthorCurrentOptimize $job): void
{
$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<int, Asset> $assets
*/
private function processAssetsCollection(JobAuthorCurrentOptimize $job, Collection $assets, string $lastId = ''): void
{
$changedAuthorsCount = 0;
foreach ($assets as $asset) {
if ($this->authorProvider->provideCurrentAuthorToColl($asset)) {
$changedAuthorsCount++;
}
$lastId = (string) $asset->getId();
}

$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);
}
}
Loading