Use [#MapEntity()] attribute to inject entity into method + for now set controller_resolver.auto_mapping to true

This commit is contained in:
2025-05-28 14:58:59 +02:00
parent f282ffbfd4
commit 8ec18a6fb8
24 changed files with 120 additions and 117 deletions

View File

@@ -14,6 +14,7 @@ namespace Chill\MainBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Chill\MainBundle\Entity\Address;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
@@ -33,7 +34,7 @@ class AddressApiController extends ApiController
* Duplicate an existing address.
*/
#[Route(path: '/api/1.0/main/address/{id}/duplicate.json', name: 'chill_api_main_address_duplicate', methods: ['POST'])]
public function duplicate(Address $address): JsonResponse
public function duplicate(#[MapEntity(id: 'id')] Address $address): JsonResponse
{
$this->denyAccessUnlessGranted('ROLE_USER');
$new = Address::createFromAddress($address);

View File

@@ -17,6 +17,7 @@ use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Chill\MainBundle\Repository\AddressReferenceRepository;
use Chill\MainBundle\Serializer\Model\Collection;
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@@ -29,7 +30,7 @@ final class AddressReferenceAPIController extends ApiController
public function __construct(private readonly AddressReferenceRepository $addressReferenceRepository, private readonly PaginatorFactory $paginatorFactory) {}
#[Route(path: '/api/1.0/main/address-reference/by-postal-code/{id}/search.json')]
public function search(PostalCode $postalCode, Request $request): JsonResponse
public function search(#[MapEntity(id: 'id')] PostalCode $postalCode, Request $request): JsonResponse
{
$this->denyAccessUnlessGranted('ROLE_USER');

View File

@@ -13,6 +13,7 @@ namespace Chill\MainBundle\Controller;
use Chill\MainBundle\Entity\Address;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
@@ -26,7 +27,7 @@ class AddressToReferenceMatcherController
public function __construct(private readonly Security $security, private readonly EntityManagerInterface $entityManager, private readonly SerializerInterface $serializer) {}
#[Route(path: '/api/1.0/main/address/reference-match/{id}/set/reviewed', methods: ['POST'])]
public function markAddressAsReviewed(Address $address): JsonResponse
public function markAddressAsReviewed(#[MapEntity(id: 'id')] Address $address): JsonResponse
{
if (!$this->security->isGranted('ROLE_USER')) {
throw new AccessDeniedHttpException();
@@ -48,7 +49,7 @@ class AddressToReferenceMatcherController
* Set an address back to "to review". Only if the address is in "reviewed" state.
*/
#[Route(path: '/api/1.0/main/address/reference-match/{id}/set/to_review', methods: ['POST'])]
public function markAddressAsToReview(Address $address): JsonResponse
public function markAddressAsToReview(#[MapEntity(id: 'id')] Address $address): JsonResponse
{
if (!$this->security->isGranted('ROLE_USER')) {
throw new AccessDeniedHttpException();
@@ -71,7 +72,7 @@ class AddressToReferenceMatcherController
}
#[Route(path: '/api/1.0/main/address/reference-match/{id}/sync-with-reference', methods: ['POST'])]
public function syncAddressWithReference(Address $address): JsonResponse
public function syncAddressWithReference(#[MapEntity(id: 'id')] Address $address): JsonResponse
{
if (null === $address->getAddressReference()) {
throw new BadRequestHttpException('this address does not have any address reference');

View File

@@ -26,6 +26,7 @@ use Chill\MainBundle\Repository\SavedExportRepositoryInterface;
use Chill\MainBundle\Security\Authorization\SavedExportVoter;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\Extension\Core\Type\FormType;
@@ -128,7 +129,7 @@ class ExportController extends AbstractController
* @throws \RedisException
*/
#[Route(path: '/{_locale}/exports/generate-from-saved/{id}', name: 'chill_main_export_generate_from_saved')]
public function generateFromSavedExport(SavedExport $savedExport): RedirectResponse
public function generateFromSavedExport(#[MapEntity(id: 'id')] SavedExport $savedExport): RedirectResponse
{
$this->denyAccessUnlessGranted(SavedExportVoter::GENERATE, $savedExport);
@@ -198,7 +199,7 @@ class ExportController extends AbstractController
}
#[Route(path: '/{_locale}/export/saved/update-from-key/{id}/{key}', name: 'chill_main_export_saved_edit_options_from_key')]
public function editSavedExportOptionsFromKey(SavedExport $savedExport, string $key): Response
public function editSavedExportOptionsFromKey(#[MapEntity(id: 'id')] SavedExport $savedExport, string $key): Response
{
$this->denyAccessUnlessGranted('ROLE_USER');
$user = $this->getUser();

View File

@@ -15,6 +15,7 @@ use Chill\MainBundle\Entity\Address;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Repository\GeographicalUnitRepositoryInterface;
use Chill\MainBundle\Serializer\Model\Collection;
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Routing\Annotation\Route;
@@ -27,7 +28,7 @@ class GeographicalUnitByAddressApiController
public function __construct(private readonly PaginatorFactory $paginatorFactory, private readonly GeographicalUnitRepositoryInterface $geographicalUnitRepository, private readonly Security $security, private readonly SerializerInterface $serializer) {}
#[Route(path: '/api/1.0/main/geographical-unit/by-address/{id}.{_format}', requirements: ['_format' => 'json'])]
public function getGeographicalUnitCoveringAddress(Address $address): JsonResponse
public function getGeographicalUnitCoveringAddress(#[MapEntity(id: 'id')] Address $address): JsonResponse
{
if (!$this->security->isGranted('ROLE_USER')) {
throw new AccessDeniedHttpException();

View File

@@ -16,10 +16,14 @@ use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Repository\NewsItemRepository;
use Chill\MainBundle\Templating\Listing\FilterOrderHelper;
use Chill\MainBundle\Templating\Listing\FilterOrderHelperFactoryInterface;
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Twig\Environment;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Error\SyntaxError;
final readonly class NewsItemHistoryController
{
@@ -46,8 +50,13 @@ final readonly class NewsItemHistoryController
]));
}
/**
* @throws SyntaxError
* @throws RuntimeError
* @throws LoaderError
*/
#[Route(path: '/{_locale}/news-items/{id}', name: 'chill_main_single_news_item')]
public function showSingleItem(NewsItem $newsItem, Request $request): Response
public function showSingleItem(#[MapEntity(id: 'id')] NewsItem $newsItem, Request $request): Response
{
return new Response($this->environment->render(
'@ChillMain/NewsItem/show.html.twig',

View File

@@ -19,6 +19,7 @@ use Chill\MainBundle\Security\Authorization\NotificationVoter;
use Chill\MainBundle\Serializer\Model\Collection;
use Chill\MainBundle\Serializer\Model\Counter;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
@@ -32,13 +33,13 @@ class NotificationApiController
public function __construct(private readonly EntityManagerInterface $entityManager, private readonly NotificationRepository $notificationRepository, private readonly PaginatorFactory $paginatorFactory, private readonly Security $security, private readonly SerializerInterface $serializer) {}
#[Route(path: '/{id}/mark/read', name: 'chill_api_main_notification_mark_read', methods: ['POST'])]
public function markAsRead(Notification $notification): JsonResponse
public function markAsRead(#[MapEntity(id: 'id')] Notification $notification): JsonResponse
{
return $this->markAs('read', $notification);
}
#[Route(path: '/{id}/mark/unread', name: 'chill_api_main_notification_mark_unread', methods: ['POST'])]
public function markAsUnread(Notification $notification): JsonResponse
public function markAsUnread(#[MapEntity(id: 'id')] Notification $notification): JsonResponse
{
return $this->markAs('unread', $notification);
}

View File

@@ -24,6 +24,7 @@ use Chill\MainBundle\Security\Authorization\NotificationVoter;
use Chill\MainBundle\Security\ChillSecurity;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
@@ -99,7 +100,7 @@ class NotificationController extends AbstractController
}
#[Route(path: '/{id}/edit', name: 'chill_main_notification_edit')]
public function editAction(Notification $notification, Request $request): Response
public function editAction(#[MapEntity(id: 'id')] Notification $notification, Request $request): Response
{
$this->denyAccessUnlessGranted(NotificationVoter::NOTIFICATION_UPDATE, $notification);
@@ -127,7 +128,7 @@ class NotificationController extends AbstractController
}
#[Route(path: '/{id}/access_key', name: 'chill_main_notification_grant_access_by_access_key')]
public function getAccessByAccessKey(Notification $notification, Request $request): Response
public function getAccessByAccessKey(#[MapEntity(id: 'id')] Notification $notification, Request $request): Response
{
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED');
@@ -215,7 +216,7 @@ class NotificationController extends AbstractController
}
#[Route(path: '/{id}/show', name: 'chill_main_notification_show')]
public function showAction(Notification $notification, Request $request): Response
public function showAction(#[MapEntity(id: 'id')] Notification $notification, Request $request): Response
{
$this->denyAccessUnlessGranted(NotificationVoter::NOTIFICATION_SEE, $notification);

View File

@@ -26,6 +26,7 @@ use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
@@ -208,7 +209,7 @@ final class PermissionsGroupController extends AbstractController
/**
* Displays a form to edit an existing PermissionsGroup entity.
*/
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/admin/permissionsgroup/{id}/edit', name: 'admin_permissionsgroup_edit')]
#[Route(path: '/{_locale}/admin/permissionsgroup/{id}/edit', name: 'admin_permissionsgroup_edit')]
public function editAction(int $id): Response
{
$permissionsGroup = $this->permissionsGroupRepository->find($id);
@@ -255,7 +256,7 @@ final class PermissionsGroupController extends AbstractController
/**
* Lists all PermissionsGroup entities.
*/
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/admin/permissionsgroup/', name: 'admin_permissionsgroup')]
#[Route(path: '/{_locale}/admin/permissionsgroup/', name: 'admin_permissionsgroup')]
public function indexAction(): Response
{
$entities = $this->permissionsGroupRepository->findAllOrderedAlphabetically();
@@ -268,7 +269,7 @@ final class PermissionsGroupController extends AbstractController
/**
* Displays a form to create a new PermissionsGroup entity.
*/
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/admin/permissionsgroup/new', name: 'admin_permissionsgroup_new')]
#[Route(path: '/{_locale}/admin/permissionsgroup/new', name: 'admin_permissionsgroup_new')]
public function newAction(): Response
{
$permissionsGroup = new PermissionsGroup();
@@ -283,7 +284,7 @@ final class PermissionsGroupController extends AbstractController
/**
* Finds and displays a PermissionsGroup entity.
*/
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/admin/permissionsgroup/{id}/show', name: 'admin_permissionsgroup_show')]
#[Route(path: '/{_locale}/admin/permissionsgroup/{id}/show', name: 'admin_permissionsgroup_show')]
public function showAction(int $id): Response
{
$permissionsGroup = $this->permissionsGroupRepository->find($id);
@@ -335,7 +336,7 @@ final class PermissionsGroupController extends AbstractController
/**
* Edits an existing PermissionsGroup entity.
*/
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/admin/permissionsgroup/{id}/update', name: 'admin_permissionsgroup_update', methods: ['POST', 'PUT'])]
#[Route(path: '/{_locale}/admin/permissionsgroup/{id}/update', name: 'admin_permissionsgroup_update', methods: ['POST', 'PUT'])]
public function updateAction(Request $request, int $id): Response
{
$permissionsGroup = $this->permissionsGroupRepository

View File

@@ -20,6 +20,7 @@ use Chill\MainBundle\Form\SavedExportType;
use Chill\MainBundle\Repository\SavedExportRepositoryInterface;
use Chill\MainBundle\Security\Authorization\SavedExportVoter;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
@@ -37,7 +38,7 @@ class SavedExportController
public function __construct(private readonly \Twig\Environment $templating, private readonly EntityManagerInterface $entityManager, private readonly ExportManager $exportManager, private readonly FormFactoryInterface $formFactory, private readonly SavedExportRepositoryInterface $savedExportRepository, private readonly Security $security, private readonly RequestStack $requestStack, private readonly TranslatorInterface $translator, private readonly UrlGeneratorInterface $urlGenerator) {}
#[Route(path: '/{_locale}/exports/saved/{id}/delete', name: 'chill_main_export_saved_delete')]
public function delete(SavedExport $savedExport, Request $request): Response
public function delete(#[MapEntity(id: 'id')] SavedExport $savedExport, Request $request): Response
{
if (!$this->security->isGranted(SavedExportVoter::DELETE, $savedExport)) {
throw new AccessDeniedHttpException();
@@ -70,7 +71,7 @@ class SavedExportController
}
#[Route(path: '/{_locale}/exports/saved/{id}/edit', name: 'chill_main_export_saved_edit')]
public function edit(SavedExport $savedExport, Request $request): Response
public function edit(#[MapEntity(id: 'id')] SavedExport $savedExport, Request $request): Response
{
if (!$this->security->isGranted(SavedExportVoter::EDIT, $savedExport)) {
throw new AccessDeniedHttpException();

View File

@@ -14,11 +14,13 @@ namespace Chill\MainBundle\Controller;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Form\ScopeType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* Class ScopeController.
@@ -57,8 +59,8 @@ class ScopeController extends AbstractController
/**
* Displays a form to edit an existing Scope entity.
*/
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/admin/scope/{id}/edit', name: 'admin_scope_edit')]
public function editAction(Scope $scope, Request $request): Response
#[Route(path: '/{_locale}/admin/scope/{id}/edit', name: 'admin_scope_edit')]
public function editAction(#[MapEntity(id: 'id')] Scope $scope, Request $request): Response
{
$editForm = $this->createEditForm($scope);
$editForm->handleRequest($request);
@@ -78,7 +80,7 @@ class ScopeController extends AbstractController
/**
* Lists all Scope entities.
*/
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/admin/scope/', name: 'admin_scope')]
#[Route(path: '/{_locale}/admin/scope/', name: 'admin_scope')]
public function indexAction(): \Symfony\Component\HttpFoundation\Response
{
$em = $this->managerRegistry->getManager();
@@ -93,7 +95,7 @@ class ScopeController extends AbstractController
/**
* Displays a form to create a new Scope entity.
*/
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/admin/scope/new', name: 'admin_scope_new')]
#[Route(path: '/{_locale}/admin/scope/new', name: 'admin_scope_new')]
public function newAction(): \Symfony\Component\HttpFoundation\Response
{
$scope = new Scope();

View File

@@ -26,6 +26,7 @@ use Chill\MainBundle\Security\ChillSecurity;
use Chill\MainBundle\Templating\Listing\FilterOrderHelper;
use Doctrine\Persistence\ManagerRegistry;
use Psr\Log\LoggerInterface;
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Form;
@@ -235,7 +236,7 @@ class UserController extends CRUDController
* Displays a form to edit the user password.
*/
#[Route(path: '/{_locale}/admin/user/{id}/edit_password', name: 'admin_user_edit_password')]
public function editPasswordAction(User $user, Request $request): RedirectResponse|Response
public function editPasswordAction(#[MapEntity(id: 'id')] User $user, Request $request): RedirectResponse|Response
{
$editForm = $this->createEditPasswordForm($user);
$editForm->handleRequest($request);

View File

@@ -12,6 +12,7 @@ declare(strict_types=1);
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\Entity\User;
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
@@ -24,7 +25,7 @@ class UserJobScopeHistoriesController extends AbstractController
) {}
#[Route(path: '/{_locale}/admin/main/user/{id}/job-scope-history', name: 'admin_user_job_scope_history')]
public function indexAction(User $user): Response
public function indexAction(#[MapEntity(id: 'id')] User $user): Response
{
$jobHistories = $user->getUserJobHistoriesOrdered();
$scopeHistories = $user->getMainScopeHistoriesOrdered();

View File

@@ -18,6 +18,7 @@ use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository;
use Chill\MainBundle\Serializer\Model\Collection;
use Chill\MainBundle\Serializer\Model\Counter;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@@ -108,13 +109,13 @@ class WorkflowApiController
}
#[Route(path: '/api/1.0/main/workflow/{id}/subscribe', methods: ['POST'])]
public function subscribe(EntityWorkflow $entityWorkflow, Request $request): Response
public function subscribe(#[MapEntity(id: 'id')] EntityWorkflow $entityWorkflow, Request $request): Response
{
return $this->handleSubscription($entityWorkflow, $request, 'subscribe');
}
#[Route(path: '/api/1.0/main/workflow/{id}/unsubscribe', methods: ['POST'])]
public function unsubscribe(EntityWorkflow $entityWorkflow, Request $request): Response
public function unsubscribe(#[MapEntity(id: 'id')] EntityWorkflow $entityWorkflow, Request $request): Response
{
return $this->handleSubscription($entityWorkflow, $request, 'unsubscribe');
}

View File

@@ -25,6 +25,7 @@ use Chill\MainBundle\Workflow\EntityWorkflowManager;
use Chill\MainBundle\Workflow\WorkflowTransitionContextDTO;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\NonUniqueResultException;
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Clock\ClockInterface;
use Symfony\Component\Form\Extension\Core\Type\FormType;
@@ -101,7 +102,7 @@ class WorkflowController extends AbstractController
}
#[Route(path: '/{_locale}/main/workflow/{id}/delete', name: 'chill_main_workflow_delete')]
public function delete(EntityWorkflow $entityWorkflow, Request $request): Response
public function delete(#[MapEntity(id: 'id')] EntityWorkflow $entityWorkflow, Request $request): Response
{
$this->denyAccessUnlessGranted(EntityWorkflowVoter::DELETE, $entityWorkflow);
@@ -126,7 +127,7 @@ class WorkflowController extends AbstractController
}
#[Route(path: '/{_locale}/main/workflow-step/{id}/access_key', name: 'chill_main_workflow_grant_access_by_key')]
public function getAccessByAccessKey(EntityWorkflowStep $entityWorkflowStep, Request $request): Response
public function getAccessByAccessKey(#[MapEntity(id: 'id')] EntityWorkflowStep $entityWorkflowStep, Request $request): Response
{
if (null === $accessKey = $request->query->get('accessKey', null)) {
throw new BadRequestHttpException('accessKey is missing');
@@ -288,7 +289,7 @@ class WorkflowController extends AbstractController
* @throws NonUniqueResultException
*/
#[Route(path: '/{_locale}/main/workflow/{id}/show', name: 'chill_main_workflow_show')]
public function show(EntityWorkflow $entityWorkflow, Request $request): Response
public function show(#[MapEntity(id: 'id')] EntityWorkflow $entityWorkflow, Request $request): Response
{
$this->denyAccessUnlessGranted(EntityWorkflowVoter::SEE, $entityWorkflow);