Repository: pimcore/studio-backend-bundle
Pull request #1095: [Documents][Editor] List controllers and teplates
Author: login: lukmzig
Labels: name: New Feature
Created: 2025-05-22T06:45:34Z | Merged: 2025-05-22T10:01:41Z

## Changes in this pull request
Resolves #1093


Linked issue #1093: [Documents][Editor] List controllers and teplates
Add endpoints to retrieve:

- list of available controllers (classic UI `/misc/get-available-controller-references`)
- list of available templates  (classic UI `/misc/get-available-templates`)

Diff:
diff --git a/config/documents.yaml b/config/documents.yaml
index e51749ca4..17c3076e9 100644
--- a/config/documents.yaml
+++ b/config/documents.yaml
@@ -47,6 +47,8 @@ services:
     arguments:
       $classResolver: '@pimcore.class.resolver.document'
 
+  Pimcore\Bundle\StudioBackendBundle\Document\Service\PageSnippetServiceInterface:
+    class: Pimcore\Bundle\StudioBackendBundle\Document\Service\PageSnippetService
 
   #
   # Repositories
diff --git a/doc/05_Additional_Custom_Attributes.md b/doc/05_Additional_Custom_Attributes.md
index 94c822351..511aceeb6 100644
--- a/doc/05_Additional_Custom_Attributes.md
+++ b/doc/05_Additional_Custom_Attributes.md
@@ -95,6 +95,8 @@ final class AssetEvent extends AbstractPreResponseEvent
 - `pre_response.dependency`
 - `pre_response.document`
 - `pre_response.document.doc_type_list`
+- `pre_response.document.list_available_controllers`
+- `pre_response.document.list_available_templates`
 - `pre_response.document.sites_list_available`
 - `pre_response.document_version`
 - `pre_response.email.blocklist.entry`
