Skip to content

Commit

Permalink
[Task] Add batch edit based on folder ids (#496)
Browse files Browse the repository at this point in the history
* Add batch edit for folders

* Apply php-cs-fixer changes

* Split lines

* Add translations and refactor to use gridsearch and filters

* Apply php-cs-fixer changes

* Add type infos

---------

Co-authored-by: mattamon <[email protected]>
  • Loading branch information
mattamon and mattamon authored Oct 17, 2024
1 parent ac8bfc4 commit ee153b7
Show file tree
Hide file tree
Showing 28 changed files with 843 additions and 4 deletions.
7 changes: 7 additions & 0 deletions config/data_index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ services:
$assetHydratorLocator: '@open_search.asset_hydrator.service_locator'
$dataObjectHydratorLocator: '@open_search.data_object_hydrator.service_locator'

# Elements

Pimcore\Bundle\StudioBackendBundle\DataIndex\ElementSearchServiceInterface:
class: Pimcore\Bundle\StudioBackendBundle\DataIndex\ElementSearchService

# Assets
Pimcore\Bundle\StudioBackendBundle\DataIndex\AssetSearchServiceInterface:
Expand Down Expand Up @@ -72,6 +76,9 @@ services:
Pimcore\Bundle\StudioBackendBundle\DataIndex\DocumentSearchServiceInterface:
class: Pimcore\Bundle\StudioBackendBundle\DataIndex\DocumentSearchService

Pimcore\Bundle\StudioBackendBundle\DataIndex\Provider\DocumentQueryProviderInterface:
class: Pimcore\Bundle\StudioBackendBundle\DataIndex\Provider\DocumentQueryProvider


#Service Locator
open_search.asset_hydrator.service_locator:
Expand Down
2 changes: 1 addition & 1 deletion config/elements.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ services:
Pimcore\Bundle\StudioBackendBundle\Element\ExecutionEngine\AutomationAction\Messenger\Handler\RecycleBinHandler: ~
Pimcore\Bundle\StudioBackendBundle\Element\ExecutionEngine\AutomationAction\Messenger\Handler\RewriteRefHandler: ~
Pimcore\Bundle\StudioBackendBundle\Element\ExecutionEngine\AutomationAction\Messenger\Handler\PatchHandler: ~

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

#
# Event Subscriber
Expand Down
1 change: 1 addition & 0 deletions config/pimcore/execution_engine.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ framework:
Pimcore\Bundle\StudioBackendBundle\Element\ExecutionEngine\AutomationAction\Messenger\Messages\ElementDeleteMessage: pimcore_generic_execution_engine
Pimcore\Bundle\StudioBackendBundle\Element\ExecutionEngine\AutomationAction\Messenger\Messages\RecycleBinMessage: pimcore_generic_execution_engine
Pimcore\Bundle\StudioBackendBundle\Element\ExecutionEngine\AutomationAction\Messenger\Messages\PatchMessage: pimcore_generic_execution_engine
Pimcore\Bundle\StudioBackendBundle\Element\ExecutionEngine\AutomationAction\Messenger\Messages\PatchFolderMessage: pimcore_generic_execution_engine
Pimcore\Bundle\StudioBackendBundle\Element\ExecutionEngine\AutomationAction\Messenger\Messages\RewriteRefMessage: pimcore_generic_execution_engine
Pimcore\Bundle\StudioBackendBundle\DataObject\ExecutionEngine\AutomationAction\Messenger\Messages\CloneMessage: pimcore_generic_execution_engine
73 changes: 73 additions & 0 deletions src/Asset/Attribute/Request/PatchAssetFolderRequestBody.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?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\Asset\Attribute\Request;

use Attribute;
use OpenApi\Attributes\Items;
use OpenApi\Attributes\JsonContent;
use OpenApi\Attributes\Property;
use OpenApi\Attributes\RequestBody;
use Pimcore\Bundle\StudioBackendBundle\Asset\Attribute\Property\CustomMetadata;
use Pimcore\Bundle\StudioBackendBundle\Asset\Schema\PatchCustomMetadata;
use Pimcore\Bundle\StudioBackendBundle\Grid\Schema\Filter;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Property\UpdateIntegerProperty;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Property\UpdateStringProperty;

/**
* @internal
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class PatchAssetFolderRequestBody extends RequestBody
{
public function __construct()
{
parent::__construct(
required: true,
content: new JsonContent(
required: ['data'],
properties: [
new Property(
property: 'data',
type: 'array',
items: new Items(
required: ['folderId'],
properties: [
new Property(
property: 'folderId',
description: 'Folder ID',
type: 'integer',
example: 83
),
new UpdateIntegerProperty('parentId'),
new UpdateStringProperty('key'),
new UpdateStringProperty('locked'),
new CustomMetadata(PatchCustomMetadata::class),
],
type: 'object',
),
),
new Property(
property: 'filters',
ref: Filter::class,
type: 'object'
),
],
type: 'object',
),
);
}
}
89 changes: 89 additions & 0 deletions src/Asset/Controller/PatchFolderController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?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\Asset\Controller;

use OpenApi\Attributes\Patch;
use Pimcore\Bundle\StudioBackendBundle\Asset\Attribute\Request\PatchAssetFolderRequestBody;
use Pimcore\Bundle\StudioBackendBundle\Asset\MappedParameter\PatchFolderParameter;
use Pimcore\Bundle\StudioBackendBundle\Controller\AbstractApiController;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\AccessDeniedException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ElementSavingFailedException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidArgumentException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotFoundException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\UserNotFoundException;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\Content\IdJson;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\CreatedResponse;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\DefaultResponses;
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\Constant\ElementTypes;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\HttpResponseCodes;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\UserPermissions;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Component\Serializer\SerializerInterface;

/**
* @internal
*/
final class PatchFolderController extends AbstractApiController
{
public function __construct(
SerializerInterface $serializer,
private readonly PatchServiceInterface $patchService,
private readonly SecurityServiceInterface $securityService
) {
parent::__construct($serializer);
}

/**
* @throws AccessDeniedException|ElementSavingFailedException
* @throws NotFoundException|UserNotFoundException|InvalidArgumentException
*/
#[Route('/assets/folder', name: 'pimcore_studio_api_patch_asset_folder', methods: ['PATCH'])]
#[IsGranted(UserPermissions::ASSETS->value)]
#[Patch(
path: self::PREFIX . '/assets/folder',
operationId: 'asset_patch_folder_by_id',
description: 'asset_patch_folder_by_id_description',
summary: 'asset_patch_folder_by_id_summary',
tags: [Tags::Assets->name]
)]
#[PatchAssetFolderRequestBody]
#[CreatedResponse(
description: 'asset_patch_by_id_created_response',
content: new IdJson('ID of created jobRun', 'jobRunId')
)]
#[DefaultResponses([
HttpResponseCodes::UNAUTHORIZED,
HttpResponseCodes::NOT_FOUND,
])]
public function assetPatchFolderById(#[MapRequestPayload] PatchFolderParameter $patchFolderParameter): Response
{

$jobRunId = $this->patchService->patchFolder(
ElementTypes::TYPE_ASSET,
$patchFolderParameter,
$this->securityService->getCurrentUser()
);

return $this->jsonResponse(['jobRunId' => $jobRunId], HttpResponseCodes::CREATED->value);
}
}
2 changes: 1 addition & 1 deletion src/Asset/MappedParameter/PatchAssetParameter.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
/**
* @internal
*/
final readonly class PatchAssetParameter
readonly class PatchAssetParameter
{
public function __construct(
private array $data
Expand Down
42 changes: 42 additions & 0 deletions src/Asset/MappedParameter/PatchFolderParameter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?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\Asset\MappedParameter;

use Pimcore\Bundle\StudioBackendBundle\Filter\MappedParameter\FilterParameter;

/**
* @internal
*/
final readonly class PatchFolderParameter extends PatchAssetParameter
{
public function __construct(
private array $data,
private ?FilterParameter $filters,
) {
parent::__construct($data);
}

public function getData(): array
{
return $this->data;
}

public function getFilters(): FilterParameter
{
return $this->filters ?? new FilterParameter();
}
}
16 changes: 16 additions & 0 deletions src/DataIndex/Adapter/DocumentSearchAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@
namespace Pimcore\Bundle\StudioBackendBundle\DataIndex\Adapter;

use Pimcore\Bundle\GenericDataIndexBundle\Exception\DocumentSearchException;
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Sort\Tree\OrderByFullPath;
use Pimcore\Bundle\GenericDataIndexBundle\Service\Search\SearchService\Document\DocumentSearchServiceInterface;
use Pimcore\Bundle\GenericDataIndexBundle\Service\Search\SearchService\SearchResultIdListServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\DataIndex\Hydrator\DocumentHydratorInterface;
use Pimcore\Bundle\StudioBackendBundle\DataIndex\Query\QueryInterface;
use Pimcore\Bundle\StudioBackendBundle\Document\Schema\Document;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotFoundException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\SearchException;
Expand All @@ -32,6 +35,7 @@
final readonly class DocumentSearchAdapter implements DocumentSearchAdapterInterface
{
public function __construct(
private SearchResultIdListServiceInterface $searchResultIdListService,
private DocumentSearchServiceInterface $searchService,
private DocumentHydratorInterface $hydratorService
) {
Expand All @@ -57,4 +61,16 @@ public function getDocumentById(int $id, ?UserInterface $user = null): Document

return $this->hydratorService->hydrate($document);
}

public function fetchDocumentIds(QueryInterface $documentQuery): array
{
try {
$search = $documentQuery->getSearch();
$search->addModifier(new OrderByFullPath());

return $this->searchResultIdListService->getAllIds($search);
} catch (DocumentSearchException) {
throw new SearchException('documents');
}
}
}
3 changes: 3 additions & 0 deletions src/DataIndex/Adapter/DocumentSearchAdapterInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

namespace Pimcore\Bundle\StudioBackendBundle\DataIndex\Adapter;

use Pimcore\Bundle\StudioBackendBundle\DataIndex\Query\QueryInterface;
use Pimcore\Bundle\StudioBackendBundle\Document\Schema\Document;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotFoundException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\SearchException;
Expand All @@ -30,4 +31,6 @@ interface DocumentSearchAdapterInterface
* @throws SearchException|NotFoundException
*/
public function getDocumentById(int $id, ?UserInterface $user = null): Document;

public function fetchDocumentIds(QueryInterface $documentQuery): array;
}
21 changes: 20 additions & 1 deletion src/DataIndex/DocumentSearchService.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
namespace Pimcore\Bundle\StudioBackendBundle\DataIndex;

use Pimcore\Bundle\StudioBackendBundle\DataIndex\Adapter\DocumentSearchAdapterInterface;
use Pimcore\Bundle\StudioBackendBundle\DataIndex\Provider\DocumentQueryProviderInterface;
use Pimcore\Bundle\StudioBackendBundle\DataIndex\Query\DocumentQueryInterface;
use Pimcore\Bundle\StudioBackendBundle\Document\Schema\Document;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotFoundException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\SearchException;
Expand All @@ -28,7 +30,8 @@
final readonly class DocumentSearchService implements DocumentSearchServiceInterface
{
public function __construct(
private DocumentSearchAdapterInterface $documentSearchAdapter
private DocumentSearchAdapterInterface $documentSearchAdapter,
private DocumentQueryProviderInterface $documentQueryProvider,
) {
}

Expand All @@ -39,4 +42,20 @@ public function getDocumentById(int $id, ?UserInterface $user): Document
{
return $this->documentSearchAdapter->getDocumentById($id, $user);
}

public function getChildrenIds(string $parentPath, ?string $sortDirection = null): array
{
$query = $this->documentQueryProvider->createDocumentQuery();
$query->filterPath($parentPath, true, false);
if ($sortDirection) {
$query->orderByPath($sortDirection);
}

return $this->fetchDocumentIds($query);
}

public function fetchDocumentIds(DocumentQueryInterface $documentQuery): array
{
return $this->documentSearchAdapter->fetchDocumentIds($documentQuery);
}
}
2 changes: 2 additions & 0 deletions src/DataIndex/DocumentSearchServiceInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,6 @@ interface DocumentSearchServiceInterface
* @throws SearchException|NotFoundException
*/
public function getDocumentById(int $id, ?UserInterface $user): Document;

public function getChildrenIds(string $parentPath, ?string $sortDirection = null): array;
}
Loading

0 comments on commit ee153b7

Please sign in to comment.