Learn what causes the Symfony 5 exception "Entity could not be converted to string" and how to fix it.

How to fix Symfony 5 Error: Object of class Proxies\__CG__\App\Entity could not be converted to string

Symfony is awesome, that's for sure. It includes a lot of tools that you may use to improve the development times of your project, automatizing very important stuff like the generation of forms from tables that exist already, so you don't need to write them as doctrine entities from scratch. Using the mentioned tools may lead of course to some exceptions to appear in your project if you don't fully understand what the Symfony commands did.

In the case of "Object of class Proxies\__CG__\App\Entity could not be converted to string", it's quite probably that you generated the doctrine entities from a database automatically, and therefore, the entities have not the magic __toString method. In this article, I'll explain to you how to easily prevent this exception from appearing.

Context

In order to replicate this error just like the use that you are having right now, we will use a very basic example. We do have 2 tables with a ManyToOne relationship:

Many To One Relationship SQL

When the user registers a new person in the database, it's necessary to provide the state in which the user lives, quite simple. This information, converted to doctrine entities, look respectively like this, for the Person.php entity:

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Person
 *
 * @ORM\Table(name="person")
 * @ORM\Entity
 */
class Person
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="bigint", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string|null
     *
     * @ORM\Column(name="first_name", type="string", length=255, nullable=true, options={"default"="NULL"})
     */
    private $firstName;

    /**
     * @var string|null
     *
     * @ORM\Column(name="last_name", type="string", length=255, nullable=true, options={"default"="NULL"})
     */
    private $lastName;

    /**
     * @var \States
     *
     * @ORM\ManyToOne(targetEntity="States")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="states_id", referencedColumnName="id")
     * })
     */
    private $state;

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

    public function getFirstName(): ?string
    {
        return $this->firstName;
    }

    public function setLastName(?string $firstName): self
    {
        $this->firstName = $firstName;

        return $this;
    }

    public function getLastName(): ?string
    {
        return $this->lastName;
    }

    public function setLastName(?string $lastName): self
    {
        $this->lastName = $lastName;

        return $this;
    }

    public function getState(): ?State
    {
        return $this->state;
    }

    public function setState(?State $state): self
    {
        $this->state = $state;

        return $this;
    }
}

And the State.php entity:

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * State
 *
 * @ORM\Table(name="state")
 * @ORM\Entity
 */
class State
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="bigint", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255, nullable=false)
     */
    private $name;

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

    public function getName(): ?string
    {
        return $this->nombre;
    }

    public function setName(string $name): self
    {
        $this->name = $name;

        return $this;
    }
}

In our case, they were automatically created using doctrine:mapping:import (using reverse engineering). Then, we created the CRUD through generate:doctrine:crud. This would generate the views where the user should be able to see all the items in the database and the form to create and edit the Person entities:

<?php

namespace App\Controller;

use App\Entity\Person;
use App\Form\PersonType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

/**
 * @Route("/person")
 */
class PersonController extends AbstractController
{
    /**
     * @Route("/", name="person_index", methods={"GET"})
     */
    public function index(): Response
    {
        // .. //
    }

    /**
     * @Route("/new", name="person_new", methods={"GET","POST"})
     */
    public function new(Request $request): Response
    {
        $persona = new person();
        $form = $this->createForm(PersonType::class, $persona);
        $form->handleRequest($request);

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

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

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

    /**
     * @Route("/{id}", name="person_show", methods={"GET"})
     */
    public function show(person $persona): Response
    {
        // .. //
    }

    /**
     * @Route("/{id}/edit", name="person_edit", methods={"GET","POST"})
     */
    public function edit(Request $request, person $persona): Response
    {
        // .. //
    }

    /**
     * @Route("/{id}", name="person_delete", methods={"DELETE"})
     */
    public function delete(Request $request, person $persona): Response
    {
        // .. //
    }
}

Now, if the user visits either the edit or new route, the exception will appear.

Cause and solution

The only reason why this error appears is because there's no magic __toString method in the State entity:

<?php

class MyEntity
{
    public function __toString() {
        return $this->somePropertyOrPlainString;
    }
}

Even though we are in the Person form. Basically, because when the form is rendered, Symfony doesn't know what should be displayed on the select field causing the error, so in this case, as the select (state_id) should allow the user to select one of the states registered in the database, when the entities in the list are printed as a string, we should return the name property of the entity returning its value in the magic method:

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * State
 *
 * @ORM\Table(name="state")
 * @ORM\Entity
 */
class State
{
    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255, nullable=false)
     */
    private $nombre;

    // Register Magic Method to Print the name of the State e.g California
    public function __toString() {
        return $this->name;
    }
}

Allowing the form to render a list of states without any exception:

Symfony 5 Cast Entity as String

Happy coding ❤️!


Senior Software Engineer at Software Medico. Interested in programming since he was 14 years old, Carlos is a self-taught programmer and founder and author of most of the articles at Our Code World.

Sponsors