diff --git a/src/Document/Controller/PageSnippet/GetAvailableControllersController.php b/src/Document/Controller/PageSnippet/GetAvailableControllersController.php
new file mode 100644
index 000000000..01c6b2b2e
--- /dev/null
+++ b/src/Document/Controller/PageSnippet/GetAvailableControllersController.php
@@ -0,0 +1,72 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * This source file is available under the terms of the
+ * Pimcore Open Core License (POCL)
+ * Full copyright and license information is available in
+ * LICENSE.md which is distributed with this source code.
+ *
+ *  @copyright  Copyright (c) Pimcore GmbH (https://www.pimcore.com)
+ *  @license    Pimcore Open Core License (POCL)
+ */
+
+namespace Pimcore\Bundle\StudioBackendBundle\Document\Controller\PageSnippet;
+
+use OpenApi\Attributes\Get;
+use Pimcore\Bundle\StudioBackendBundle\Controller\AbstractApiController;
+use Pimcore\Bundle\StudioBackendBundle\Document\Schema\PageSnippet\Controller;
+use Pimcore\Bundle\StudioBackendBundle\Document\Service\PageSnippetServiceInterface;
+use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ReflectionException;
+use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\Content\ItemsJson;
+use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\DefaultResponses;
+use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\SuccessResponse;
+use Pimcore\Bundle\StudioBackendBundle\OpenApi\Config\Tags;
+use Pimcore\Bundle\StudioBackendBundle\Util\Constant\HttpResponseCodes;
+use Symfony\Component\HttpFoundation\JsonResponse;
+use Symfony\Component\Routing\Attribute\Route;
+use Symfony\Component\Serializer\SerializerInterface;
+
+/**
+ * @internal
+ */
+final class GetAvailableControllersController extends AbstractApiController
+{
+    private const string ROUTE = '/documents/get-available-controllers';
+
+    public function __construct(
+        SerializerInterface $serializer,
+        private readonly PageSnippetServiceInterface $pageSnippetService,
+    ) {
+        parent::__construct($serializer);
+    }
+
+    /**
+     * @throws ReflectionException
+     */
+    #[Route(
+        path: self::ROUTE,
+        name: 'pimcore_studio_api_list_document_available_controllers',
+        methods: ['GET']
+    )]
+    #[Get(
+        path: self::PREFIX . self::ROUTE,
+        operationId: 'document_available_controllers_list',
+        description: 'document_available_controllers_list_description',
+        summary: 'document_available_controllers_list_summary',
+        tags: [Tags::Documents->value]
+    )]
+    #[SuccessResponse(
+        description: 'document_available_controllers_list_success_response',
+        content: new ItemsJson(Controller::class),
+    )]
+    #[DefaultResponses([
+        HttpResponseCodes::INTERNAL_SERVER_ERROR,
+        HttpResponseCodes::UNAUTHORIZED,
+        HttpResponseCodes::NOT_FOUND,
+    ])]
+    public function getAvailableControllers(): JsonResponse
+    {
+        return $this->jsonResponse(['items' => $this->pageSnippetService->getAvailableControllers()]);
+    }
+}
diff --git a/src/Document/Controller/PageSnippet/GetAvailableTemplatesController.php b/src/Document/Controller/PageSnippet/GetAvailableTemplatesController.php
new file mode 100644
index 000000000..3946c0662
--- /dev/null
+++ b/src/Document/Controller/PageSnippet/GetAvailableTemplatesController.php
@@ -0,0 +1,71 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * This source file is available under the terms of the
+ * Pimcore Open Core License (POCL)
+ * Full copyright and license information is available in
+ * LICENSE.md which is distributed with this source code.
+ *
+ *  @copyright  Copyright (c) Pimcore GmbH (https://www.pimcore.com)
+ *  @license    Pimcore Open Core License (POCL)
+ */
+
+namespace Pimcore\Bundle\StudioBackendBundle\Document\Controller\PageSnippet;
+
+use OpenApi\Attributes\Get;
+use Pimcore\Bundle\StudioBackendBundle\Controller\AbstractApiController;
+use Pimcore\Bundle\StudioBackendBundle\Document\Schema\PageSnippet\Template;
+use Pimcore\Bundle\StudioBackendBundle\Document\Service\PageSnippetServiceInterface;
+use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ReflectionException;
+use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\Content\ItemsJson;
+use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\DefaultResponses;
+use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\SuccessResponse;
+use Pimcore\Bundle\StudioBackendBundle\OpenApi\Config\Tags;
+use Pimcore\Bundle\StudioBackendBundle\Util\Constant\HttpResponseCodes;
+use Symfony\Component\HttpFoundation\JsonResponse;
+use Symfony\Component\Routing\Attribute\Route;
+use Symfony\Component\Serializer\SerializerInterface;
+
+/**
+ * @internal
+ */
+final class GetAvailableTemplatesController extends AbstractApiController
+{
+    private const string ROUTE = '/documents/get-available-templates';
+
+    public function __construct(
+        SerializerInterface $serializer,
+        private readonly PageSnippetServiceInterface $pageSnippetService,
+    ) {
+        parent::__construct($serializer);
+    }
+
+    /**
+     * @throws ReflectionException
+     */
+    #[Route(
+        path: self::ROUTE,
+        name: 'pimcore_studio_api_list_document_available_templates',
+        methods: ['GET']
+    )]
+    #[Get(
+        path: self::PREFIX . self::ROUTE,
+        operationId: 'document_available_templates_list',
+        description: 'document_available_templates_list_description',
+        summary: 'document_available_templates_list_summary',
+        tags: [Tags::Documents->value]
+    )]
+    #[SuccessResponse(
+        description: 'document_available_templates_list_success_response',
+        content: new ItemsJson(Template::class),
+    )]
+    #[DefaultResponses([
+        HttpResponseCodes::UNAUTHORIZED,
+        HttpResponseCodes::NOT_FOUND,
+    ])]
+    public function getAvailableTemplates(): JsonResponse
+    {
+        return $this->jsonResponse(['items' => $this->pageSnippetService->getAvailableTemplates()]);
+    }
+}
diff --git a/src/Document/Event/PreResponse/ControllerEvent.php b/src/Document/Event/PreResponse/ControllerEvent.php
new file mode 100644
index 000000000..69ebd99d9
--- /dev/null
+++ b/src/Document/Event/PreResponse/ControllerEvent.php
@@ -0,0 +1,36 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * This source file is available under the terms of the
+ * Pimcore Open Core License (POCL)
+ * Full copyright and license information is available in
+ * LICENSE.md which is distributed with this source code.
+ *
+ *  @copyright  Copyright (c) Pimcore GmbH (https://www.pimcore.com)
+ *  @license    Pimcore Open Core License (POCL)
+ */
+
+namespace Pimcore\Bundle\StudioBackendBundle\Document\Event\PreResponse;
+
+use Pimcore\Bundle\StudioBackendBundle\Document\Schema\PageSnippet\Controller;
+use Pimcore\Bundle\StudioBackendBundle\Event\AbstractPreResponseEvent;
+
+final class ControllerEvent extends AbstractPreResponseEvent
+{
+    public const string EVENT_NAME = 'pre_response.document.list_available_controllers';
+
+    public function __construct(
+        private readonly Controller $controller
+    ) {
+        parent::__construct($controller);
+    }
+
+    /**
+     * Use this to get additional info out of the response object
+     */
+    public function getController(): Controller
+    {
+        return $this->controller;
+    }
+}
diff --git a/src/Document/Event/PreResponse/TemplateEvent.php b/src/Document/Event/PreResponse/TemplateEvent.php
new file mode 100644
index 000000000..3284ccecd
--- /dev/null
+++ b/src/Document/Event/PreResponse/TemplateEvent.php
@@ -0,0 +1,36 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * This source file is available under the terms of the
+ * Pimcore Open Core License (POCL)
+ * Full copyright and license information is available in
+ * LICENSE.md which is distributed with this source code.
+ *
+ *  @copyright  Copyright (c) Pimcore GmbH (https://www.pimcore.com)
+ *  @license    Pimcore Open Core License (POCL)
+ */
+
+namespace Pimcore\Bundle\StudioBackendBundle\Document\Event\PreResponse;
+
+use Pimcore\Bundle\StudioBackendBundle\Document\Schema\PageSnippet\Template;
+use Pimcore\Bundle\StudioBackendBundle\Event\AbstractPreResponseEvent;
+
+final class TemplateEvent extends AbstractPreResponseEvent
+{
+    public const string EVENT_NAME = 'pre_response.document.list_available_templates';
+
+    public function __construct(
+        private readonly Template $template
+    ) {
+        parent::__construct($template);
+    }
+
+    /**
+     * Use this to get additional info out of the response object
+     */
+    public function getController(): Template
+    {
+        return $this->template;
+    }
+}
diff --git a/src/Document/Schema/PageSnippet/Controller.php b/src/Document/Schema/PageSnippet/Controller.php
new file mode 100644
index 000000000..de394f098
--- /dev/null
+++ b/src/Document/Schema/PageSnippet/Controller.php
@@ -0,0 +1,41 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * This source file is available under the terms of the
+ * Pimcore Open Core License (POCL)
+ * Full copyright and license information is available in
+ * LICENSE.md which is distributed with this source code.
+ *
+ *  @copyright  Copyright (c) Pimcore GmbH (https://www.pimcore.com)
+ *  @license    Pimcore Open Core License (POCL)
+ */
+
+namespace Pimcore\Bundle\StudioBackendBundle\Document\Schema\PageSnippet;
+
+use OpenApi\Attributes\Property;
+use OpenApi\Attributes\Schema;
+use Pimcore\Bundle\StudioBackendBundle\Util\Schema\AdditionalAttributesInterface;
+use Pimcore\Bundle\StudioBackendBundle\Util\Trait\AdditionalAttributesTrait;
+
+#[Schema(
+    schema: 'Document Controller',
+    title: 'Document Controller',
+    required: ['name'],
+    type: 'object'
+)]
+final class Controller implements AdditionalAttributesInterface
+{
+    use AdditionalAttributesTrait;
+
+    public function __construct(
+        #[Property(description: 'Name', type: 'string', example: 'App\\Controller\\ContentController::indexAction')]
+        private readonly string $name,
+    ) {
+    }
+
+    public function getName(): string
+    {
+        return $this->name;
+    }
+}
diff --git a/src/Document/Schema/PageSnippet/Template.php b/src/Document/Schema/PageSnippet/Template.php
new file mode 100644
index 000000000..51042b310
--- /dev/null
+++ b/src/Document/Schema/PageSnippet/Template.php
@@ -0,0 +1,41 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * This source file is available under the terms of the
+ * Pimcore Open Core License (POCL)
+ * Full copyright and license information is available in
+ * LICENSE.md which is distributed with this source code.
+ *
+ *  @copyright  Copyright (c) Pimcore GmbH (https://www.pimcore.com)
+ *  @license    Pimcore Open Core License (POCL)
+ */
+
+namespace Pimcore\Bundle\StudioBackendBundle\Document\Schema\PageSnippet;
+
+use OpenApi\Attributes\Property;
+use OpenApi\Attributes\Schema;
+use Pimcore\Bundle\StudioBackendBundle\Util\Schema\AdditionalAttributesInterface;
+use Pimcore\Bundle\StudioBackendBundle\Util\Trait\AdditionalAttributesTrait;
+
+#[Schema(
+    schema: 'Document Template',
+    title: 'Document Template',
+    required: ['path'],
+    type: 'object'
+)]
+final class Template implements AdditionalAttributesInterface
+{
+    use AdditionalAttributesTrait;
+
+    public function __construct(
+        #[Property(description: 'Path', type: 'string', example: '@App/Resources/views/default.html.twig')]
+        private readonly string $path,
+    ) {
+    }
+
+    public function getPath(): string
+    {
+        return $this->path;
+    }
+}
diff --git a/src/Document/Schema/Site.php b/src/Document/Schema/Site.php
index 788526d8e..b7ee08d9b 100644
--- a/src/Document/Schema/Site.php
+++ b/src/Document/Schema/Site.php
@@ -26,6 +26,8 @@
         'id',
         'domains',
         'domain',
