Categories
Software Development Web Development

Symfony doctrine remove column from entity table

As a newcomer to Doctrine I had to google and dig to figure this out. Explanation here.

Basically if you want to remove a column from a table when using Doctrine and Symfony Entities all you do is remove the variable and the matching getter/setter methods from the Entity, then run a diff.

php bin/console doctrine:migrations:diff

instead of making a migration, this command makes the migration file for you. Then you can run this command to change the table.

php bin/console doctrine:migrations:migrate

What is happening is Doctrine ORM is used to map the Database tables to an Entity. Every Doctrine/Symfony Entity matches 1 table in a database.

Lets view an example. This Entity should be familiar to anyone who created an app using the Symfony maker system. User.php should be located in app\src\Entity\User.php and it looks basically like this.


<?php namespace App\Entity; use App\Repository\UserRepository; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Security\Core\User\UserInterface; /** * User * * @ORM\Table(name="user", uniqueConstraints={@ORM\UniqueConstraint(name="email_UNIQUE", columns={"email"})}, indexes={@ORM\Index(name="email", columns={"email"})}) * @ORM\Entity(repositoryClass=UserRepository::class) */ class User implements UserInterface { /** * @var int * * @ORM\Column(name="id", type="bigint", nullable=false, options={"unsigned"=true}) * @ORM\Id * @ORM\GeneratedValue(strategy="IDENTITY") */ private int $id; /** * @var string * * @ORM\Column(name="email", type="string", length=255, nullable=false) */ private string $email; /** * @var string * * @ORM\Column(name="password", type="string", length=255, nullable=false) */ private string $password; /** * @var array|null * * @ORM\Column(name="roles", type="json", nullable=true) */ private ?array $roles; /** * @var string|null * * @ORM\Column(name="web_token", type="string", length=255, nullable=true) */ private ?string $webToken; /** * @var string|null * * @ORM\Column(name="api_token", type="string", length=255, nullable=true) */ private ?string $apiToken; public function getId(): ?string { return $this->id;
    }

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

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

        return $this;
    }

    public function getPassword(): ?string
    {
        return $this->password;
    }

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

        return $this;
    }

    public function getRoles(): ?array
    {
        return $this->roles;
    }

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

        return $this;
    }

    public function getWebToken(): ?string
    {
        return $this->webToken;
    }

    public function setWebToken(?string $webToken): self
    {
        $this->webToken = $webToken;

        return $this;
    }

    public function getApiToken(): ?string
    {
        return $this->apiToken;
    }

    public function setApiToken(?string $apiToken): self
    {
        $this->apiToken = $apiToken;

        return $this;
    }


    public function getSalt()
    {
        // TODO: Implement getSalt() method.
    }

    public function getUsername(): ?string
    {
        // TODO: Implement getUsername() method.
        return $this->getEmail();
    }

    public function eraseCredentials()
    {
        // TODO: Implement eraseCredentials() method.
    }
}

As you can see I have a web token and api token in this class. If I wanted to remove the web token from my database I simply remove the relate variable and getter/setters like so.


<?php namespace App\Entity; use App\Repository\UserRepository; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Security\Core\User\UserInterface; /** * User * * @ORM\Table(name="user", uniqueConstraints={@ORM\UniqueConstraint(name="email_UNIQUE", columns={"email"})}, indexes={@ORM\Index(name="email", columns={"email"})}) * @ORM\Entity(repositoryClass=UserRepository::class) */ class User implements UserInterface { /** * @var int * * @ORM\Column(name="id", type="bigint", nullable=false, options={"unsigned"=true}) * @ORM\Id * @ORM\GeneratedValue(strategy="IDENTITY") */ private int $id; /** * @var string * * @ORM\Column(name="email", type="string", length=255, nullable=false) */ private string $email; /** * @var string * * @ORM\Column(name="password", type="string", length=255, nullable=false) */ private string $password; /** * @var array|null * * @ORM\Column(name="roles", type="json", nullable=true) */ private ?array $roles; /** * @var string|null * * @ORM\Column(name="api_token", type="string", length=255, nullable=true) */ private ?string $apiToken; public function getId(): ?string { return $this->id;
    }

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

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

        return $this;
    }

    public function getPassword(): ?string
    {
        return $this->password;
    }

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

        return $this;
    }

    public function getRoles(): ?array
    {
        return $this->roles;
    }

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

        return $this;
    }

   

    public function getApiToken(): ?string
    {
        return $this->apiToken;
    }

    public function setApiToken(?string $apiToken): self
    {
        $this->apiToken = $apiToken;

        return $this;
    }


    public function getSalt()
    {
        // TODO: Implement getSalt() method.
    }

    public function getUsername(): ?string
    {
        // TODO: Implement getUsername() method.
        return $this->getEmail();
    }

    public function eraseCredentials()
    {
        // TODO: Implement eraseCredentials() method.
    }
}

Now when you run the migrations:diff command a new migration file will be created. Inside that file will be the queries to make the changes in the “up” method of that migrations file. In the “down” method you will find the code to restore the database and add the column back, which will also update the Entity class.

After you run the diff you run a migration. Running the migration changes your database to match your changes in your Entity class.

3 replies on “Symfony doctrine remove column from entity table”

It’s dangerous to generate automatically. If you made changes in the previous migrations, that aren’t supported natively by doctrine (like default values or some custom SQL generated via PHP), then the `migrations:diff` (or `make:migration`) will try to restore previous state that might not make sense and silently revert your custom code.
Don’t trust doctrine auto-generation; always verify that what was generated makes sense to you.
It’s just a helper, not an automatic tool for avoiding to know SQL.
Also i think I read that it might be removed in the future.

Doctrine (and symfony bundle for doctrine) have a command to update DB schema without any migrations.

This is may be useful while developing, but not in production environment.

https://www.doctrine-project.org/projects/doctrine-orm/en/2.8/reference/tools.html

https://symfony.com/doc/3.3/doctrine.html#creating-the-database-tables-schema (link for outdated symfony version, because it is dropped from newer versions – may be related to dangerous behavior)

Thanks I started this thing way back in version 2. Didn’t work on it for a year + came back it was version 4. Got started and now it was version 5 time. This has been a slow learning experience. I spend a lot of time on github digging into the symfony source code just to find out how things work because so much is not in the docs for 5 and some of it causes errors. It was using smarty back when I started now it is twig.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.