This course is still being released! Check back later for more chapters.

Get Notified About this Course!

We will send you messages regarding this course only
and nothing else, we promise.
You can unsubscribe anytime by emailing us at:
privacy@symfonycasts.com
Login to bookmark this video
Buy Access to Course
03.

Starship Entity

|

Share this awesome video!

|

We have a database and can connect to it but... it doesn't have any tables!

The Doctrine ORM uses PHP classes to represent tables in the database, like if you need a table for products, you create a Product class. Doctrine calls these classes "entities", but they're really just standard boring PHP classes. I like boring!

In our StarShop app, we need to track Starships... so we need a Starship table... so we need a Starship entity class. What does a Starship look like? In the last tutorial, we created a Starship model class in the src/Model directory. Open it up. We decided that each Starship has an id, name, class, captain, status, and arrivedAt.

This is almost a Doctrine entity: it's just missing some config that helps Doctrine understand how to map this class to a table in the database. We could easily add that by hand. But... we have a tool that can do this for us: the MakerBundle!

make:entity

Run:

symfony console make:entity

For the name, use Starship. We're not using Symfony UX Turbo, so answer no to that question. This already created a Starship class in the Entity/ directory and a StarshipRepository class. We'll talk about that later.

But we're not done! This command is awesome: it interactively asks what properties - or columns if you want to think that way - our entity needs. Jump back to the Starship model to see what we need. MakerBundle will add id automatically, so skip to name. Field type? Use the default: string. Field length? 255 is fine. Can this field be null in the database? No, every Starship needs a name.

Next is class, it'll be the same as name... then captain is also a simple string. Next: status. Doctrine defaults to a string, but... look at our Starship model, status is an enum. How can we map this to a column? Back in the terminal, hit ? to see all the different types we can add. At the bottom... enum! Use that. Enum class? Use the full class name of our enum: App\Model\StarshipStatusEnum.

Can this field store multiple values? No, a Starship can only have one status at a time. Can this field be null? Nope!

Finally, add arrivedAt. Cool! Maker defaults to datetime_immutable instead of string. This is because we suffixed our property name with At. Smart! Can this field be null? No.

[ORM\Entity]

Let's take a look at our newly minted Starship entity: in src/Entity/.

Notice: this is a standard PHP class with properties... and one special thing: some PHP attributes:

The #[ORM\Entity] attribute on the class tells Doctrine that this not just a boring PHP class, but an entity that should be mapped to a table in our database. The table name can be customized, but we'll use the default which is the snake cased class name: starship.

[ORM\Column]

Check out the properties: each has #[ORM\Column]. This tells Doctrine that these properties are columns in our table. For the type, Doctrine is smart and guesses from the type hint. For example, id will be an integer type, name will be a string type, and arrivedAt will be a timestamp type. Nice!

97 lines | src/Entity/Starship.php
// ... lines 1 - 8
#[ORM\Entity(repositoryClass: StarshipRepository::class)]
class Starship
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 255)]
private ?string $name = null;
#[ORM\Column(length: 255)]
private ?string $class = null;
#[ORM\Column(length: 255)]
private ?string $captain = null;
#[ORM\Column(enumType: StarshipStatusEnum::class)]
private ?StarshipStatusEnum $status = null;
#[ORM\Column]
private ?\DateTimeImmutable $arrivedAt = null;
// ... lines 31 - 95
}

id has a few extra attributes that mark it as the primary key and tells the database to auto-generate this as an auto-incrementing integer.

Oh, and we can remove the length argument from the string columns: this is the default.

111 lines | src/Entity/Starship.php
// ... lines 1 - 9
class Starship
{
// ... lines 12 - 16
#[ORM\Column]
private ?string $name = null;
#[ORM\Column]
private ?string $class = null;
#[ORM\Column]
private ?string $captain = null;
// ... lines 25 - 109
}

The status property is a StarshipStatusEnum type but Doctrine will store this as a string in the database. Cool! We can actually remove the enumType argument: Doctrine can guess that from the property type too!

111 lines | src/Entity/Starship.php
// ... lines 1 - 9
class Starship
{
// ... lines 12 - 25
#[ORM\Column]
private ?StarshipStatusEnum $status = null;
// ... lines 28 - 109
}

Down below, the maker generated getters and setters for all our properties. Our old Starship model had two extra methods: getStatusString() and getStatusImageFilename(). Copy those from the model class... and at the bottom of the entity class, paste!

111 lines | src/Entity/Starship.php
// ... lines 1 - 9
class Starship
{
// ... lines 12 - 96
public function getStatusString(): string
{
return $this->status->value;
}
public function getStatusImageFilename(): string
{
return match ($this->status) {
StarshipStatusEnum::WAITING => 'images/status-waiting.png',
StarshipStatusEnum::IN_PROGRESS => 'images/status-in-progress.png',
StarshipStatusEnum::COMPLETED => 'images/status-complete.png',
};
}
}

Entity done! We can even double-check our work. At your terminal, run:

Schema Validation

symfony console doctrine:schema:validate

This means that Doctrine sees and can read our attributes. Then... our database is out of sync?

We have an entity class... but we don't actually have the starship table in the database.

There are a few ways to get the table into the database, but the best way is migrations. That's next!