Creating Entities with the Schema Generator [API Platform]
In the previous video we covered one way of generating an entity for use in your API Platform project. I'd say that approach would be fairly natural to you if you have any experience of Symfony 2, 3, or 4.
Another way might be to use the Symfony Maker bundle.
Manually defining an entity using either of these methods is possibly good enough. But the API Platform has a dedicated Schema Generator of its own to help us document our code in a way that works best with the API Platform setup.
I'd strongly recommend you check out the link above as there's only three short sections to read, and here we are only focusing on the 'how to', rather than the 'why'.
Technically the most specific match for what our data represents is a MusicAlbum
. I haven't added enough properties to our basic Album
representation to fully meet the Schema. Feel free to add more data, but it's not necessary to complete this tutorial.
According to the API Platform docs, to generate an MusicAlbum
data model, we may use something like this:
# api/config/schema.yaml
types:
# Parent class of everything
Thing:
properties:
name: ~
CreativeWork:
properties:
datePublished: ~
MusicPlaylist:
properties:
numTracks: ~
MusicAlbum: ~
I've had problems with this. Judging by what the documentation displays as expected output, here is a version that works for me:
# api/config/schema.yaml
types:
MusicAlbum:
properties:
name: ~
datePublished: ~
numTracks: ~
In order to generate this new MusicAlbum
entity, I can run the command:
docker-compose exec php php vendor/bin/schema generate-types src config/schema.yaml
Which is a little long winded. The first part is all Docker, so removing that we see the more natural command of:
vendor/bin/schema generate-types src config/schema.yaml
And a new MusicAlbum
is created:
<?php
declare(strict_types=1);
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* A collection of music tracks.
*
* @see http://schema.org/MusicAlbum Documentation on Schema.org
*
* @ORM\Entity
* @ApiResource(iri="http://schema.org/MusicAlbum")
*/
class MusicAlbum
{
/**
* @var int|null
*
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
* @ORM\Column(type="integer")
*/
private $id;
/**
* @var string|null the name of the item
*
* @ORM\Column(type="text", nullable=true)
* @ApiProperty(iri="http://schema.org/name")
*/
private $name;
/**
* @var \DateTimeInterface|null date of first broadcast/publication
*
* @ORM\Column(type="date", nullable=true)
* @ApiProperty(iri="http://schema.org/datePublished")
* @Assert\Date
*/
private $datePublished;
/**
* @var int|null the number of tracks in this album or playlist
*
* @ORM\Column(type="integer", nullable=true)
* @ApiProperty(iri="http://schema.org/numTracks")
*/
private $numTrack;
public function getId(): ?int
{
return $this->id;
}
public function setName(?string $name): void
{
$this->name = $name;
}
public function getName(): ?string
{
return $this->name;
}
public function setDatePublished(?\DateTimeInterface $datePublished): void
{
$this->datePublished = $datePublished;
}
public function getDatePublished(): ?\DateTimeInterface
{
return $this->datePublished;
}
public function setNumTrack(?int $numTrack): void
{
$this->numTrack = $numTrack;
}
public function getNumTrack(): ?int
{
return $this->numTrack;
}
}
Please do watch the video for a further probe into what we get in terms of generated output.
Immediately we hit on some problems here for our implementation.
The primary of which is that the resource, and property names no longer match up with our expectations.
Also some of the values are nullable
, which is unwanted. And we're missing an assertion that our Album must have at least one track.
My approach is somewhat of a hybrid. I take the generated ApiProperty
annotations and apply them to my own custom Album
entity:
<?php
// api/src/Entity/Album.php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiProperty;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Entity()
* @ApiResource(iri="http://schema.org/MusicAlbum")
*/
class Album
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @Assert\NotBlank()
* @ORM\column(type="string")
* @ApiProperty(iri="http://schema.org/name")
*/
private $title;
/**
* @var \DateTime|null
* @ORM\column(type="datetime")
* @ApiProperty(iri="http://schema.org/datePublished")
*/
private $releaseDate;
/**
* @Assert\GreaterThan(0)
* @ORM\column(type="integer")
* @ApiProperty(iri="http://schema.org/numTracks")
*/
private $trackCount;
/**
* @return int
*/
public function getId(): ?int
{
return $this->id;
}
/**
* @return string|null
*/
public function getTitle(): ?string
{
return $this->title;
}
/**
* @param string $title
*
* @return Album
*/
public function setTitle($title): Album
{
$this->title = $title;
return $this;
}
/**
* @return \DateTime|null
*/
public function getReleaseDate(): ?\DateTime
{
return $this->releaseDate;
}
/**
* @param \DateTime $releaseDate
*
* @return Album
*/
public function setReleaseDate($releaseDate): Album
{
$this->releaseDate = $releaseDate;
return $this;
}
/**
* @return int|null
*/
public function getTrackCount(): ?int
{
return $this->trackCount;
}
/**
* @param int $trackCount
*
* @return Album
*/
public function setTrackCount($trackCount): Album
{
$this->trackCount = $trackCount;
return $this;
}
}
For me and my needs, this is currently the best compromise.
However you generate an entity is your decision. The important part is your entity have the @ApiResource
annotation on the class itself.
At this stage I am assuming you have completed, or are about to complete the final step from the previous video whereby we update our database schema, and ensure a new set of routes are available for use.