Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,17 @@
use Pimcore\Bundle\StaticResolverBundle\Models\User\UserResolverInterface;
use Pimcore\Bundle\StudioBackendBundle\Element\ExecutionEngine\AutomationAction\Messenger\Messages\BatchDeleteMessage;
use Pimcore\Bundle\StudioBackendBundle\Element\Service\ElementDeleteServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Element\Service\ExecutionEngine\DeleteServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\AutomationAction\AbstractHandler;
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\Util\Config;
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\Util\StepConfig;
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\Util\Trait\HandlerProgressTrait;
use Pimcore\Bundle\StudioBackendBundle\Mercure\Service\PublishServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Mercure\Service\UserTopicServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Util\Trait\ElementProviderTrait;
use Pimcore\Model\Element\ElementInterface;
use Pimcore\Model\UserInterface;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use function count;

/**
* @internal
Expand Down Expand Up @@ -67,44 +69,71 @@ public function __invoke(BatchDeleteMessage $message): void
));
}

$type = $this->extractConfigFieldFromJobStepConfig(
$elementType = $this->extractConfigFieldFromJobStepConfig(
$message,
DeleteServiceInterface::ELEMENT_TYPE_TO_DELETE
StepConfig::ELEMENT_TYPE_TO_BATCH_DELETE->value
);
$id = $this->extractConfigFieldFromJobStepConfig($message, DeleteServiceInterface::ELEMENT_TO_DELETE);
$parentElement = $this->elementService->getElementById($this->getCoreElementType($type), $id);
$items = $this->extractConfigFieldFromJobStepConfig(
$message,
StepConfig::ITEMS_TO_BATCH_DELETE->value
);
$totalItems = count($items);
$stepName = $this->getJobStep($message)->getName();

if ($parentElement instanceof ElementInterface) {
try {
$this->elementDeleteService->processBatchDelete($parentElement, $user, $type);
} catch (Exception $exception) {
$this->abort($this->getAbortData(
Config::ELEMENT_BATCH_DELETE_FAILED_MESSAGE->value,
[
'type' => $parentElement->getType(),
'id' => $parentElement->getId(),
'message' => $exception->getMessage(),
],
));
foreach ($items as $elementId) {
$element = $this->elementService->getElementById(
$this->getCoreElementType($elementType),
$elementId
);

if ($element instanceof ElementInterface) {
$this->deleteBatchElement($element, $user, $elementType);
}

$this->updateProgress(
$this->publishService,
$this->userTopicService,
$jobRun,
$stepName,
$totalItems,
100,
);
}
}

$this->updateProgress(
$this->publishService,
$this->userTopicService,
$jobRun,
$this->getJobStep($message)->getName()
);
/**
* @throws Exception
*/
private function deleteBatchElement(
ElementInterface $element,
UserInterface $user,
string $elementType
): void {
try {
$this->elementDeleteService->processBatchDelete($element, $user, $elementType);
} catch (Exception $exception) {
$this->abort($this->getAbortData(
Config::ELEMENT_BATCH_DELETE_FAILED_MESSAGE->value,
[
'type' => $element->getType(),
'id' => $element->getId(),
'message' => $exception->getMessage(),
],
));
}
}

