1

I have an issue with an Entity. The goal is to display a Form which the user can use to change his personal information like the Email or password. I created a form for that, but when I created the /Edit Route I get the following error:

"App\Entity\Users object not found by the @ParamConverter annotation."

Here's my Controller:

<?php

namespace App\Controller;

use App\Entity\Users;
use App\Form\EditProfileType;
use App\Form\UsersType;
use App\Repository\UsersRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

/**
 * @Route("/users")
 */
class UsersController extends AbstractController
{

    /**
     * @Route("/", name="users_index", methods={"GET"})
     */
    public function index(): Response
    {
        return $this->render('users/index.html.twig');
    }

    /**
     * @Route("/{id}", name="users_show", methods={"GET"})
     */
    public function show(Users $user): Response
    {
        return $this->render('users/show.html.twig', [
            'user' => $user,
        ]);
    }

    /**
     * @Route("/edit", name="users_edit")
     */
    public function editProfile(Request $request): Response
    {
        $user = $this->getUser();
        $form = $this->createForm(EditProfileType::class, $user);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($user);
            $em->flush();

            $this->addflash('message', 'Profile mis à jour');

            return $this->redirectToRoute('users');
        }

        return $this->render('users/editprofile.html.twig', [
            'form' => $form->createView(),
        ]);
    }

Here's the form:

<?php

namespace App\Form;

use App\Entity\Users;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class EditProfileType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('email')
            ->add('pseudo', TextType::class)
            ->add('Valider', SubmitType::class)
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => Users::class,
        ]);
    }
}

Here's the Entity Users:

<?php

namespace App\Entity;

use App\Repository\UsersRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\UserInterface;

/**
 * @ORM\Entity(repositoryClass=UsersRepository::class)
 * @UniqueEntity(fields={"email"}, message="There is already an account with this email")
 */
class Users implements UserInterface
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=180, unique=true)
     */
    private $email;

    /**
     * @ORM\Column(type="json")
     */
    private $roles = [];

    /**
     * @var string The hashed password
     * @ORM\Column(type="string")
     */
    private $password;

    /**
     * @ORM\OneToMany(targetEntity=Commentaires::class, mappedBy="auteur", orphanRemoval=true)
     */
    private $commentaires;

    /**
     * @ORM\OneToMany(targetEntity=Notes::class, mappedBy="user", orphanRemoval=true)
     */
    private $note;

    /**
     * @ORM\Column(type="string", length=100)
     */
    private $pseudo;

    public function __construct()
    {
        $this->commentaires = new ArrayCollection();
        $this->note = new ArrayCollection();
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getEmail(): ?string
    {
        return $this->email;
    }

    public function setEmail(string $email): self
    {
        $this->email = $email;

        return $this;
    }

    /**
     * A visual identifier that represents this user.
     *
     * @see UserInterface
     */
    public function getUsername(): string
    {
        return (string) $this->email;
    }

    /**
     * @see UserInterface
     */
    public function getRoles(): array
    {
        $roles = $this->roles;
        // guarantee every user at least has ROLE_USER
        $roles[] = 'ROLE_USER';

        return array_unique($roles);
    }

    public function setRoles(array $roles): self
    {
        $this->roles = $roles;

        return $this;
    }

    /**
     * @see UserInterface
     */
    public function getPassword(): string
    {
        return (string) $this->password;
    }

    public function setPassword(string $password): self
    {
        $this->password = $password;

        return $this;
    }

    /**
     * @see UserInterface
     */
    public function getSalt()
    {
        // not needed when using the "bcrypt" algorithm in security.yaml
    }

    /**
     * @see UserInterface
     */
    public function eraseCredentials()
    {
        // If you store any temporary, sensitive data on the user, clear it here
        // $this->plainPassword = null;
    }

    /**
     * @return Collection|Commentaires[]
     */
    public function getCommentaires(): Collection
    {
        return $this->commentaires;
    }

    public function addCommentaire(Commentaires $commentaire): self
    {
        if (!$this->commentaires->contains($commentaire)) {
            $this->commentaires[] = $commentaire;
            $commentaire->setAuteur($this);
        }

        return $this;
    }

    public function removeCommentaire(Commentaires $commentaire): self
    {
        if ($this->commentaires->contains($commentaire)) {
            $this->commentaires->removeElement($commentaire);
            // set the owning side to null (unless already changed)
            if ($commentaire->getAuteur() === $this) {
                $commentaire->setAuteur(null);
            }
        }

        return $this;
    }

    /**
     * @return Collection|Notes[]
     */
    public function getNote(): Collection
    {
        return $this->note;
    }

    public function addNote(Notes $note): self
    {
        if (!$this->note->contains($note)) {
            $this->note[] = $note;
            $note->setUser($this);
        }

        return $this;
    }

    public function removeNote(Notes $note): self
    {
        if ($this->note->contains($note)) {
            $this->note->removeElement($note);
            // set the owning side to null (unless already changed)
            if ($note->getUser() === $this) {
                $note->setUser(null);
            }
        }

        return $this;
    }

    public function getPseudo(): ?string
    {
        return $this->pseudo;
    }

    public function setPseudo(string $pseudo): self
    {
        $this->pseudo = $pseudo;

        return $this;
    }
}

