diff --git a/config/data_objects.yaml b/config/data_objects.yaml
index c95e000e4..c9cf10b11 100644
--- a/config/data_objects.yaml
+++ b/config/data_objects.yaml
@@ -38,6 +38,9 @@ services:
Pimcore\Bundle\StudioBackendBundle\DataObject\Service\DataAdapterLoaderInterface:
class: Pimcore\Bundle\StudioBackendBundle\DataObject\Service\Loader\TaggedIteratorDataAdapter
+ Pimcore\Bundle\StudioBackendBundle\DataObject\Service\LayoutServiceInterface:
+ class: Pimcore\Bundle\StudioBackendBundle\DataObject\Service\LayoutService
+
#
# Data Adapters
#
@@ -161,6 +164,7 @@ services:
Pimcore\Bundle\StudioBackendBundle\DataObject\Data\Adapter\FieldCollectionsAdapter:
tags: [ 'pimcore.studio_backend.data_adapter' ]
+
#
# Handler
#
diff --git a/src/DataIndex/Hydrator/HydratorService.php b/src/DataIndex/Hydrator/HydratorService.php
index a6b157237..2c49636f7 100644
--- a/src/DataIndex/Hydrator/HydratorService.php
+++ b/src/DataIndex/Hydrator/HydratorService.php
@@ -66,7 +66,7 @@ public function hydrateDataObjects(DataObjectSearchResultItem $item): DataObject
return $this->dataObjectHydrator->hydrate($item);
}
- public function hydradeDocuments(DocumentSearchResultItem $item): IndexDocument
+ public function hydrateDocuments(DocumentSearchResultItem $item): IndexDocument
{
// TODO: Add Service Locator for different document types
diff --git a/src/DataObject/Controller/LayoutController.php b/src/DataObject/Controller/LayoutController.php
new file mode 100644
index 000000000..e9c701fcb
--- /dev/null
+++ b/src/DataObject/Controller/LayoutController.php
@@ -0,0 +1,80 @@
+value)]
+ #[Get(
+ path: self::PREFIX . '/data-objects/{id}/layout',
+ operationId: 'data_object_get_layout_by_id',
+ description: 'data_object_get_layout_by_id_description',
+ summary: 'data_object_get_layout_by_id_summary',
+ tags: [Tags::DataObjects->value]
+ )]
+ #[IdParameter(type: 'data-object')]
+ #[SuccessResponse(
+ description: 'data_object_get_layout_by_id_success_response',
+ content: new JsonContent(ref: Layout::class)
+ )]
+ #[DefaultResponses([
+ HttpResponseCodes::UNAUTHORIZED,
+ HttpResponseCodes::NOT_FOUND,
+ ])]
+ public function getDataObjectLayoutById(int $id): JsonResponse
+ {
+ return $this->jsonResponse($this->layoutService->getDataObjectLayout($id));
+ }
+}
diff --git a/src/DataObject/Event/PreResponse/LayoutEvent.php b/src/DataObject/Event/PreResponse/LayoutEvent.php
new file mode 100644
index 000000000..8e31ebd4e
--- /dev/null
+++ b/src/DataObject/Event/PreResponse/LayoutEvent.php
@@ -0,0 +1,39 @@
+layout);
+ }
+
+ /**
+ * Use this to get additional infos out of the response object
+ */
+ public function getLayout(): Layout
+ {
+ return $this->layout;
+ }
+}
diff --git a/src/DataObject/Schema/Layout.php b/src/DataObject/Schema/Layout.php
new file mode 100644
index 000000000..5aada15f0
--- /dev/null
+++ b/src/DataObject/Schema/Layout.php
@@ -0,0 +1,183 @@
+name;
+ }
+
+ public function getTitle(): ?string
+ {
+ return $this->title;
+ }
+
+ public function getDataType(): string
+ {
+ return $this->dataType;
+ }
+
+ public function getFieldType(): string
+ {
+ return $this->fieldType;
+ }
+
+ public function getType(): ?string
+ {
+ return $this->type;
+ }
+
+ public function getLayout(): ?string
+ {
+ return $this->layout;
+ }
+
+ public function getRegion(): ?string
+ {
+ return $this->region;
+ }
+
+ public function getWidth(): int
+ {
+ return $this->width;
+ }
+
+ public function getHeight(): int
+ {
+ return $this->height;
+ }
+
+ public function getCollapsible(): bool
+ {
+ return $this->collapsible;
+ }
+
+ public function getCollapsed(): bool
+ {
+ return $this->collapsed;
+ }
+
+ public function getBodyStyle(): ?string
+ {
+ return $this->bodyStyle;
+ }
+
+ public function getBorder(): bool
+ {
+ return $this->border;
+ }
+
+ public function getIcon(): ?ElementIcon
+ {
+ return $this->icon;
+ }
+
+ public function getLabelWidth(): int
+ {
+ return $this->labelWidth;
+ }
+
+ public function getLabelAlign(): string
+ {
+ return $this->labelAlign;
+ }
+
+ public function getLocked(): bool
+ {
+ return $this->locked;
+ }
+
+ public function getChildren(): array
+ {
+ return $this->children;
+ }
+}
diff --git a/src/DataObject/Service/LayoutService.php b/src/DataObject/Service/LayoutService.php
new file mode 100644
index 000000000..37c99241c
--- /dev/null
+++ b/src/DataObject/Service/LayoutService.php
@@ -0,0 +1,109 @@
+securityService->getCurrentUser();
+ $dataObject = $this->dataObjectService->getDataObjectElement(
+ $user,
+ $id
+ );
+
+ $dataObject = $this->getLatestVersionForUser($dataObject, $user);
+ if (!$dataObject instanceof Concrete) {
+ throw new InvalidElementTypeException(
+ sprintf('DataObject class (%s) is not a concrete object', get_class($dataObject))
+ );
+ }
+
+ try {
+ $layout = $dataObject->getClass()->getLayoutDefinitions();
+ } catch (Exception) {
+ throw new NotFoundException(type: 'class for data object', id: $id);
+ }
+
+ if (!$layout instanceof Panel) {
+ throw new NotFoundException(type: 'class layout for data object', id: $id);
+ }
+
+ //ToDo: Consider custom layouts once implemented
+ $hydratedLayout = $this->hydrateLayout($layout);
+ $this->eventDispatcher->dispatch(new LayoutEvent($hydratedLayout), LayoutEvent::EVENT_NAME);
+
+ return $hydratedLayout;
+ }
+
+ private function hydrateLayout(
+ Panel $panel
+ ): Layout {
+ return new Layout(
+ $panel->getName(),
+ $panel->getDatatype(),
+ $panel->fieldtype,
+ $panel->getType(),
+ $panel->getLayout(),
+ $panel->getRegion(),
+ $panel->getTitle(),
+ $panel->getWidth(),
+ $panel->getHeight(),
+ $panel->getCollapsible(),
+ $panel->getCollapsed(),
+ $panel->getBodyStyle(),
+ $panel->getLocked(),
+ $panel->getChildren(),
+ $this->iconService->getIconForLayout($panel->getIcon()),
+ $panel->getLabelAlign(),
+ $panel->getLabelWidth(),
+ $panel->getBorder()
+ );
+ }
+}
diff --git a/src/DataObject/Service/LayoutServiceInterface.php b/src/DataObject/Service/LayoutServiceInterface.php
new file mode 100644
index 000000000..8b3d0b77f
--- /dev/null
+++ b/src/DataObject/Service/LayoutServiceInterface.php
@@ -0,0 +1,31 @@
+value, $iconPath);
+ }
}
diff --git a/src/Icon/Service/IconServiceInterface.php b/src/Icon/Service/IconServiceInterface.php
index 3f6691966..9b348ad76 100644
--- a/src/Icon/Service/IconServiceInterface.php
+++ b/src/Icon/Service/IconServiceInterface.php
@@ -26,4 +26,6 @@ public function getIconForAsset(string $assetType, string $mimeType): ElementIco
public function getIconForDataObject(DataObjectSearchResultItem $dataObject): ElementIcon;
public function getIconForTag(): string;
+
+ public function getIconForLayout(?string $iconPath): ?ElementIcon;
}
diff --git a/translations/studio_api_docs.en.yaml b/translations/studio_api_docs.en.yaml
index 9ba7db82d..9bc445bdb 100644
--- a/translations/studio_api_docs.en.yaml
+++ b/translations/studio_api_docs.en.yaml
@@ -177,6 +177,10 @@ data_object_get_by_id_description: |
Retrieves a specific data object based on the given {id}.
The {id} must be an ID of existing data object or folder.
data_object_get_by_id_success_response: Successfully retrieved data object data as JSON
data_object_get_by_id_summary: Get a specific data object by ID
+data_object_get_layout_by_id_description: |
+ Retrieves the layout of a specific data object based on the given {id}.
The {id} must be an ID of existing data object.
+data_object_get_layout_by_id_success_response: Successfully retrieved data object layout data as JSON
+data_object_get_layout_by_id_summary: Get layout of a data object by ID
data_object_get_tree_description: |
Listing of all data objects and data object folders in the system.
Returns only data which are relevant for the tree