diff --git a/config/versions.yaml b/config/versions.yaml index c1f23297e..c02b5b44d 100644 --- a/config/versions.yaml +++ b/config/versions.yaml @@ -11,8 +11,8 @@ services: public: true tags: [ 'controller.service_arguments' ] - Pimcore\Bundle\StudioBackendBundle\Version\RepositoryInterface: - class: Pimcore\Bundle\StudioBackendBundle\Version\Repository + Pimcore\Bundle\StudioBackendBundle\Version\Repository\VersionRepositoryInterface: + class: Pimcore\Bundle\StudioBackendBundle\Version\Repository\VersionRepository Pimcore\Bundle\StudioBackendBundle\Version\Hydrator\VersionHydratorInterface: class: Pimcore\Bundle\StudioBackendBundle\Version\Hydrator\VersionHydrator @@ -38,15 +38,15 @@ services: class: Pimcore\Bundle\StudioBackendBundle\Version\Publisher\DocumentVersionPublisher # Services - Pimcore\Bundle\StudioBackendBundle\Version\Hydrator\VersionHydratorServiceInterface: - class: Pimcore\Bundle\StudioBackendBundle\Version\Hydrator\VersionHydratorService + Pimcore\Bundle\StudioBackendBundle\Version\Service\VersionServiceInterface: + class: Pimcore\Bundle\StudioBackendBundle\Version\Service\VersionService arguments: - $versionHydratorLocator: '@listing.version_hydrator.service_locator' + $versionPublisherLocator: '@version.element_publisher.service_locator' - Pimcore\Bundle\StudioBackendBundle\Version\Publisher\VersionPublisherServiceInterface: - class: Pimcore\Bundle\StudioBackendBundle\Version\Publisher\VersionPublisherService + Pimcore\Bundle\StudioBackendBundle\Version\Service\VersionDetailServiceInterface: + class: Pimcore\Bundle\StudioBackendBundle\Version\Service\VersionDetailService arguments: - $versionPublisherLocator: '@version.element_publisher.service_locator' + $versionHydratorLocator: '@listing.version_hydrator.service_locator' #Service Locator listing.version_hydrator.service_locator: diff --git a/src/Response/Schemas.php b/src/Response/Schemas.php index e85fe84f4..5ae47e79d 100644 --- a/src/Response/Schemas.php +++ b/src/Response/Schemas.php @@ -26,10 +26,10 @@ use Pimcore\Bundle\StudioBackendBundle\Asset\Schema\Type\Video; use Pimcore\Bundle\StudioBackendBundle\Response\Schema\DevError; use Pimcore\Bundle\StudioBackendBundle\Response\Schema\Error; -use Pimcore\Bundle\StudioBackendBundle\Version\Schema\AssetType\ImageVersion; use Pimcore\Bundle\StudioBackendBundle\Version\Schema\AssetVersion; use Pimcore\Bundle\StudioBackendBundle\Version\Schema\DataObjectVersion; use Pimcore\Bundle\StudioBackendBundle\Version\Schema\DocumentVersion; +use Pimcore\Bundle\StudioBackendBundle\Version\Schema\ImageVersion; /** * @internal diff --git a/src/OpenApi/Attributes/Response/Content/OneOfVersionJson.php b/src/Version/Attributes/Response/Content/OneOfVersionJson.php similarity index 93% rename from src/OpenApi/Attributes/Response/Content/OneOfVersionJson.php rename to src/Version/Attributes/Response/Content/OneOfVersionJson.php index 2e200a25f..914489734 100644 --- a/src/OpenApi/Attributes/Response/Content/OneOfVersionJson.php +++ b/src/Version/Attributes/Response/Content/OneOfVersionJson.php @@ -14,7 +14,7 @@ * @license http://www.pimcore.org/license GPLv3 and PCL */ -namespace Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\Content; +namespace Pimcore\Bundle\StudioBackendBundle\Version\Attributes\Response\Content; use OpenApi\Attributes\JsonContent; use OpenApi\Attributes\Schema; diff --git a/src/OpenApi/Attributes/Response/Property/VersionCollection.php b/src/Version/Attributes/Response/Property/VersionCollection.php similarity index 78% rename from src/OpenApi/Attributes/Response/Property/VersionCollection.php rename to src/Version/Attributes/Response/Property/VersionCollection.php index 13f55813f..390b42d34 100644 --- a/src/OpenApi/Attributes/Response/Property/VersionCollection.php +++ b/src/Version/Attributes/Response/Property/VersionCollection.php @@ -14,11 +14,10 @@ * @license http://www.pimcore.org/license GPLv3 and PCL */ -namespace Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\Property; +namespace Pimcore\Bundle\StudioBackendBundle\Version\Attributes\Response\Property; use OpenApi\Attributes\Items; use OpenApi\Attributes\Property; -use OpenApi\Attributes\Schema; use Pimcore\Bundle\StudioBackendBundle\Version\Schema\Version; /** @@ -32,11 +31,7 @@ public function __construct() 'items', title: 'items', type: 'array', - items: new Items( - anyOf: [ - new Schema(ref: Version::class), - ] - ) + items: new Items(ref: Version::class) ); } } diff --git a/src/Version/Controller/CleanupController.php b/src/Version/Controller/CleanupController.php index b84f30e7b..a38e34d52 100644 --- a/src/Version/Controller/CleanupController.php +++ b/src/Version/Controller/CleanupController.php @@ -29,7 +29,7 @@ use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\Error\UnsupportedMediaTypeResponse; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\SuccessResponse; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Config\Tags; -use Pimcore\Bundle\StudioBackendBundle\Version\RepositoryInterface; +use Pimcore\Bundle\StudioBackendBundle\Version\Repository\VersionRepositoryInterface; use Pimcore\Bundle\StudioBackendBundle\Version\Request\VersionCleanupParameters; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpKernel\Attribute\MapQueryString; @@ -42,7 +42,7 @@ final class CleanupController extends AbstractApiController { public function __construct( - private readonly RepositoryInterface $repository, + private readonly VersionRepositoryInterface $repository, SerializerInterface $serializer, ) { parent::__construct($serializer); diff --git a/src/Version/Controller/CollectionController.php b/src/Version/Controller/CollectionController.php index bd058c7cc..f62a19c90 100644 --- a/src/Version/Controller/CollectionController.php +++ b/src/Version/Controller/CollectionController.php @@ -28,13 +28,13 @@ use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\Error\NotFoundResponse; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\Error\UnauthorizedResponse; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\Error\UnprocessableContentResponse; -use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\Property\VersionCollection; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\SuccessResponse; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Config\Tags; use Pimcore\Bundle\StudioBackendBundle\Security\Service\SecurityServiceInterface; use Pimcore\Bundle\StudioBackendBundle\Util\Traits\PaginatedResponseTrait; -use Pimcore\Bundle\StudioBackendBundle\Version\Hydrator\VersionHydratorServiceInterface; +use Pimcore\Bundle\StudioBackendBundle\Version\Attributes\Response\Property\VersionCollection; use Pimcore\Bundle\StudioBackendBundle\Version\Request\VersionParameters; +use Pimcore\Bundle\StudioBackendBundle\Version\Service\VersionServiceInterface; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpKernel\Attribute\MapQueryString; use Symfony\Component\Routing\Attribute\Route; @@ -50,7 +50,7 @@ final class CollectionController extends AbstractApiController public function __construct( SerializerInterface $serializer, private readonly SecurityServiceInterface $securityService, - private readonly VersionHydratorServiceInterface $hydratorService, + private readonly VersionServiceInterface $hydratorService, ) { parent::__construct($serializer); } @@ -80,15 +80,15 @@ public function __construct( #[UnprocessableContentResponse] public function getVersions(#[MapQueryString] VersionParameters $parameters): JsonResponse { - $result = $this->hydratorService->getHydratedVersions( + $collection = $this->hydratorService->getVersions( $parameters, $this->securityService->getCurrentUser() ); return $this->getPaginatedCollection( $this->serializer, - $result->getItems(), - $result->getTotalItems(), + $collection->getItems(), + $collection->getTotalItems(), ); } } diff --git a/src/Version/Controller/DeleteController.php b/src/Version/Controller/DeleteController.php index 8cf9bf922..1f5321e16 100644 --- a/src/Version/Controller/DeleteController.php +++ b/src/Version/Controller/DeleteController.php @@ -29,7 +29,7 @@ use Pimcore\Bundle\StudioBackendBundle\OpenApi\Config\Tags; use Pimcore\Bundle\StudioBackendBundle\Security\Service\SecurityServiceInterface; use Pimcore\Bundle\StudioBackendBundle\Util\Constants\ElementPermissions; -use Pimcore\Bundle\StudioBackendBundle\Version\RepositoryInterface; +use Pimcore\Bundle\StudioBackendBundle\Version\Repository\VersionRepositoryInterface; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Serializer\SerializerInterface; @@ -42,7 +42,7 @@ final class DeleteController extends AbstractApiController public function __construct( SerializerInterface $serializer, private readonly SecurityServiceInterface $securityService, - private readonly RepositoryInterface $repository + private readonly VersionRepositoryInterface $repository ) { parent::__construct($serializer); } @@ -70,12 +70,15 @@ public function __construct( public function deleteVersion(int $id): JsonResponse { $user = $this->securityService->getCurrentUser(); + $version = $this->repository->getVersionById($id); + $this->securityService->hasElementPermission( $version->getData(), $user, ElementPermissions::VERSIONS_PERMISSION ); + $version->delete(); return $this->jsonResponse(['id' => $id]); diff --git a/src/Version/Controller/GetController.php b/src/Version/Controller/GetController.php index 8031ad1f4..974026626 100644 --- a/src/Version/Controller/GetController.php +++ b/src/Version/Controller/GetController.php @@ -19,7 +19,6 @@ use OpenApi\Attributes\Get; use Pimcore\Bundle\StudioBackendBundle\Controller\AbstractApiController; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Parameters\Path\IdParameter; -use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\Content\OneOfVersionJson; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\Error\MethodNotAllowedResponse; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\Error\NotFoundResponse; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\Error\UnauthorizedResponse; @@ -28,7 +27,8 @@ use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\SuccessResponse; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Config\Tags; use Pimcore\Bundle\StudioBackendBundle\Security\Service\SecurityServiceInterface; -use Pimcore\Bundle\StudioBackendBundle\Version\Hydrator\VersionHydratorServiceInterface; +use Pimcore\Bundle\StudioBackendBundle\Version\Attributes\Response\Content\OneOfVersionJson; +use Pimcore\Bundle\StudioBackendBundle\Version\Service\VersionDetailServiceInterface; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Serializer\SerializerInterface; @@ -41,7 +41,7 @@ final class GetController extends AbstractApiController public function __construct( SerializerInterface $serializer, private readonly SecurityServiceInterface $securityService, - private readonly VersionHydratorServiceInterface $hydratorService, + private readonly VersionDetailServiceInterface $versionDetailService, ) { parent::__construct($serializer); } @@ -69,7 +69,7 @@ public function __construct( public function getVersions(int $id): JsonResponse { return $this->jsonResponse( - $this->hydratorService->getHydratedVersionData( + $this->versionDetailService->getVersionData( $id, $this->securityService->getCurrentUser() ) diff --git a/src/Version/Controller/PublishController.php b/src/Version/Controller/PublishController.php index b5419e18e..d62ac3619 100644 --- a/src/Version/Controller/PublishController.php +++ b/src/Version/Controller/PublishController.php @@ -28,7 +28,7 @@ use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\SuccessResponse; use Pimcore\Bundle\StudioBackendBundle\OpenApi\Config\Tags; use Pimcore\Bundle\StudioBackendBundle\Security\Service\SecurityServiceInterface; -use Pimcore\Bundle\StudioBackendBundle\Version\Publisher\VersionPublisherServiceInterface; +use Pimcore\Bundle\StudioBackendBundle\Version\Service\VersionServiceInterface; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Serializer\SerializerInterface; @@ -41,7 +41,7 @@ final class PublishController extends AbstractApiController public function __construct( SerializerInterface $serializer, private readonly SecurityServiceInterface $securityService, - private readonly VersionPublisherServiceInterface $publisher + private readonly VersionServiceInterface $versionService ) { parent::__construct($serializer); } @@ -71,7 +71,7 @@ public function publishVersion(int $id): JsonResponse $user = $this->securityService->getCurrentUser(); return $this->jsonResponse([ - 'id' => $this->publisher->publishVersion($id, $user), + 'id' => $this->versionService->publishVersion($id, $user), ]); } } diff --git a/src/Version/Event/AssetVersionEvent.php b/src/Version/Event/AssetVersionEvent.php new file mode 100644 index 000000000..b0dea0c9e --- /dev/null +++ b/src/Version/Event/AssetVersionEvent.php @@ -0,0 +1,40 @@ +version; + } +} diff --git a/src/Version/Event/DataObjectVersionEvent.php b/src/Version/Event/DataObjectVersionEvent.php new file mode 100644 index 000000000..ced828910 --- /dev/null +++ b/src/Version/Event/DataObjectVersionEvent.php @@ -0,0 +1,40 @@ +version; + } +} diff --git a/src/Version/Event/DocumentVersionEvent.php b/src/Version/Event/DocumentVersionEvent.php new file mode 100644 index 000000000..3add6e059 --- /dev/null +++ b/src/Version/Event/DocumentVersionEvent.php @@ -0,0 +1,40 @@ +version; + } +} diff --git a/src/Version/Event/ImageVersionEvent.php b/src/Version/Event/ImageVersionEvent.php new file mode 100644 index 000000000..1be182860 --- /dev/null +++ b/src/Version/Event/ImageVersionEvent.php @@ -0,0 +1,40 @@ +version; + } +} diff --git a/src/Version/Event/VersionEvent.php b/src/Version/Event/VersionEvent.php new file mode 100644 index 000000000..a6d7b0601 --- /dev/null +++ b/src/Version/Event/VersionEvent.php @@ -0,0 +1,40 @@ +version; + } +} diff --git a/src/Version/Hydrator/AssetVersionHydrator.php b/src/Version/Hydrator/AssetVersionHydrator.php index 2e824bb53..bd51be5cb 100644 --- a/src/Version/Hydrator/AssetVersionHydrator.php +++ b/src/Version/Hydrator/AssetVersionHydrator.php @@ -19,17 +19,25 @@ use Exception; use Pimcore\Bundle\StudioBackendBundle\Exception\ElementProcessingNotCompletedException; use Pimcore\Bundle\StudioBackendBundle\Exception\ElementUnsafeException; -use Pimcore\Bundle\StudioBackendBundle\Version\Schema\AssetType\ImageVersion; +use Pimcore\Bundle\StudioBackendBundle\Version\Event\AssetVersionEvent; +use Pimcore\Bundle\StudioBackendBundle\Version\Event\ImageVersionEvent; use Pimcore\Bundle\StudioBackendBundle\Version\Schema\AssetVersion; use Pimcore\Bundle\StudioBackendBundle\Version\Schema\Dimensions; +use Pimcore\Bundle\StudioBackendBundle\Version\Schema\ImageVersion; use Pimcore\Model\Asset; use Pimcore\Model\Asset\Image; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** * @internal */ -final class AssetVersionHydrator implements AssetVersionHydratorInterface +final readonly class AssetVersionHydrator implements AssetVersionHydratorInterface { + public function __construct( + private EventDispatcherInterface $eventDispatcher, + ) { + } + /** * @throws Exception */ @@ -45,15 +53,22 @@ public function hydrate( return $this->hydrateImage($asset); } - return new AssetVersion( + $hydratedAsset = new AssetVersion( $asset->getFilename(), $this->getTemporaryFile($asset), ); + + $this->eventDispatcher->dispatch( + new AssetVersionEvent($hydratedAsset), + AssetVersionEvent::EVENT_NAME + ); + + return $hydratedAsset; } private function hydrateImage(Image $image): ImageVersion { - return new ImageVersion( + $hydratedImage = new ImageVersion( $image->getFilename(), $this->getTemporaryFile($image), $image->getCreationDate(), @@ -62,6 +77,13 @@ private function hydrateImage(Image $image): ImageVersion $image->getMimeType(), $this->getImageDimensions($image) ); + + $this->eventDispatcher->dispatch( + new ImageVersionEvent($hydratedImage), + ImageVersionEvent::EVENT_NAME + ); + + return $hydratedImage; } private function getImageDimensions(Image $image): Dimensions diff --git a/src/Version/Hydrator/AssetVersionHydratorInterface.php b/src/Version/Hydrator/AssetVersionHydratorInterface.php index 86b410947..db415d2cb 100644 --- a/src/Version/Hydrator/AssetVersionHydratorInterface.php +++ b/src/Version/Hydrator/AssetVersionHydratorInterface.php @@ -17,6 +17,7 @@ namespace Pimcore\Bundle\StudioBackendBundle\Version\Hydrator; use Pimcore\Bundle\StudioBackendBundle\Version\Schema\AssetVersion; +use Pimcore\Bundle\StudioBackendBundle\Version\Schema\ImageVersion; use Pimcore\Model\Asset; /** @@ -26,5 +27,5 @@ interface AssetVersionHydratorInterface { public function hydrate( Asset $asset - ): AssetVersion; + ): ImageVersion|AssetVersion; } diff --git a/src/Version/Hydrator/DataObjectVersionHydrator.php b/src/Version/Hydrator/DataObjectVersionHydrator.php index cc7e1c080..7db546442 100644 --- a/src/Version/Hydrator/DataObjectVersionHydrator.php +++ b/src/Version/Hydrator/DataObjectVersionHydrator.php @@ -16,14 +16,21 @@ namespace Pimcore\Bundle\StudioBackendBundle\Version\Hydrator; +use Pimcore\Bundle\StudioBackendBundle\Version\Event\DataObjectVersionEvent; use Pimcore\Bundle\StudioBackendBundle\Version\Schema\DataObjectVersion; use Pimcore\Model\DataObject; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** * @internal */ -final class DataObjectVersionHydrator implements DataObjectVersionHydratorInterface +final readonly class DataObjectVersionHydrator implements DataObjectVersionHydratorInterface { + public function __construct( + private EventDispatcherInterface $eventDispatcher, + ) { + } + public function hydrate( DataObject $dataObject ): DataObjectVersion { @@ -32,10 +39,17 @@ public function hydrate( $published = $dataObject->isPublished(); } - return new DataObjectVersion( + $hydratedDataObject = new DataObjectVersion( $dataObject->getModificationDate(), $dataObject->getRealFullPath(), $published, ); + + $this->eventDispatcher->dispatch( + new DataObjectVersionEvent($hydratedDataObject), + DataObjectVersionEvent::EVENT_NAME + ); + + return $hydratedDataObject; } } diff --git a/src/Version/Hydrator/DocumentVersionHydrator.php b/src/Version/Hydrator/DocumentVersionHydrator.php index 2a6c01046..da1cd9e7c 100644 --- a/src/Version/Hydrator/DocumentVersionHydrator.php +++ b/src/Version/Hydrator/DocumentVersionHydrator.php @@ -16,21 +16,35 @@ namespace Pimcore\Bundle\StudioBackendBundle\Version\Hydrator; +use Pimcore\Bundle\StudioBackendBundle\Version\Event\DocumentVersionEvent; use Pimcore\Bundle\StudioBackendBundle\Version\Schema\DocumentVersion; use Pimcore\Model\Document; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** * @internal */ -final class DocumentVersionHydrator +final readonly class DocumentVersionHydrator { + public function __construct( + private EventDispatcherInterface $eventDispatcher, + ) { + } + public function hydrate( Document $document ): DocumentVersion { - return new DocumentVersion( + $hydratedDocument = new DocumentVersion( $document->getModificationDate(), $document->getRealFullPath(), $document->isPublished(), ); + + $this->eventDispatcher->dispatch( + new DocumentVersionEvent($hydratedDocument), + DocumentVersionEvent::EVENT_NAME + ); + + return $hydratedDocument; } } diff --git a/src/Version/Hydrator/VersionHydratorService.php b/src/Version/Hydrator/VersionHydratorService.php deleted file mode 100644 index 22c7513f5..000000000 --- a/src/Version/Hydrator/VersionHydratorService.php +++ /dev/null @@ -1,108 +0,0 @@ -getElement( - $this->serviceResolver, - $parameters->getElementType(), - $parameters->getElementId(), - ); - $scheduledTasks = $this->getScheduledTasks($element); - $list = $this->repository->listVersions($element, $parameters, $user); - $versions = []; - $versionObjects = $list->load(); - foreach ($versionObjects as $versionObject) { - $versions[] = $this->versionHydrator->hydrate($versionObject, $scheduledTasks); - } - - return new ListingResult( - $versions, - $parameters->getPage(), - $parameters->getPageSize(), - $list->getTotalCount() - ); - } - - public function getHydratedVersionData( - int $id, - UserInterface $user - ): AssetVersion|DataObjectVersion|DocumentVersion { - $version = $this->repository->getVersionById($id); - $element = $this->repository->getElementFromVersion($version, $user); - - return $this->hydrate( - $element, - $this->getElementClass($element) - ); - } - - private function hydrate( - ElementInterface $element, - string $class - ): AssetVersion|DocumentVersion|DataObjectVersion { - if ($this->versionHydratorLocator->has($class)) { - return $this->versionHydratorLocator->get($class)->hydrate($element); - } - - throw new InvalidElementTypeException($class); - } - - private function getScheduledTasks(ElementInterface $element): array - { - $scheduledTasks = $element->getScheduledTasks(); - $schedules = []; - foreach ($scheduledTasks as $task) { - if ($task->getActive()) { - $schedules[$task->getVersion()] = $task->getDate(); - } - } - - return $schedules; - } -} diff --git a/src/Version/Repository.php b/src/Version/Repository/VersionRepository.php similarity index 95% rename from src/Version/Repository.php rename to src/Version/Repository/VersionRepository.php index 8407ae3fb..10f5e752f 100644 --- a/src/Version/Repository.php +++ b/src/Version/Repository/VersionRepository.php @@ -14,9 +14,9 @@ * @license http://www.pimcore.org/license GPLv3 and PCL */ -namespace Pimcore\Bundle\StudioBackendBundle\Version; +namespace Pimcore\Bundle\StudioBackendBundle\Version\Repository; -use Pimcore\Bundle\StaticResolverBundle\Models\Version\VersionResolver; +use Pimcore\Bundle\StaticResolverBundle\Models\Version\VersionResolverInterface; use Pimcore\Bundle\StudioBackendBundle\Exception\ElementNotFoundException; use Pimcore\Bundle\StudioBackendBundle\Security\Service\SecurityServiceInterface; use Pimcore\Bundle\StudioBackendBundle\Util\Constants\ElementPermissions; @@ -31,13 +31,13 @@ /** * @internal */ -final readonly class Repository implements RepositoryInterface +final readonly class VersionRepository implements VersionRepositoryInterface { use ElementProviderTrait; public function __construct( private SecurityServiceInterface $securityService, - private VersionResolver $versionResolver + private VersionResolverInterface $versionResolver ) { } diff --git a/src/Version/RepositoryInterface.php b/src/Version/Repository/VersionRepositoryInterface.php similarity index 93% rename from src/Version/RepositoryInterface.php rename to src/Version/Repository/VersionRepositoryInterface.php index 45d8be072..9d018c6e7 100644 --- a/src/Version/RepositoryInterface.php +++ b/src/Version/Repository/VersionRepositoryInterface.php @@ -14,7 +14,7 @@ * @license http://www.pimcore.org/license GPLv3 and PCL */ -namespace Pimcore\Bundle\StudioBackendBundle\Version; +namespace Pimcore\Bundle\StudioBackendBundle\Version\Repository; use Pimcore\Bundle\StudioBackendBundle\Version\Request\VersionCleanupParameters; use Pimcore\Bundle\StudioBackendBundle\Version\Request\VersionParameters; @@ -26,7 +26,7 @@ /** * @internal */ -interface RepositoryInterface +interface VersionRepositoryInterface { public function listVersions( ElementInterface $element, diff --git a/src/Version/Result/ListingResult.php b/src/Version/Response/Collection.php similarity index 92% rename from src/Version/Result/ListingResult.php rename to src/Version/Response/Collection.php index 450c2139f..4461739c7 100644 --- a/src/Version/Result/ListingResult.php +++ b/src/Version/Response/Collection.php @@ -14,12 +14,12 @@ * @license http://www.pimcore.org/license GPLv3 and PCL */ -namespace Pimcore\Bundle\StudioBackendBundle\Version\Result; +namespace Pimcore\Bundle\StudioBackendBundle\Version\Response; /** * @internal */ -final readonly class ListingResult +final readonly class Collection { /** * @param array $items diff --git a/src/Version/Schema/AssetVersion.php b/src/Version/Schema/AssetVersion.php index 4ad6233dd..f5abbc872 100644 --- a/src/Version/Schema/AssetVersion.php +++ b/src/Version/Schema/AssetVersion.php @@ -18,6 +18,8 @@ use OpenApi\Attributes\Property; use OpenApi\Attributes\Schema; +use Pimcore\Bundle\StudioBackendBundle\Util\Schema\AdditionalAttributesInterface; +use Pimcore\Bundle\StudioBackendBundle\Util\Traits\AdditionalAttributesTrait; /** * @internal @@ -26,13 +28,15 @@ title: 'AssetVersion', type: 'object' )] -readonly class AssetVersion +final class AssetVersion implements AdditionalAttributesInterface { + use AdditionalAttributesTrait; + public function __construct( #[Property(description: 'file name', type: 'string', example: 'myImageFile.png')] - private string $fileName, + private readonly string $fileName, #[Property(description: 'temporary file', type: 'string', example: 'path/to/temporary/file.png')] - private ?string $temporaryFile, + private readonly ?string $temporaryFile, ) { } diff --git a/src/Version/Schema/DataObjectVersion.php b/src/Version/Schema/DataObjectVersion.php index 3851b9cc9..2438fda04 100644 --- a/src/Version/Schema/DataObjectVersion.php +++ b/src/Version/Schema/DataObjectVersion.php @@ -18,6 +18,8 @@ use OpenApi\Attributes\Property; use OpenApi\Attributes\Schema; +use Pimcore\Bundle\StudioBackendBundle\Util\Schema\AdditionalAttributesInterface; +use Pimcore\Bundle\StudioBackendBundle\Util\Traits\AdditionalAttributesTrait; /** * @internal @@ -26,15 +28,17 @@ title: 'DataObjectVersion', type: 'object' )] -final readonly class DataObjectVersion +final class DataObjectVersion implements AdditionalAttributesInterface { + use AdditionalAttributesTrait; + public function __construct( #[Property(description: 'modification date', type: 'integer', example: 1712823182)] - private int $modificationDate, + private readonly int $modificationDate, #[Property(description: 'path', type: 'string', example: '/path/to/object')] - private string $path, + private readonly string $path, #[Property(description: 'published', type: 'bool', example: true)] - private bool $published + private readonly bool $published ) { } diff --git a/src/Version/Schema/DocumentVersion.php b/src/Version/Schema/DocumentVersion.php index 8a2070946..0646f1d49 100644 --- a/src/Version/Schema/DocumentVersion.php +++ b/src/Version/Schema/DocumentVersion.php @@ -18,6 +18,8 @@ use OpenApi\Attributes\Property; use OpenApi\Attributes\Schema; +use Pimcore\Bundle\StudioBackendBundle\Util\Schema\AdditionalAttributesInterface; +use Pimcore\Bundle\StudioBackendBundle\Util\Traits\AdditionalAttributesTrait; /** * @internal @@ -26,15 +28,17 @@ title: 'DocumentVersion', type: 'object' )] -final readonly class DocumentVersion +final class DocumentVersion implements AdditionalAttributesInterface { + use AdditionalAttributesTrait; + public function __construct( #[Property(description: 'modification date', type: 'integer', example: 1712823182)] - private int $modificationDate, + private readonly int $modificationDate, #[Property(description: 'path', type: 'string', example: '/path/to/object')] - private string $path, + private readonly string $path, #[Property(description: 'published', type: 'bool', example: true)] - private bool $published + private readonly bool $published ) { } diff --git a/src/Version/Schema/AssetType/ImageVersion.php b/src/Version/Schema/ImageVersion.php similarity index 60% rename from src/Version/Schema/AssetType/ImageVersion.php rename to src/Version/Schema/ImageVersion.php index ca796b735..2b81f0f5e 100644 --- a/src/Version/Schema/AssetType/ImageVersion.php +++ b/src/Version/Schema/ImageVersion.php @@ -14,12 +14,12 @@ * @license http://www.pimcore.org/license GPLv3 and PCL */ -namespace Pimcore\Bundle\StudioBackendBundle\Version\Schema\AssetType; +namespace Pimcore\Bundle\StudioBackendBundle\Version\Schema; use OpenApi\Attributes\Property; use OpenApi\Attributes\Schema; -use Pimcore\Bundle\StudioBackendBundle\Version\Schema\AssetVersion; -use Pimcore\Bundle\StudioBackendBundle\Version\Schema\Dimensions; +use Pimcore\Bundle\StudioBackendBundle\Util\Schema\AdditionalAttributesInterface; +use Pimcore\Bundle\StudioBackendBundle\Util\Traits\AdditionalAttributesTrait; /** * @internal @@ -28,26 +28,36 @@ title: 'ImageVersion', type: 'object' )] -final readonly class ImageVersion extends AssetVersion +final class ImageVersion implements AdditionalAttributesInterface { + use AdditionalAttributesTrait; + public function __construct( - string $fileName, - ?string $temporaryFile, + #[Property(description: 'file name', type: 'string', example: 'myImageFile.png')] + private readonly string $fileName, + #[Property(description: 'temporary file', type: 'string', example: 'path/to/temporary/file.png')] + private readonly ?string $temporaryFile, #[Property(description: 'creation date', type: 'integer', example: 1707312457)] - private int $creationDate, + private readonly int $creationDate, #[Property(description: 'modification date', type: 'integer', example: 1707312457)] - private ?int $modificationDate, + private readonly ?int $modificationDate, #[Property(description: 'file size', type: 'integer', example: 41862)] - private int $fileSize, + private readonly int $fileSize, #[Property(description: 'mime type', type: 'string', example: 'image/png')] - private string $mimeType, + private readonly string $mimeType, #[Property(description: 'dimensions', type: Dimensions::class, example: '{"width":1920,"height":1080}')] - private ?Dimensions $dimensions = null, + private readonly ?Dimensions $dimensions = null, ) { - parent::__construct( - $fileName, - $temporaryFile - ); + } + + public function getFileName(): string + { + return $this->fileName; + } + + public function getTemporaryFile(): string + { + return $this->temporaryFile; } public function getDimensions(): ?Dimensions diff --git a/src/Version/Schema/Version.php b/src/Version/Schema/Version.php index 33b6c09ba..21e50f7a6 100644 --- a/src/Version/Schema/Version.php +++ b/src/Version/Schema/Version.php @@ -18,6 +18,8 @@ use OpenApi\Attributes\Property; use OpenApi\Attributes\Schema; +use Pimcore\Bundle\StudioBackendBundle\Util\Schema\AdditionalAttributesInterface; +use Pimcore\Bundle\StudioBackendBundle\Util\Traits\AdditionalAttributesTrait; /** * @internal @@ -26,29 +28,31 @@ title: 'Version', type: 'object' )] -final readonly class Version +final class Version implements AdditionalAttributesInterface { + use AdditionalAttributesTrait; + public function __construct( #[Property(description: 'version ID', type: 'integer', example: 2)] - private int $id, + private readonly int $id, #[Property(description: 'element ID', type: 'integer', example: 10)] - private int $cid, + private readonly int $cid, #[Property(description: 'element type', type: 'string', example: 'object')] - private string $ctype, + private readonly string $ctype, #[Property(description: 'note', type: 'string', example: 'some note')] - private string $note, + private readonly string $note, #[Property(description: 'date', type: 'integer', example: 1712823182)] - private int $date, + private readonly int $date, #[Property(description: 'public', type: 'bool', example: false)] - private bool $public, + private readonly bool $public, #[Property(description: 'version count', type: 'integer', example: 10)] - private int $versionCount, + private readonly int $versionCount, #[Property(description: 'autosave', type: 'bool', example: false)] - private bool $autosave, + private readonly bool $autosave, #[Property(description: 'user', type: User::class, example: '{"id":2,"name":"John Doe"}')] - private User $user, + private readonly User $user, #[Property(description: 'scheduled', type: 'integer', example: null)] - private ?int $scheduled + private readonly ?int $scheduled ) { } diff --git a/src/Version/Service/VersionDetailService.php b/src/Version/Service/VersionDetailService.php new file mode 100644 index 000000000..3106e4692 --- /dev/null +++ b/src/Version/Service/VersionDetailService.php @@ -0,0 +1,66 @@ +repository->getVersionById($id); + $element = $this->repository->getElementFromVersion($version, $user); + + return $this->hydrate( + $element, + $this->getElementClass($element) + ); + } + + private function hydrate( + ElementInterface $element, + string $class + ): AssetVersion|ImageVersion|DocumentVersion|DataObjectVersion { + if ($this->versionHydratorLocator->has($class)) { + return $this->versionHydratorLocator->get($class)->hydrate($element); + } + + throw new InvalidElementTypeException($class); + } +} diff --git a/src/Version/Hydrator/VersionHydratorServiceInterface.php b/src/Version/Service/VersionDetailServiceInterface.php similarity index 61% rename from src/Version/Hydrator/VersionHydratorServiceInterface.php rename to src/Version/Service/VersionDetailServiceInterface.php index 40a0cf543..dfc98b40c 100644 --- a/src/Version/Hydrator/VersionHydratorServiceInterface.php +++ b/src/Version/Service/VersionDetailServiceInterface.php @@ -14,27 +14,21 @@ * @license http://www.pimcore.org/license GPLv3 and PCL */ -namespace Pimcore\Bundle\StudioBackendBundle\Version\Hydrator; +namespace Pimcore\Bundle\StudioBackendBundle\Version\Service; -use Pimcore\Bundle\StudioBackendBundle\Version\Request\VersionParameters; -use Pimcore\Bundle\StudioBackendBundle\Version\Result\ListingResult; use Pimcore\Bundle\StudioBackendBundle\Version\Schema\AssetVersion; use Pimcore\Bundle\StudioBackendBundle\Version\Schema\DataObjectVersion; use Pimcore\Bundle\StudioBackendBundle\Version\Schema\DocumentVersion; +use Pimcore\Bundle\StudioBackendBundle\Version\Schema\ImageVersion; use Pimcore\Model\UserInterface; /** * @internal */ -interface VersionHydratorServiceInterface +interface VersionDetailServiceInterface { - public function getHydratedVersions( - VersionParameters $parameters, - UserInterface $user - ): ListingResult; - - public function getHydratedVersionData( + public function getVersionData( int $id, UserInterface $user - ): AssetVersion|DataObjectVersion|DocumentVersion; + ): AssetVersion|ImageVersion|DataObjectVersion|DocumentVersion; } diff --git a/src/Version/Publisher/VersionPublisherService.php b/src/Version/Service/VersionService.php similarity index 50% rename from src/Version/Publisher/VersionPublisherService.php rename to src/Version/Service/VersionService.php index 01306436c..dcd272047 100644 --- a/src/Version/Publisher/VersionPublisherService.php +++ b/src/Version/Service/VersionService.php @@ -14,7 +14,7 @@ * @license http://www.pimcore.org/license GPLv3 and PCL */ -namespace Pimcore\Bundle\StudioBackendBundle\Version\Publisher; +namespace Pimcore\Bundle\StudioBackendBundle\Version\Service; use Pimcore\Bundle\StaticResolverBundle\Models\Element\ServiceResolverInterface; use Pimcore\Bundle\StudioBackendBundle\Exception\ElementPublishingFailedException; @@ -22,25 +22,67 @@ use Pimcore\Bundle\StudioBackendBundle\Security\Service\SecurityServiceInterface; use Pimcore\Bundle\StudioBackendBundle\Util\Constants\ElementPermissions; use Pimcore\Bundle\StudioBackendBundle\Util\Traits\ElementProviderTrait; -use Pimcore\Bundle\StudioBackendBundle\Version\RepositoryInterface; +use Pimcore\Bundle\StudioBackendBundle\Version\Event\VersionEvent; +use Pimcore\Bundle\StudioBackendBundle\Version\Hydrator\VersionHydratorInterface; +use Pimcore\Bundle\StudioBackendBundle\Version\Repository\VersionRepositoryInterface; +use Pimcore\Bundle\StudioBackendBundle\Version\Request\VersionParameters; +use Pimcore\Bundle\StudioBackendBundle\Version\Response\Collection; +use Pimcore\Model\Element\ElementInterface; use Pimcore\Model\UserInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Contracts\Service\ServiceProviderInterface; /** * @internal */ -final class VersionPublisherService implements VersionPublisherServiceInterface +final readonly class VersionService implements VersionServiceInterface { use ElementProviderTrait; public function __construct( - private readonly SecurityServiceInterface $securityService, - private readonly ServiceResolverInterface $serviceResolver, - private readonly RepositoryInterface $repository, - private readonly ServiceProviderInterface $versionPublisherLocator + private EventDispatcherInterface $eventDispatcher, + private VersionRepositoryInterface $repository, + private ServiceResolverInterface $serviceResolver, + private ServiceProviderInterface $versionPublisherLocator, + private VersionHydratorInterface $versionHydrator, + private SecurityServiceInterface $securityService ) { } + public function getVersions( + VersionParameters $parameters, + UserInterface $user + ): Collection { + $element = $this->getElement( + $this->serviceResolver, + $parameters->getElementType(), + $parameters->getElementId(), + ); + $scheduledTasks = $this->getScheduledTasks($element); + $list = $this->repository->listVersions($element, $parameters, $user); + $versions = []; + $versionObjects = $list->load(); + foreach ($versionObjects as $versionObject) { + $hydratedVersion = $this->versionHydrator->hydrate($versionObject, $scheduledTasks); + + $this->eventDispatcher->dispatch( + new VersionEvent( + $hydratedVersion + ), + VersionEvent::EVENT_NAME + ); + + $versions[] = $hydratedVersion; + } + + return new Collection( + $versions, + $parameters->getPage(), + $parameters->getPageSize(), + $list->getTotalCount() + ); + } + public function publishVersion( int $versionId, UserInterface $user @@ -89,4 +131,17 @@ public function publishVersion( return $lastVersion->getId(); } + + private function getScheduledTasks(ElementInterface $element): array + { + $scheduledTasks = $element->getScheduledTasks(); + $schedules = []; + foreach ($scheduledTasks as $task) { + if ($task->getActive()) { + $schedules[$task->getVersion()] = $task->getDate(); + } + } + + return $schedules; + } } diff --git a/src/Version/Publisher/VersionPublisherServiceInterface.php b/src/Version/Service/VersionServiceInterface.php similarity index 63% rename from src/Version/Publisher/VersionPublisherServiceInterface.php rename to src/Version/Service/VersionServiceInterface.php index 6ede26a97..b73ba5aee 100644 --- a/src/Version/Publisher/VersionPublisherServiceInterface.php +++ b/src/Version/Service/VersionServiceInterface.php @@ -14,15 +14,22 @@ * @license http://www.pimcore.org/license GPLv3 and PCL */ -namespace Pimcore\Bundle\StudioBackendBundle\Version\Publisher; +namespace Pimcore\Bundle\StudioBackendBundle\Version\Service; +use Pimcore\Bundle\StudioBackendBundle\Version\Request\VersionParameters; +use Pimcore\Bundle\StudioBackendBundle\Version\Response\Collection; use Pimcore\Model\UserInterface; /** * @internal */ -interface VersionPublisherServiceInterface +interface VersionServiceInterface { + public function getVersions( + VersionParameters $parameters, + UserInterface $user + ): Collection; + public function publishVersion( int $versionId, UserInterface $user diff --git a/tests/Unit/Version/Hydrator/AssetVersionHydratorTest.php b/tests/Unit/Version/Hydrator/AssetVersionHydratorTest.php index b85fe15ba..9d76380b6 100644 --- a/tests/Unit/Version/Hydrator/AssetVersionHydratorTest.php +++ b/tests/Unit/Version/Hydrator/AssetVersionHydratorTest.php @@ -20,6 +20,7 @@ use Pimcore\Bundle\StudioBackendBundle\Exception\ElementProcessingNotCompletedException; use Pimcore\Bundle\StudioBackendBundle\Version\Hydrator\AssetVersionHydrator; use Pimcore\Model\Asset\Document; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** * @internal @@ -33,7 +34,9 @@ public function testGetHydratedVersionData(): void $asset->setMimeType('application/pdf'); $asset->setFilename('test.pdf'); - $assetVersionHydrator = new AssetVersionHydrator(); + $assetVersionHydrator = new AssetVersionHydrator( + $this->makeEmpty(EventDispatcherInterface::class) + ); // Status is not set properly $this->expectException(ElementProcessingNotCompletedException::class);