protected function configureStep(): void
{
$this->stepConfiguration->setRequired(DeleteServiceInterface::ELEMENT_TO_DELETE);
$this->stepConfiguration->setAllowedTypes(DeleteServiceInterface::ELEMENT_TO_DELETE, 'int');
$this->stepConfiguration->setRequired(DeleteServiceInterface::ELEMENT_TYPE_TO_DELETE);
$this->stepConfiguration->setRequired(StepConfig::ITEMS_TO_BATCH_DELETE->value);
$this->stepConfiguration->setAllowedTypes(
StepConfig::ITEMS_TO_BATCH_DELETE->value,
StepConfig::CONFIG_TYPE_ARRAY->value
);
$this->stepConfiguration->setRequired(StepConfig::ELEMENT_TYPE_TO_BATCH_DELETE->value);
$this->stepConfiguration->setAllowedTypes(
DeleteServiceInterface::ELEMENT_TYPE_TO_DELETE,
'string'
StepConfig::ELEMENT_TYPE_TO_BATCH_DELETE->value,
StepConfig::CONFIG_TYPE_STRING->value
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,18 @@
use Pimcore\Bundle\StudioBackendBundle\Element\ExecutionEngine\AutomationAction\Messenger\Messages\ElementDeleteMessage;
use Pimcore\Bundle\StudioBackendBundle\Element\Service\ElementDeleteServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Element\Service\ElementServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Element\Service\ExecutionEngine\DeleteServiceInterface;
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\ExecutionEngine\Util\StepConfig;
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\Util\Trait\HandlerProgressTrait;
use Pimcore\Bundle\StudioBackendBundle\Mercure\Service\PublishServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Mercure\Service\UserTopicServiceInterface;
use Pimcore\Model\Element\ElementInterface;
use Pimcore\Model\Element\ElementDescriptor;
use Pimcore\Model\UserInterface;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use function count;

/**
* @internal
Expand Down Expand Up @@ -68,40 +71,60 @@ public function __invoke(ElementDeleteMessage $message): void

$user = $validatedParameters->getUser();
$parentElement = $validatedParameters->getSubject();
$element = $this->getElementById(
new ElementDescriptor(
$parentElement->getType(),
$this->extractConfigFieldFromJobStepConfig($message, DeleteServiceInterface::ELEMENT_TO_DELETE)
),
$user,
$this->elementService

$items = $this->extractConfigFieldFromJobStepConfig(
$message,
StepConfig::ITEMS_TO_DELETE->value
);
$totalItems = count($items);
$stepName = $this->getJobStep($message)->getName();

if ($element->getId() === $parentElement->getId()) {
try {
$this->elementDeleteService->deleteParentElement($element, $user);
$this->updateProgress(
$this->publishService,
$this->userTopicService,
$jobRun,
$this->getJobStep($message)->getName()
);
} catch (Exception $exception) {
$this->abort($this->getAbortData(
Config::ELEMENT_DELETE_FAILED_MESSAGE->value,
[
'type' => $element->getType(),
'id' => $element->getId(),
'message' => $exception->getMessage(),
],
));
}
foreach ($items as $elementId) {
$element = $this->getElementById(
new ElementDescriptor($parentElement->getType(), $elementId),
$user,
$this->elementService
);

return;
$this->deleteElement($element, $parentElement->getId(), $user);

$this->updateProgress(
$this->publishService,
$this->userTopicService,
$jobRun,
$stepName,
$totalItems,
100,
);
}
}

protected function configureStep(): void
{
$this->stepConfiguration->setRequired(StepConfig::ITEMS_TO_DELETE->value);
$this->stepConfiguration->setAllowedTypes(
StepConfig::ITEMS_TO_DELETE->value,
StepConfig::CONFIG_TYPE_ARRAY->value
);
}



/**
* @throws Exception
*/
private function deleteElement(
ElementInterface $element,
int $parentId,
UserInterface $user
): void {
$isParent = $element->getId() === $parentId;

try {
$this->elementDeleteService->deleteElement($element, $user);
match ($isParent) {
true => $this->elementDeleteService->deleteParentElement($element, $user),
false => $this->elementDeleteService->deleteElement($element, $user, true),
};
} catch (Exception $exception) {
$this->abort($this->getAbortData(
Config::ELEMENT_DELETE_FAILED_MESSAGE->value,
Expand All @@ -112,18 +135,5 @@ public function __invoke(ElementDeleteMessage $message): void
],
));
}

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

protected function configureStep(): void
{
$this->stepConfiguration->setRequired(DeleteServiceInterface::ELEMENT_TO_DELETE);
$this->stepConfiguration->setAllowedTypes(DeleteServiceInterface::ELEMENT_TO_DELETE, 'int');
}
}
12 changes: 5 additions & 7 deletions src/Element/Service/ElementDeleteService.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,8 @@ public function deleteParentElement(
*/
public function deleteElement(
ElementInterface $element,
UserInterface $user
UserInterface $user,
bool $skipChildrenCheck = false
): void {

/** @var User $user because of the core method */
Expand All @@ -165,14 +166,11 @@ public function deleteElement(
}

if ($element->isLocked()) {
throw new ForbiddenException(sprintf('Element %s is locked', $element->getId())
);
throw new ForbiddenException(sprintf('Element %s is locked', $element->getId()));
}

if ($this->elementService->hasElementChildren($element)) {
throw new EnvironmentException(
'Element has existing children'
);
if (!$skipChildrenCheck && $this->elementService->hasElementChildren($element)) {
throw new EnvironmentException('Element has existing children');
}

try {
Expand Down
5 changes: 3 additions & 2 deletions src/Element/Service/ElementDeleteServiceInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,12 @@ public function deleteParentElement(
): void;

/**
* @throws ElementDeletionFailedException|EnvironmentException
* @throws ElementDeletionFailedException|EnvironmentException|ForbiddenException
*/
public function deleteElement(
ElementInterface $element,
UserInterface $user
UserInterface $user,
bool $skipChildrenCheck = false
): void;

public function addElementToRecycleBin(
Expand Down
57 changes: 30 additions & 27 deletions src/Element/Service/ExecutionEngine/DeleteService.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidElementTypeException;
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\Util\Config;
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\Util\Jobs;
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\Util\StepConfig;
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\Util\Trait\ChunkGeneratorTrait;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\ElementTypes;
use Pimcore\Model\Element\ElementDescriptor;
use Pimcore\Model\Element\ElementInterface;
Expand All @@ -33,6 +35,10 @@
*/
final readonly class DeleteService implements DeleteServiceInterface
{
use ChunkGeneratorTrait;

private const int DELETE_BATCH_SIZE = 500;

public function __construct(
private JobExecutionAgentInterface $jobExecutionAgent
) {
Expand All @@ -55,30 +61,22 @@ public function deleteElementsWithExecutionEngine(
);
}

$jobSteps = array_merge(
$jobSteps,
array_map(
static fn (int $id) => new JobStep(
JobSteps::ELEMENT_DELETION->value,
ElementDeleteMessage::class,
'',
[self::ELEMENT_TO_DELETE => $id]
),
$childrenIds
)
);
// Append parent ID to the end so it's deleted last
$allIds = array_merge($childrenIds, [$element->getId()]);

$jobSteps[] = new JobStep(
JobSteps::ELEMENT_DELETION->value,
ElementDeleteMessage::class,
'',
[self::ELEMENT_TO_DELETE => $element->getId()]
);
foreach ($this->chunkGenerator($allIds, self::DELETE_BATCH_SIZE) as $batch) {
$jobSteps[] = new JobStep(
JobSteps::ELEMENT_DELETION->value,
ElementDeleteMessage::class,
'',
[StepConfig::ITEMS_TO_DELETE->value => $batch],
);
}

$job = new Job(
name: $this->getJobName($elementType),
steps: $jobSteps,
selectedElements:[
selectedElements: [
new ElementDescriptor(
$elementType,
$element->getId()
Expand All @@ -100,18 +98,23 @@ public function batchDeleteElements(
UserInterface $user,
string $elementType,
): int {
$jobSteps = array_map(
static fn (ElementInterface $element) => new JobStep(
$elementIds = array_map(
static fn (ElementInterface $element) => $element->getId(),
$elements
);

$jobSteps = [];
foreach ($this->chunkGenerator($elementIds, self::DELETE_BATCH_SIZE) as $batch) {
$jobSteps[] = new JobStep(
JobSteps::ELEMENT_DELETION->value,
BatchDeleteMessage::class,
'',
[
self::ELEMENT_TO_DELETE => $element->getId(),
self::ELEMENT_TYPE_TO_DELETE => $elementType,
]
),
$elements
);
StepConfig::ITEMS_TO_BATCH_DELETE->value => $batch,
StepConfig::ELEMENT_TYPE_TO_BATCH_DELETE->value => $elementType,
],
);
}

$job = new Job(
name: $this->getBatchJobName($elementType),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@
*/
interface DeleteServiceInterface
{
public const string ELEMENT_TO_DELETE = 'element_to_delete';

public const string ELEMENT_TYPE_TO_DELETE = 'element_type_to_delete';

public function deleteElementsWithExecutionEngine(
ElementInterface $element,
UserInterface $user,
Expand Down
Loading
Loading