最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

symfony - Specifying a route with GET, POST method and handling a form - Stack Overflow

programmeradmin2浏览0评论

I am following a Symfony tutorial with basic atomic operations on a "Recipe" object with doctrine.
I am interested in understanding why I certain case the Entity object $recipe is passed implicitly as argument
to one routed method, and why in other case it need not.

E.g. with this method, the tutorial writes that "an object $recipe corresponding to the {id} is automatically found as input to the edit form"


    #[Route('/recette/{id}/edit', name: 'recipe.edit', methods: ['GET', 'POST'])]
    public function edit(Recipe $recipe, Request $request, EntityManagerInterface $em) 
    {
       $form = $this->createForm(RecipeType::class, $recipe);
       $form ->handleRequest($request);
       if ($form->isSubmitted() && $form->isValid()) {
          $em->flush(); // le formulaire a automatiquement sauvegarde mes changements
          return $this->redirectToRoute('recipe.show',  ['slug' => $recipe->getSlug(), 'id' => $recipe->getId()]);
       }
       return $this->render('recipe/edit.html.twig', [
           'recipe' => $recipe,
           'form' => $form,
       ]);
    } 

And I verified that a form is automatically filled with pre values corresponding to the recipe of {id=1}

But in the case of a creating of a new recipe, no object needed to be passed. However it seem logic, how are the new data transmitted in this case?

    #[Route('/recette/create', name: 'recipe.create', methods: ['GET', 'POST'])]
    public function create(Request $request, EntityManagerInterface $em) 
    {
       $recipe = new Recipe();
       $form = $this->createForm(RecipeType::class, $recipe);
       $form->handleRequest($request);
       if ($form->isSubmitted() && $form->isValid()) {
          $em->persist($recipe);
      $em->flush();
      $this->addFlash('success', 'the recipe is actually created');
          return $this->redirectToRoute('recipe.list');
       }
       return $this->render('recipe/create.html.twig', [
           'form' => $form
           ]);
    }

My last question concerns the possibility of defining an URL with a form hidden field for triggering the delete method. The following does not work (it simply prints out "Supprimer" (delete) on the page, without action)

  <td>
     <a class="btn btn-primary btn-sm" href="{{ path('recipe.edit', {id: recipe.id}) }}">Editer</a>
     <form action="{{ path('recipe.delete', {id: recipe.id}) }}"  method="post">
        <input type="hidden" name="_method" value="DELETE" 
        <button type="submit" class="btn btn-danger btn-sm" >Supprimer</button>

     </form>
  </td>
    #[Route('/recette/{id}/delete', name: 'recipe.delete', methods: ['DELETE'])]
    public function remove(Recipe $recipe, EntityManagerInterface $em)
    {
       $em->remove($recipe);
       $em->flush();
       $this->addFlash('success', 'La recette a bien ete supprimee');
       return $this->redirectToRoute('recipe.list');
    }

I would be grateful to any answer.

For the last question I expected two buttons to be created on side of each element of a recipe list. I observed only a hmtl link for Editer (edit) and a simple text 'Supprimer' (delete) aside

I am following a Symfony tutorial with basic atomic operations on a "Recipe" object with doctrine.
I am interested in understanding why I certain case the Entity object $recipe is passed implicitly as argument
to one routed method, and why in other case it need not.

E.g. with this method, the tutorial writes that "an object $recipe corresponding to the {id} is automatically found as input to the edit form"


    #[Route('/recette/{id}/edit', name: 'recipe.edit', methods: ['GET', 'POST'])]
    public function edit(Recipe $recipe, Request $request, EntityManagerInterface $em) 
    {
       $form = $this->createForm(RecipeType::class, $recipe);
       $form ->handleRequest($request);
       if ($form->isSubmitted() && $form->isValid()) {
          $em->flush(); // le formulaire a automatiquement sauvegarde mes changements
          return $this->redirectToRoute('recipe.show',  ['slug' => $recipe->getSlug(), 'id' => $recipe->getId()]);
       }
       return $this->render('recipe/edit.html.twig', [
           'recipe' => $recipe,
           'form' => $form,
       ]);
    } 