+        'rootId',
+        'rootPath',
     ],
     type: 'object'
 )]
diff --git a/src/Document/Service/PageSnippetService.php b/src/Document/Service/PageSnippetService.php
new file mode 100644
index 000000000..27cf50471
--- /dev/null
+++ b/src/Document/Service/PageSnippetService.php
@@ -0,0 +1,74 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * This source file is available under the terms of the
+ * Pimcore Open Core License (POCL)
+ * Full copyright and license information is available in
+ * LICENSE.md which is distributed with this source code.
+ *
+ *  @copyright  Copyright (c) Pimcore GmbH (https://www.pimcore.com)
+ *  @license    Pimcore Open Core License (POCL)
+ */
+
+namespace Pimcore\Bundle\StudioBackendBundle\Document\Service;
+
+use Exception;
+use Pimcore\Bundle\StudioBackendBundle\Document\Event\PreResponse\ControllerEvent;
+use Pimcore\Bundle\StudioBackendBundle\Document\Event\PreResponse\TemplateEvent;
+use Pimcore\Bundle\StudioBackendBundle\Document\Schema\PageSnippet\Controller;
+use Pimcore\Bundle\StudioBackendBundle\Document\Schema\PageSnippet\Template;
+use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ReflectionException;
+use Pimcore\Controller\Config\ControllerDataProvider;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+
+/**
+ * @internal
+ */
+final readonly class PageSnippetService implements PageSnippetServiceInterface
+{
+    public function __construct(
+        private ControllerDataProvider $controllerDataProvider,
+        private EventDispatcherInterface $eventDispatcher,
+    ) {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getAvailableControllers(): array
+    {
+        try {
+            $controllerReferences = $this->controllerDataProvider->getControllerReferences();
+        } catch (Exception $exception) {
+            throw new ReflectionException($exception->getMessage(), $exception);
+        }
+
+        $controllers = [];
+        foreach ($controllerReferences as $controllerReference) {
+            $controller = new Controller($controllerReference);
+            $this->eventDispatcher->dispatch(new ControllerEvent($controller), ControllerEvent::EVENT_NAME);
+
+            $controllers[] = $controller;
+        }
+
+        return $controllers;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getAvailableTemplates(): array
+    {
+        $templateReferences = $this->controllerDataProvider->getTemplates();
+        $templates = [];
+        foreach ($templateReferences as $templateReference) {
+            $template = new Template($templateReference);
+            $this->eventDispatcher->dispatch(new TemplateEvent($template), TemplateEvent::EVENT_NAME);
+
+            $templates[] = $template;
+        }
+
+        return $templates;
+    }
+}
diff --git a/src/Document/Service/PageSnippetServiceInterface.php b/src/Document/Service/PageSnippetServiceInterface.php
new file mode 100644
index 000000000..639b0ed0e
--- /dev/null
+++ b/src/Document/Service/PageSnippetServiceInterface.php
@@ -0,0 +1,36 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * This source file is available under the terms of the
+ * Pimcore Open Core License (POCL)
+ * Full copyright and license information is available in
+ * LICENSE.md which is distributed with this source code.
+ *
+ *  @copyright  Copyright (c) Pimcore GmbH (https://www.pimcore.com)
+ *  @license    Pimcore Open Core License (POCL)
+ */
+
+namespace Pimcore\Bundle\StudioBackendBundle\Document\Service;
+
+use Pimcore\Bundle\StudioBackendBundle\Document\Schema\PageSnippet\Controller;
+use Pimcore\Bundle\StudioBackendBundle\Document\Schema\PageSnippet\Template;
+use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ReflectionException;
+
+/**
+ * @internal
+ */
+interface PageSnippetServiceInterface
+{
+    /**
+     * @return Controller[]
+     *
+     * @throws ReflectionException
+     */
+    public function getAvailableControllers(): array;
+
+    /**
+     * @return Template[]
+     */
+    public function getAvailableTemplates(): array;
+}
diff --git a/src/Exception/Api/ReflectionException.php b/src/Exception/Api/ReflectionException.php
new file mode 100644
index 000000000..3ff26b242
--- /dev/null
+++ b/src/Exception/Api/ReflectionException.php
@@ -0,0 +1,32 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * This source file is available under the terms of the
+ * Pimcore Open Core License (POCL)
+ * Full copyright and license information is available in
+ * LICENSE.md which is distributed with this source code.
+ *
+ *  @copyright  Copyright (c) Pimcore GmbH (https://www.pimcore.com)
+ *  @license    Pimcore Open Core License (POCL)
+ */
+
+namespace Pimcore\Bundle\StudioBackendBundle\Exception\Api;
+
+use Pimcore\Bundle\StudioBackendBundle\Util\Constant\HttpResponseCodes;
+use Throwable;
+
+/**
+ * @internal
+ */
+final class ReflectionException extends AbstractApiException
+{
+    public function __construct(string $message = 'A reflection error occurred.', ?Throwable $previous = null)
+    {
+        parent::__construct(
+            statusCode: HttpResponseCodes::INTERNAL_SERVER_ERROR->value,
+            message: $message,
+            previous: $previous
+        );
+    }
+}
diff --git a/translations/studio_api_docs.en.yaml b/translations/studio_api_docs.en.yaml
index eb6762e80..5d88470ca 100644
--- a/translations/studio_api_docs.en.yaml
+++ b/translations/studio_api_docs.en.yaml
@@ -212,6 +212,14 @@ document_add_description: |
   Add a new data object to the given <strong>{parentId}</strong>. <br> The <strong>{parentId}</strong> must be an ID of a folder or another data object. See the full description of request fields with the schema <strong>DocumentAdd</strong>
 document_add_success_response: ID of added document
 document_add_summary: Add a new document
+document_available_controllers_list_description: |
+  List all available controllers for documents.
+document_available_controllers_list_response: List of available document controllers
+document_available_controllers_list_summary: List document controllers
+document_available_templates_list_description: |
+  List all available templates for documents.
+document_available_templates_list_response: List of available document templates
+document_available_templates_list_summary: List document templates
 document_clone_created_response: Successfully copied parent document and created
   <strong>jobRun</strong> for copying children
 document_clone_description: |


Reviews:
user: login: martineiber
body: Just an Idea. So it would be easier to find the right controller when just looking at the endpoint. 

I general there is `list` and `get` mixed up some times? 
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T07:45:00Z
user: login: martineiber
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T09:35:08Z

Review comments:
diff_hunk: @@ -0,0 +1,72 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * This source file is available under the terms of the
+ * Pimcore Open Core License (POCL)
+ * Full copyright and license information is available in
+ * LICENSE.md which is distributed with this source code.
+ *
+ *  @copyright  Copyright (c) Pimcore GmbH (https://www.pimcore.com)
+ *  @license    Pimcore Open Core License (POCL)
+ */
+
+namespace Pimcore\Bundle\StudioBackendBundle\Document\Controller\PageSnippet;
+
+use OpenApi\Attributes\Get;
+use Pimcore\Bundle\StudioBackendBundle\Controller\AbstractApiController;
+use Pimcore\Bundle\StudioBackendBundle\Document\Schema\PageSnippet\Controller;
+use Pimcore\Bundle\StudioBackendBundle\Document\Service\PageSnippetServiceInterface;
+use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ReflectionException;
+use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\Content\ItemsJson;
+use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\DefaultResponses;
+use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\SuccessResponse;
+use Pimcore\Bundle\StudioBackendBundle\OpenApi\Config\Tags;
+use Pimcore\Bundle\StudioBackendBundle\Util\Constant\HttpResponseCodes;
+use Symfony\Component\HttpFoundation\JsonResponse;
+use Symfony\Component\Routing\Attribute\Route;
+use Symfony\Component\Serializer\SerializerInterface;
+
+/**
+ * @internal
+ */
+final class ListControllersController extends AbstractApiController
path: src/Document/Controller/PageSnippet/ListControllersController.php
user: login: martineiber
body: ```suggestion
final class GetAvailableControllersController extends AbstractApiController
```
created_at: 2025-05-22T07:43:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,71 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * This source file is available under the terms of the
+ * Pimcore Open Core License (POCL)
+ * Full copyright and license information is available in
+ * LICENSE.md which is distributed with this source code.
+ *
+ *  @copyright  Copyright (c) Pimcore GmbH (https://www.pimcore.com)
+ *  @license    Pimcore Open Core License (POCL)
+ */
+
+namespace Pimcore\Bundle\StudioBackendBundle\Document\Controller\PageSnippet;
+
+use OpenApi\Attributes\Get;
+use Pimcore\Bundle\StudioBackendBundle\Controller\AbstractApiController;
+use Pimcore\Bundle\StudioBackendBundle\Document\Schema\PageSnippet\Template;
+use Pimcore\Bundle\StudioBackendBundle\Document\Service\PageSnippetServiceInterface;
+use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ReflectionException;
+use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\Content\ItemsJson;
+use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\DefaultResponses;
+use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\SuccessResponse;
+use Pimcore\Bundle\StudioBackendBundle\OpenApi\Config\Tags;
+use Pimcore\Bundle\StudioBackendBundle\Util\Constant\HttpResponseCodes;
+use Symfony\Component\HttpFoundation\JsonResponse;
+use Symfony\Component\Routing\Attribute\Route;
+use Symfony\Component\Serializer\SerializerInterface;
+
+/**
+ * @internal
+ */
+final class ListTemplatesController extends AbstractApiController
path: src/Document/Controller/PageSnippet/ListTemplatesController.php
user: login: martineiber
body: ```suggestion
final class GetAvailableTemplatesController extends AbstractApiController
```
created_at: 2025-05-22T07:43:43Z
author_association: CONTRIBUTOR

PR comments:
user: login: lukmzig
created_at: 2025-05-22T07:48:41Z
body: > Just an Idea. So it would be easier to find the right controller when just looking at the endpoint.
> 
> I general there is `list` and `get` mixed up some times?

Well we use `get` mostly for single results, this is a list. But I agree this is somewhat a special case and `get` would fit more here
author_association: CONTRIBUTOR
user: login: sonarqubecloud[bot]
created_at: 2025-05-22T09:28:30Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=pimcore_studio-backend-bundle&pullRequest=1095) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=pimcore_studio-backend-bundle&pullRequest=1095&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [2 Accepted issues](https://sonarcloud.io/project/issues?id=pimcore_studio-backend-bundle&pullRequest=1095&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=pimcore_studio-backend-bundle&pullRequest=1095&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=pimcore_studio-backend-bundle&pullRequest=1095&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=pimcore_studio-backend-bundle&pullRequest=1095&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=pimcore_studio-backend-bundle&pullRequest=1095)


author_association: NONE