diff --git a/config/documents.yaml b/config/documents.yaml
index 1bce398c..f198214c 100644
--- a/config/documents.yaml
+++ b/config/documents.yaml
@@ -4,6 +4,35 @@ services:
autoconfigure: true
public: false
- # Secvices
+ # controllers are imported separately to make sure they're public
+ # and have a tag that allows actions to type-hint services
+ Pimcore\Bundle\StudioBackendBundle\Document\Controller\:
+ resource: '../src/Document/Controller'
+ public: true
+ tags: [ 'controller.service_arguments' ]
+
+ #
+ # Services
+ #
+
Pimcore\Bundle\StudioBackendBundle\Document\Service\DocumentServiceInterface:
- class: Pimcore\Bundle\StudioBackendBundle\Document\Service\DocumentService
\ No newline at end of file
+ class: Pimcore\Bundle\StudioBackendBundle\Document\Service\DocumentService
+
+ Pimcore\Bundle\StudioBackendBundle\Document\Service\SiteServiceInterface:
+ class: Pimcore\Bundle\StudioBackendBundle\Document\Service\SiteService
+
+
+ #
+ # Repositories
+ #
+
+ Pimcore\Bundle\StudioBackendBundle\Document\Repository\SiteRepositoryInterface:
+ class: Pimcore\Bundle\StudioBackendBundle\Document\Repository\SiteRepository
+
+
+ #
+ # Hydrators
+ #
+
+ Pimcore\Bundle\StudioBackendBundle\Document\Hydrator\SiteHydratorInterface:
+ class: Pimcore\Bundle\StudioBackendBundle\Document\Hydrator\SiteHydrator
\ No newline at end of file
diff --git a/src/Asset/Controller/Video/ImageThumbnailStreamController.php b/src/Asset/Controller/Video/ImageThumbnailStreamController.php
index 200af814..828c77ea 100644
--- a/src/Asset/Controller/Video/ImageThumbnailStreamController.php
+++ b/src/Asset/Controller/Video/ImageThumbnailStreamController.php
@@ -81,7 +81,7 @@ public function __construct(
operationId: 'asset_video_image_thumbnail_stream',
description: 'asset_video_image_thumbnail_stream_description',
summary: 'asset_video_image_thumbnail_stream_summary',
- tags: [Tags::Assets->name]
+ tags: [Tags::Assets->value]
)]
#[IdParameter(type: 'video')]
#[WidthParameter('Width of the video image thumbnail', 265)]
diff --git a/src/Document/Attribute/Response/AvailableSitesJson.php b/src/Document/Attribute/Response/AvailableSitesJson.php
new file mode 100644
index 00000000..99a62603
--- /dev/null
+++ b/src/Document/Attribute/Response/AvailableSitesJson.php
@@ -0,0 +1,43 @@
+value)]
+ #[Get(
+ path: self::PREFIX . '/documents/sites/list-available',
+ operationId: 'documents_list_available_sites',
+ description: 'documents_list_available_sites_description',
+ summary: 'documents_list_available_sites_summary',
+ tags: [Tags::Documents->value]
+ )]
+ #[ExcludeMainSiteParameter]
+ #[SuccessResponse(
+ description: 'documents_list_available_sites_success_response',
+ content: new AvailableSitesJson()
+ )]
+ #[DefaultResponses([
+ HttpResponseCodes::UNAUTHORIZED,
+ ])]
+ public function getAvailableSites(
+ #[MapQueryString] MappedParameter $parameter
+ ): JsonResponse {
+ return $this->jsonResponse(['items' => $this->siteService->getAvailableSites($parameter)]);
+ }
+}
diff --git a/src/Document/Event/PreResponse/SiteEvent.php b/src/Document/Event/PreResponse/SiteEvent.php
new file mode 100644
index 00000000..d6300e3a
--- /dev/null
+++ b/src/Document/Event/PreResponse/SiteEvent.php
@@ -0,0 +1,39 @@
+site;
+ }
+}
diff --git a/src/Document/Hydrator/SiteHydrator.php b/src/Document/Hydrator/SiteHydrator.php
new file mode 100644
index 00000000..577d1337
--- /dev/null
+++ b/src/Document/Hydrator/SiteHydrator.php
@@ -0,0 +1,37 @@
+getId(),
+ $siteModel->getDomains(),
+ $siteModel->getMainDomain(),
+ $siteModel->getRootId(),
+ $siteModel->getRootPath(),
+ );
+ }
+}
diff --git a/src/Document/Hydrator/SiteHydratorInterface.php b/src/Document/Hydrator/SiteHydratorInterface.php
new file mode 100644
index 00000000..5c456805
--- /dev/null
+++ b/src/Document/Hydrator/SiteHydratorInterface.php
@@ -0,0 +1,28 @@
+excludeMainSite === 'true'; // TODO: symfony 7.1 will support bool type
+ }
+}
diff --git a/src/Document/OpenApi/Attribute/Parameter/Query/ExcludeMainSiteParameter.php b/src/Document/OpenApi/Attribute/Parameter/Query/ExcludeMainSiteParameter.php
new file mode 100644
index 00000000..68a8cf55
--- /dev/null
+++ b/src/Document/OpenApi/Attribute/Parameter/Query/ExcludeMainSiteParameter.php
@@ -0,0 +1,35 @@
+load();
+ }
+}
diff --git a/src/Document/Repository/SiteRepositoryInterface.php b/src/Document/Repository/SiteRepositoryInterface.php
new file mode 100644
index 00000000..9a6b4ce9
--- /dev/null
+++ b/src/Document/Repository/SiteRepositoryInterface.php
@@ -0,0 +1,30 @@
+id;
+ }
+
+ public function getRootId(): ?int
+ {
+ return $this->rootId;
+ }
+
+ public function getRootPath(): ?string
+ {
+ return $this->rootPath;
+ }
+
+ public function getDomains(): array
+ {
+ return $this->domains;
+ }
+
+ public function getDomain(): string
+ {
+ return $this->domain;
+ }
+}
diff --git a/src/Document/Service/SiteService.php b/src/Document/Service/SiteService.php
new file mode 100644
index 00000000..a1e8349f
--- /dev/null
+++ b/src/Document/Service/SiteService.php
@@ -0,0 +1,66 @@
+getExcludeMainSite() === false) {
+ $sites[] = $this->getMainSite();
+ }
+
+ $siteList = $this->siteRepository->listSites();
+ foreach ($siteList as $siteEntry) {
+ $site = $this->siteHydrator->hydrate($siteEntry);
+
+ $this->eventDispatcher->dispatch(new SiteEvent($site), SiteEvent::EVENT_NAME);
+ $sites[] = $site;
+ }
+
+ return $sites;
+ }
+
+ private function getMainSite(): Site
+ {
+ return new Site(0, [], 'main_site', 1, '/');
+ }
+}
diff --git a/src/Document/Service/SiteServiceInterface.php b/src/Document/Service/SiteServiceInterface.php
new file mode 100644
index 00000000..f5ff2af8
--- /dev/null
+++ b/src/Document/Service/SiteServiceInterface.php
@@ -0,0 +1,31 @@
+value,
description: 'tag_dependencies_description'
)]
+#[Tag(
+ name: Tags::Documents->value,
+ description: 'tag_documents_description'
+)]
#[Tag(
name: Tags::Elements->value,
description: 'tag_elements_description'
@@ -127,6 +131,7 @@ enum Tags: string
case DataObjects = 'Data Objects';
case DataObjectsGrid = 'Data Object Grid';
case Dependencies = 'Dependencies';
+ case Documents = 'Documents';
case Elements = 'Elements';
case ExecutionEngine = 'Execution Engine';
case Emails = 'E-Mails';
diff --git a/translations/studio_api_docs.en.yaml b/translations/studio_api_docs.en.yaml
index 193ba08c..b3179401 100644
--- a/translations/studio_api_docs.en.yaml
+++ b/translations/studio_api_docs.en.yaml
@@ -201,6 +201,10 @@ data_object_update_by_id_description: |
Update needs to have the complete data present.
You can create/update/delete list entries like properties.
If you want to update only a single field, use the PATCH method.
data_object_update_by_id_success_response: Successfully updated data object
data_object_update_by_id_summary: Update a data object by ID
+documents_list_available_sites_description: |
+ List all available sites
+documents_list_available_sites_success_response: List of available sites
+documents_list_available_sites_summary: List all available sites
element_delete_created_response: Successfully created jobRun for deleting element
and its children
element_delete_description: |
@@ -434,6 +438,7 @@ tag_delete_by_id_description: |
tag_delete_by_id_success_response: ID of successfully deleted tag
tag_delete_by_id_summary: Delete a specific tag
tag_dependencies_description: Get dependencies for a single element
+tag_documents_description: Document operations to get/update/create/delete documents
tag_elements_description: Get element properties for a single element based on its
type and provided parameters
tag_emails_description: E-mail operations to get/update/create/delete/test emails and