Home > Software design >  How to have optional parameter for param conversion in Symfony 6 controller
How to have optional parameter for param conversion in Symfony 6 controller

Time:07-13

I am trying to use an optional parameter in one of my symfony 6 controllers but it just does not work.

I have a controller with a method/route to create a new item and one to edit an existing item. The route for the "new" method does not accept an item parameter but the one for the "edit" method does. As such:

#[Route('/new', name: 'new', methods: ['GET', 'POST'])]
public function new( Request $request ): Response ...

#[Route('/edit/{id}', name: 'edit', methods: ['GET', 'POST'])]
public function edit( Request $request, Item $item ): Response ...

Since both of the methods have a large amount of the same code in them, I decided to create a new "new_edit" method and route that is then called from the "new" and "edit" methods via "directToRoute".

#[Route('/new_edit/{id}', name: 'new_edit', defaults: ['id' => null], methods: ['GET', 'POST'])]
public function new_edit( Request $request, ?Item $item ) : Response ...

So far so good. When I select an existing item and elect to edit it, all works perfectly. However, when I elect to create a new item I constantly get and error message "Item object not found by the @ParamConverter annotation".

I have tried setting default values, etc. but I am just not able to get this working.

Does anyone have a solution to such a problem?

Many thanks, Kristian.

CodePudding user response:

It seems I have found the issue and it was not related directly to the optional parameter but to the priority in which the routes are evaluated.

I modified my route priorities and now all works as expected with the following configuration:

#[Route('/new', name: 'new', methods: ['GET', 'POST'])]
public function new(): Response
{
    return $this->redirectToRoute( 'item.new_edit', [], Response::HTTP_SEE_OTHER );
}

#[Route('/edit/{id}', name: 'edit', methods: ['GET', 'POST'])]
public function edit( Item $item ): Response
{
    return $this->redirectToRoute( 'item.new_edit', ['id' => $item->getId()], Response::HTTP_SEE_OTHER );
}

#[Route('/new_edit/{id}', name: 'new_edit', defaults: ['id' => null], methods: ['GET', 'POST'])]
public function new_edit( Request $request, ?Item $Item ) : Response
{
    ...
}

I hope that helps anyone who has the same issue.

Kristian

CodePudding user response:

You can use several routes for one action. For the optional param you can define a default value for the PHP parameter ?Item $Item = null

#[
    Route('/new', name: 'new', methods: ['GET', 'POST']),
    Route('/edit/{id}', name: 'edit', methods: ['GET', 'POST'])
]
public function new_edit(Request $request, ?Item $item = null) : Response
{
}
  • Related