Skip to content

Commit

Permalink
Asset List Batch Edit (#238)
Browse files Browse the repository at this point in the history
* adapt list batch patch to use GEE

* add missing subscriber

* Apply php-cs-fixer changes

---------

Co-authored-by: lukmzig <lukmzig@users.noreply.github.com>
  • Loading branch information
lukmzig and lukmzig authored Jul 9, 2024
1 parent 2e129f3 commit 83e5e61
Show file tree
Hide file tree
Showing 27 changed files with 570 additions and 49 deletions.
23 changes: 22 additions & 1 deletion config/elements.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,25 @@ services:
class: Pimcore\Bundle\StudioBackendBundle\Element\Service\ElementDeleteService

Pimcore\Bundle\StudioBackendBundle\Element\Service\ElementFolderServiceInterface:
class: Pimcore\Bundle\StudioBackendBundle\Element\Service\ElementFolderService
class: Pimcore\Bundle\StudioBackendBundle\Element\Service\ElementFolderService


#
# Handler
#

Pimcore\Bundle\StudioBackendBundle\Element\ExecutionEngine\AutomationAction\Messenger\Handler\PatchHandler: ~


#
# Event Subscriber
#

Pimcore\Bundle\StudioBackendBundle\Element\EventSubscriber\PatchSubscriber: ~

#
# Mercure SSE
#

Pimcore\Bundle\StudioBackendBundle\Element\Mercure\Provider\ElementTopicProvider:
tags: [ 'pimcore.studio_backend.mercure.topic.provider' ]
10 changes: 10 additions & 0 deletions config/patcher.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ services:
Pimcore\Bundle\StudioBackendBundle\Patcher\Service\PatchServiceInterface:
class: Pimcore\Bundle\StudioBackendBundle\Patcher\Service\PatchService

#
# Adapters
#

Pimcore\Bundle\StudioBackendBundle\Patcher\Adapter\ParentIdAdapter:
tags : ['pimcore.studio_backend.patch_adapter']

Pimcore\Bundle\StudioBackendBundle\Patcher\Adapter\KeyAdapter:
tags : ['pimcore.studio_backend.patch_adapter']

Pimcore\Bundle\StudioBackendBundle\Patcher\Adapter\LockAdapter:
tags : ['pimcore.studio_backend.patch_adapter']

3 changes: 2 additions & 1 deletion config/pimcore/execution_engine.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ framework:
Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\AutomationAction\Messenger\Messages\AssetCloneMessage: pimcore_generic_execution_engine
Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\AutomationAction\Messenger\Messages\AssetDeleteMessage: pimcore_generic_execution_engine
Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\AutomationAction\Messenger\Messages\AssetUploadMessage: pimcore_generic_execution_engine
Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\AutomationAction\Messenger\Messages\ZipUploadMessage: pimcore_generic_execution_engine
Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\AutomationAction\Messenger\Messages\ZipUploadMessage: pimcore_generic_execution_engine
Pimcore\Bundle\StudioBackendBundle\Element\ExecutionEngine\AutomationAction\Messenger\Messages\PatchMessage: pimcore_generic_execution_engine
38 changes: 32 additions & 6 deletions src/Asset/Controller/PatchController.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,17 @@
use Pimcore\Bundle\StudioBackendBundle\Asset\Attributes\Request\PatchAssetRequestBody;
use Pimcore\Bundle\StudioBackendBundle\Asset\MappedParameter\PatchAssetParameter;
use Pimcore\Bundle\StudioBackendBundle\Controller\AbstractApiController;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\Content\PatchErrorJson;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\AccessDeniedException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ElementSavingFailedException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotFoundException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\UserNotFoundException;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\Content\IdJson;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\CreatedResponse;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\DefaultResponses;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\PatchSuccessResponseWithErrors;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\SuccessResponse;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Config\Tags;
use Pimcore\Bundle\StudioBackendBundle\Patcher\Service\PatchServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Security\Service\SecurityServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Util\Constants\ElementTypes;
use Pimcore\Bundle\StudioBackendBundle\Util\Constants\HttpResponseCodes;
use Pimcore\Bundle\StudioBackendBundle\Util\Constants\UserPermissions;
Expand All @@ -43,10 +48,14 @@ final class PatchController extends AbstractApiController
public function __construct(
SerializerInterface $serializer,
private readonly PatchServiceInterface $patchService,
private readonly SecurityServiceInterface $securityService
) {
parent::__construct($serializer);
}

/**
* @throws AccessDeniedException|ElementSavingFailedException|NotFoundException|UserNotFoundException
*/
#[Route('/assets', name: 'pimcore_studio_api_patch_asset', methods: ['PATCH'])]
#[IsGranted(UserPermissions::ASSETS->value)]
#[Patch(
Expand All @@ -57,16 +66,33 @@ public function __construct(
tags: [Tags::Assets->name]
)]
#[PatchAssetRequestBody]
#[SuccessResponse]
#[PatchSuccessResponseWithErrors(content: new PatchErrorJson())]
#[SuccessResponse(
description: 'Successfully patched asset',
)]
#[CreatedResponse(
description: 'Successfully created jobRun for patching multiple assets',
content: new IdJson('ID of created jobRun')
)]
#[DefaultResponses([
HttpResponseCodes::UNAUTHORIZED,
HttpResponseCodes::NOT_FOUND,
])]
public function patchAssets(#[MapRequestPayload] PatchAssetParameter $patchAssetParameter): Response
{
$errors = $this->patchService->patch(ElementTypes::TYPE_ASSET, $patchAssetParameter->getData());
$status = HttpResponseCodes::SUCCESS->value;
$data = null;
$jobRunId = $this->patchService->patch(
ElementTypes::TYPE_ASSET,
$patchAssetParameter->getData(),
$this->securityService->getCurrentUser()
);

if ($jobRunId) {
$status = HttpResponseCodes::CREATED->value;

return $this->jsonResponse(['id' => $jobRunId], $status);
}

return $this->patchResponse($errors);
return new Response($data, $status);
}
}
2 changes: 1 addition & 1 deletion src/Asset/EventSubscriber/CloneSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public function onStateChanged(JobRunStateChangedEvent $event): void
$event->getJobName() === Jobs::CLONE_ASSETS->value
) {
$this->publishService->publish(
Events::DELETION_FINISHED->value,
Events::CLONING_FINISHED->value,
new Finished(
$event->getJobRunId(),
$event->getJobName(),
Expand Down
2 changes: 1 addition & 1 deletion src/Asset/EventSubscriber/DeletionSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public static function getSubscribedEvents(): array

public function onStateChanged(JobRunStateChangedEvent $event): void
{
if ($event->getJobName() !== Jobs::DELETE_ASSETS->value) {
if ($event->getJobName() !== Jobs::DELETE_ASSETS->value) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\Util\Config;
use Pimcore\Bundle\StudioBackendBundle\Grid\Service\GridServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Mercure\Service\PublishServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Translation\Service\TranslatorService;
use Pimcore\Bundle\StudioBackendBundle\Util\Constants\ElementPermissions;
use Pimcore\Bundle\StudioBackendBundle\Util\Constants\ElementTypes;
use Pimcore\Bundle\StudioBackendBundle\Util\Traits\HandlerProgressTrait;
Expand Down Expand Up @@ -68,12 +67,7 @@ public function __invoke(CsvCreationMessage $message): void
);

if ($validatedParameters instanceof AbortActionData) {
$this->abortAction(
$validatedParameters->getTranslationKey(),
$validatedParameters->getTranslationParameters(),
TranslatorService::DOMAIN,
$validatedParameters->getExceptionClassName()
);
$this->abort($validatedParameters);
}

$context = $jobRun->getContext();
Expand Down
1 change: 1 addition & 0 deletions src/Asset/ExecutionEngine/Util/JobSteps.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@ enum JobSteps: string
case ASSET_UPLOADING = 'studio_ee_job_step_asset_uploading';
case CSV_COLLECTION = 'studio_ee_job_step_csv_collection';
case CSV_CREATION = 'studio_ee_job_step_csv_creation';
case ELEMENT_PATCHING = 'studio_ee_job_step_element_patching';
}
2 changes: 0 additions & 2 deletions src/Asset/Mercure/Events.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,4 @@ enum Events: string
case DELETION_FINISHED = 'deletion-finished';
case CLONING_FINISHED = 'cloning-finished';
case ASSET_UPLOAD_FINISHED = 'asset-upload-finished';
case FINISHED_WITH_ERRORS = 'job-finished-with-errors';
case FAILED = 'job-failed';
}
3 changes: 2 additions & 1 deletion src/Asset/Mercure/Provider/AssetTopicProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@

use Pimcore\Bundle\StudioBackendBundle\Asset\Mercure\Events as AssetEvents;
use Pimcore\Bundle\StudioBackendBundle\Mercure\Provider\AbstractServerToClientProvider;
use Pimcore\Bundle\StudioBackendBundle\Mercure\Service\Loader\TaggedIteratorAdapter;
use Pimcore\Bundle\StudioBackendBundle\Mercure\Util\Events;
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;

/**
* @internal
*/
#[AutoconfigureTag('pimcore.studio_backend.mercure.topic.provider')]
#[AutoconfigureTag(TaggedIteratorAdapter::TOPIC_LOADER_TAG)]
final class AssetTopicProvider extends AbstractServerToClientProvider
{
public function getClientSubscribableTopic(): array
Expand Down
3 changes: 3 additions & 0 deletions src/Asset/Patcher/Adapter/MetadataAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@
namespace Pimcore\Bundle\StudioBackendBundle\Asset\Patcher\Adapter;

use Pimcore\Bundle\StudioBackendBundle\Patcher\Service\Loader\PatchAdapterInterface;
use Pimcore\Bundle\StudioBackendBundle\Patcher\Service\Loader\TaggedIteratorAdapter;
use Pimcore\Bundle\StudioBackendBundle\Util\Constants\ElementTypes;
use Pimcore\Model\Asset;
use Pimcore\Model\Element\ElementInterface;
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;
use function array_key_exists;

/**
* @internal
*/
#[AutoconfigureTag(TaggedIteratorAdapter::ADAPTER_TAG)]
final class MetadataAdapter implements PatchAdapterInterface
{
private const INDEX_KEY = 'metadata';
Expand Down
71 changes: 71 additions & 0 deletions src/Element/EventSubscriber/PatchSubscriber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php
declare(strict_types=1);

/**
* Pimcore
*
* This source file is available under two different licenses:
* - GNU General Public License version 3 (GPLv3)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license http://www.pimcore.org/license GPLv3 and PCL
*/

namespace Pimcore\Bundle\StudioBackendBundle\Element\EventSubscriber;

use Pimcore\Bundle\GenericExecutionEngineBundle\Event\JobRunStateChangedEvent;
use Pimcore\Bundle\GenericExecutionEngineBundle\Model\JobRunStates;
use Pimcore\Bundle\StudioBackendBundle\Element\Mercure\Events;
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\Service\EventSubscriberServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\Util\Jobs;
use Pimcore\Bundle\StudioBackendBundle\Mercure\Schema\ExecutionEngine\Finished;
use Pimcore\Bundle\StudioBackendBundle\Mercure\Service\PublishServiceInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
* @internal
*/
final readonly class PatchSubscriber implements EventSubscriberInterface
{
public function __construct(
private EventSubscriberServiceInterface $eventSubscriberService,
private PublishServiceInterface $publishService,
) {

}

public static function getSubscribedEvents(): array
{
return [
JobRunStateChangedEvent::class => 'onStateChanged',
];
}

public function onStateChanged(JobRunStateChangedEvent $event): void
{
if ($event->getJobName() !== Jobs::PATCH_ELEMENTS->value) {
return;
}

match ($event->getNewState()) {
JobRunStates::FINISHED->value => $this->publishService->publish(
Events::PATCH_FINISHED->value,
new Finished(
$event->getJobRunId(),
$event->getJobName(),
$event->getJobRunOwnerId(),
$event->getNewState()
)
),
JobRunStates::FINISHED_WITH_ERRORS->value => $this->eventSubscriberService->handleFinishedWithErrors(
$event->getJobRunId(),
$event->getJobRunOwnerId(),
$event->getJobName()
),
default => null,
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php
declare(strict_types=1);

/**
* Pimcore
*
* This source file is available under two different licenses:
* - GNU General Public License version 3 (GPLv3)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license http://www.pimcore.org/license GPLv3 and PCL
*/

namespace Pimcore\Bundle\StudioBackendBundle\Element\ExecutionEngine\AutomationAction\Messenger\Handler;

use Exception;
use Pimcore\Bundle\StaticResolverBundle\Models\User\UserResolverInterface;
use Pimcore\Bundle\StudioBackendBundle\Element\ExecutionEngine\AutomationAction\Messenger\Messages\PatchMessage;
use Pimcore\Bundle\StudioBackendBundle\Element\Service\ElementServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\AutomationAction\AbstractHandler;
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\Model\AbortActionData;
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\Util\Config;
use Pimcore\Bundle\StudioBackendBundle\Mercure\Service\PublishServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Patcher\Service\PatchServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Util\Traits\ElementProviderTrait;
use Pimcore\Bundle\StudioBackendBundle\Util\Traits\HandlerProgressTrait;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;

/**
* @internal
*/
#[AsMessageHandler]
final class PatchHandler extends AbstractHandler
{
use ElementProviderTrait;
use HandlerProgressTrait;

public function __construct(
private readonly PatchServiceInterface $patchService,
private readonly PublishServiceInterface $publishService,
private readonly ElementServiceInterface $elementService,
private readonly UserResolverInterface $userResolver,
) {
parent::__construct();
}

/**
* @throws Exception
*/
public function __invoke(PatchMessage $message): void
{
$jobRun = $this->getJobRun($message);

$validatedParameters = $this->validateJobParameters(
$message,
$jobRun,
$this->userResolver,
);

if ($validatedParameters instanceof AbortActionData) {
$this->abort($validatedParameters);
}

$element = $this->getElementById(
$validatedParameters->getSubject(),
$validatedParameters->getUser(),
$this->elementService
);
$elementId = $element->getId();
$elementType = $this->getElementType($element);
$jobEnvironmentData = $jobRun->getJob()?->getEnvironmentData();
if (!isset($jobEnvironmentData[(string)$elementId])) {
$this->abort($this->getAbortData(
Config::ELEMENT_PATCH_FAILED_MESSAGE->value,
[
'type' => $elementType,
'id' => $element->getId(),
'message' => Config::NO_ELEMENT_DATA_FOUND->value,
],
));
}

try {
$this->patchService->patchElement($element, $elementType, $jobEnvironmentData[$elementId]);
} catch (Exception $exception) {
$this->abort($this->getAbortData(
Config::ELEMENT_PATCH_FAILED_MESSAGE->value,
[
'type' => $elementType,
'id' => $elementId,
'message' => $exception->getMessage(),
],
));
}

$this->updateProgress($this->publishService, $jobRun, $this->getJobStep($message)->getName());
}
}
Loading

0 comments on commit 83e5e61

Please sign in to comment.