Here's the View Editprofile.html.twig:

{% extends 'basefront.html.twig' %}

{% block title %} Profile de {{ app.user.pseudo }} {% endblock %}


{% block body %}
    <h1 class="h1 text-center">Modification du profile de {{ app.user.pseudo }}</h1>

    {{ form(form) }}
{% endblock %}
5
  • 1
    Just to clarify, you are talking about the /users/{id} show method and not the /users/edit route? Commented Jun 28, 2020 at 14:47
  • Hi, Im talking about the /users/edit method Commented Jun 28, 2020 at 15:03
  • The code you posted does not show the editProfile method using $users at all. It just works on the current user. Hence my question. Commented Jun 28, 2020 at 15:17
  • I want it to work on the current user online yes, and the editProfile method is on the first paste ;) Commented Jun 28, 2020 at 15:41
  • 1
    The code I am looking at shows $users being injected into the show method, not the editProfile method. Oh well. Hopefully someone else understands. And completely off-topic but change the name of your Users entity to User and save yourself a great deal of future confusion. Commented Jun 28, 2020 at 15:46

1 Answer 1

1

order matters. especially when routing without requirements. you have the following routes (update: added prefix, thanks @Cerad!):

/users/     users_index
/users/{id} users_show
/users/edit users_edit

now, when you request the uri /users/edit the UrlMatcher will iterate over your routes to see if and which matches, stopping on the first match.

/users/ obviously doesn't match /users/{id} does match, since {id} is allowed to be any alpha-numeric string (+ few extra chars), and edit matches that, leading to the users_show route, on which the User object cannot be determined by the id "edit`. And thus, the error message appears. One way to fix this would be to add requirements to the route matching - assuming the id is numerical only:

/**
 * @Route("/{id}", ..., requirements={"id":"\d+"})
 */

I also agree with @Cerad that Users is a very bad name for an entity. They're usually in singular form.

Sign up to request clarification or add additional context in comments.

4 Comments

They actually have a /users prefix on the controller so their routes look like /users/id and /users/edit . Pretty sure all they need to do is change the edit route to /users/edit/id and then add the Users typehint to the editProfile method. But there is an obvious communication disconnect. But yes, order does matter and they should either have a /users/show/id method or add a criteria.
you're right about the prefix, doesn't change my point though. modified the answer. I'm not sure I agree about the /users/{id}/edit though, since he only wants the user to modify themself.
Okay. Now I see. The error is coming from trying to load a user with an id of 'edit' because the show method is matched instead of the editProfile method.
Problem solved guys, The solution was to change the order of the methods, juste switched user_show with user_edit and it works perfectly, I also changed the name of the entity "Users" to "User". Thank you #Jakumi

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.