And I verified that a form is automatically filled with pre values corresponding to the recipe of {id=1}

But in the case of a creating of a new recipe, no object needed to be passed. However it seem logic, how are the new data transmitted in this case?

    #[Route('/recette/create', name: 'recipe.create', methods: ['GET', 'POST'])]
    public function create(Request $request, EntityManagerInterface $em) 
    {
       $recipe = new Recipe();
       $form = $this->createForm(RecipeType::class, $recipe);
       $form->handleRequest($request);
       if ($form->isSubmitted() && $form->isValid()) {
          $em->persist($recipe);
      $em->flush();
      $this->addFlash('success', 'the recipe is actually created');
          return $this->redirectToRoute('recipe.list');
       }
       return $this->render('recipe/create.html.twig', [
           'form' => $form
           ]);
    }

My last question concerns the possibility of defining an URL with a form hidden field for triggering the delete method. The following does not work (it simply prints out "Supprimer" (delete) on the page, without action)

  <td>
     <a class="btn btn-primary btn-sm" href="{{ path('recipe.edit', {id: recipe.id}) }}">Editer</a>
     <form action="{{ path('recipe.delete', {id: recipe.id}) }}"  method="post">
        <input type="hidden" name="_method" value="DELETE" 
        <button type="submit" class="btn btn-danger btn-sm" >Supprimer</button>

     </form>
  </td>
    #[Route('/recette/{id}/delete', name: 'recipe.delete', methods: ['DELETE'])]
    public function remove(Recipe $recipe, EntityManagerInterface $em)
    {
       $em->remove($recipe);
       $em->flush();
       $this->addFlash('success', 'La recette a bien ete supprimee');
       return $this->redirectToRoute('recipe.list');
    }

I would be grateful to any answer.

For the last question I expected two buttons to be created on side of each element of a recipe list. I observed only a hmtl link for Editer (edit) and a simple text 'Supprimer' (delete) aside

Share Improve this question asked Feb 7 at 8:30 Frederic PeugnyFrederic Peugny 11 bronze badge 1
  • For your last question, your form send POST requests while your route 'recipe.delete' allows only DELETE requests. And when you create an object you dont pass an object because the purpose is to create a new Object and save it in your DB. And when you edit an object symfony is able to map the object with the id you are passing in your URL – MoWiz Commented Feb 7 at 8:52
Add a comment  | 

1 Answer 1

Reset to default 0

There are two questions in this post, so I will answer them separately.

Question one:

To simplify it, you pass the object implicitly if you plan on using it inside your Controller. To pre-fill a form with data, to use some of it's values for other purposes or to pass it to the Twig template and use it there.

In your second code block, you don't need to pass it because you don't use it for the purpose of saving the form values. When the form submits, it's data is in the Request. Which, by binding it's data to the Recipe entity, makes your Controller handle the formdata as in your code block.

Passing a Recipe as a route param in this case would trigger Symfony's param converter to start looking for a recipe with the provided id, and when found, will cause the form to act more like an edit form than a create form.

If no id is passed, the param converter won't create a new instance automatically. Instead, it will throw an error as Symfony expects a Recipe but doesn't have an id to fetch one.

Question two:

To render a delete button and have it work your current setup won't work. Your Controller method only allows 'DELETE' while your form will send a 'POST' request. You must update your controller to allow 'POST' requests.

So the code would look something like tis:

#[Route('/recette/{id}/delete', name: 'recipe.delete', methods: ['POST', 'DELETE'])]
public function remove(Recipe $recipe, EntityManagerInterface $em, Request $request)
{
    if ($request->getMethod() === 'DELETE') { 
        $em->remove($recipe);
        $em->flush();
        $this->addFlash('success', 'La recette a bien ete supprimee');
    }

    return $this->redirectToRoute('recipe.list');
}

The button itself:

<form action="{{ path('recipe.delete', {id: recipe.id}) }}" method="post">
    <input type="hidden" name="_method" value="DELETE">
    <button type="submit" class="btn btn-danger btn-sm">Supprimer</button>
</form>
发布评论

评论列表(0)

  1. 暂无评论