Pour celles et ceux qui le souhaitent, vous pouvez utiliser MakerBundle pour générer vos entités :
cd apps/sylius && symfony composer require --dev symfony/maker-bundle
Cependant, dans ce tutoriel, nous allons tout faire manuellement, sans utiliser cet outil.
erDiagram
Constructor {
int id PK
string logo
string name
}
erDiagram
Constructor {
int id PK
string logo
string name
}
Nous allons commencer par créer l'entité la plus simple : Constructor.
Avant cela, nous allons d'abord définir une interface.
Ce n'est pas obligatoire, mais si vous développez un plugin, il est recommandé d'ajouter une interface. Cela permet aux utilisateurs de l'étendre selon leurs besoins.
<?php
declare(strict_types=1);
namespace App\Entity\Constructor;
use Sylius\Component\Resource\Model\ResourceInterface;
use Sylius\Resource\Model\TimestampableInterface;
interface ConstructorInterface extends ResourceInterface, TimestampableInterface
{
public function getName(): ?string;
public function setName(?string $name): void;
public function getLogo(): ?string;
public function setLogo(?string $logo): void;
}
Nous étendons deux interfaces :
ResourceInterface : permet d'implémenter les fonctionnalités d'une ressource Sylius.TimestampableInterface : ajoute automatiquement les méthodes qui nous permettront de gérer des champs created_at et updated_at.Si vous ne souhaitez pas avoir d'informations de date de création et/ou de modification de votre entité, l'utilisation du TimestampableInterface n'est pas nécessaire.
Penchons nous maintenant sur la classe de l'entité :
<?php
declare(strict_types=1);
namespace App\Entity\Game;
use App\Repository\Game\ConstructorRepository;
use DateTimeInterface;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Sylius\Component\Resource\Model\TimestampableTrait;
use Sylius\Resource\Metadata\AsResource;
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: ConstructorRepository::class)]
#[ORM\Table(name: 'app_constructor')]
#[AsResource]
class Constructor implements ConstructorInterface
{
use TimestampableTrait;
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[Assert\NotBlank()]
#[ORM\Column(length: 255, nullable: true)]
private ?string $name = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $logo = null;
/**
* @var ?DateTimeInterface
*/
#[ORM\Column(name: 'created_at', type: 'datetime_immutable')]
#[Gedmo\Timestampable(on: 'create')]
protected $createdAt;
/**
* @var ?DateTimeInterface
*/
#[ORM\Column(name: 'updated_at', type: 'datetime')]
#[Gedmo\Timestampable(on: 'update')]
protected $updatedAt;
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(?string $name): void
{
$this->name = $name;
}
public function getLogo(): ?string
{
return $this->logo;
}
public function setLogo(?string $logo): void
{
$this->logo = $logo;
}
}
created_at et updated_at.Si vous ne souhaitez pas avoir d'informations de date de création et/ou de modification de votre entité, l'utilisation du TimestampableTrait n'est pas nécessaire.
Avant de générer la migration. Je vous propose de créer et d'expliquer rapidement la création du repository.
Comme précédemment, nous nous considérons dans un contexte de plugin où nos classes sont surchargeables par des projets tiers. Nous allons donc créer une interface pour notre repository. Pour le moment, étant donné que nous n'avons pas de méthode particulière, nous n'aurons qu'une interface vide.
Attention à bien étendrela RepositoryInterface proposé par Sylius Resource.
<?php
declare(strict_types=1);
namespace App\Repository\Game;
use Sylius\Component\Resource\Repository\RepositoryInterface;
interface ConstructorRepositoryInterface extends RepositoryInterface
{
}
Puis le code de notre repository en lui même.
<?php
declare(strict_types=1);
namespace App\Repository\Game;
use App\Entity\Game\Constructor;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use Sylius\Bundle\ResourceBundle\Doctrine\ORM\ResourceRepositoryTrait;
class ConstructorRepository extends ServiceEntityRepository implements ConstructorRepositoryInterface
{
use ResourceRepositoryTrait;
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Constructor::class);
}
}
Nous pouvons maintenant générer la migration :
± symfony console doctrine:migrations:diff --namespace="App"
Generated new migration class to "/Users/mhuran/Sites/sylius-tutorials/apps/sylius/migrations/Version20250118134804.php"
To run just this migration for testing purposes, you can use migrations:execute --up 'App\\Version20250118134804'
To revert the migration you can use migrations:execute --down 'App\\Version20250118134804'
Puis, nous appliquons cette migration :
± symfony console doctrine:migrations:migrate
WARNING! You are about to execute a migration in database "sylius_dev" that could result in schema changes and data loss. Are you sure you wish to continue? (yes/no) [yes]:
> yes
[notice] Migrating up to App\Version20250118134804
[notice] finished in 25.2ms, used 100.5M memory, 1 migrations executed, 1 sql queries
[OK] Successfully migrated to version: App\Version20250118134804
Pour vérifier si notre ressource Constructor est bien enregistrée dans Sylius, nous pouvons utiliser la commande suivante :
± sf console sylius:debug:resource
---------------------------------------------
Alias
---------------------------------------------
app.constructor
sylius.address
sylius.address_log_entry
sylius.adjustment
...
---------------------------------------------
Notre resource app.constructor est bien là ! Vous pouvez relancer la commande avec le nom de la ressource en paramètre pour afficher ses informations complètes.
± sf console sylius:debug:resource app.constructor
Configuration
-------------
----------------------- ---------------------------------------------------------------------------------
Option Value
----------------------- ---------------------------------------------------------------------------------
name "constructor"
applicationName "app"
driver "doctrine/orm"
stateMachineComponent null
templatesNamespace null
classes [
"model" => "App\Entity\Constructor\Constructor",
"controller" => "Sylius\Bundle\ResourceBundle\Controller\ResourceController",
"factory" => "Sylius\Resource\Factory\Factory",
"form" => "Sylius\Bundle\ResourceBundle\Form\Type\DefaultResourceType"
]
----------------------- ---------------------------------------------------------------------------------
New Resource Metadata
---------------------
------------------------ --------------------------------------
Option Value
------------------------ --------------------------------------
alias "app.constructor"
section null
formType null
templatesDir null
routePrefix null
name "constructor"
pluralName null
applicationName "app"
identifier null
normalizationContext null
denormalizationContext null
validationContext null
class "App\Entity\Constructor\Constructor"
driver null
vars null
------------------------ --------------------------------------
------------------------ --------------------------------------
Option Value
------------------------ --------------------------------------
alias "app.constructor"
section null
formType null
templatesDir null
routePrefix null
name "constructor"
pluralName null
applicationName "app"
identifier null
normalizationContext null
denormalizationContext null
validationContext null
class "App\Entity\Constructor\Constructor"
driver null
vars null
------------------------ --------------------------------------
New operations
--------------
[INFO] This resource has no defined operations.
---
Sylius va gérer pour nous automatiquement tout un tas de services bien pratiques ! Nous aurons l'occasion de nous en servir très prochainement et aussi d'en personnaliser par la suite ☺️
± sf console debug:container | grep -i constructor
App\Repository\Game\ConstructorRepository App\Repository\Game\ConstructorRepository
App\Repository\Game\ConstructorRepositoryInterface alias for "App\Repository\Game\ConstructorRepository"
Doctrine\Common\Collections\Selectable $constructorRepository alias for "app.repository.constructor"
Doctrine\Common\Persistence\ObjectManager $constructorManager alias for "doctrine.orm.default_entity_manager"
Doctrine\ORM\EntityManagerInterface $constructorManager alias for "doctrine.orm.default_entity_manager"
Doctrine\ORM\EntityRepository $constructorRepository alias for "app.repository.constructor"
Doctrine\Persistence\ObjectManager $constructorManager alias for "doctrine.orm.default_entity_manager"
Doctrine\Persistence\ObjectRepository $constructorRepository alias for "app.repository.constructor"
Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository $constructorRepository alias for "app.repository.constructor"
Sylius\Component\Resource\Factory\FactoryInterface $constructorFactory alias for "app.factory.constructor"
Sylius\Component\Resource\Repository\RepositoryInterface $constructorRepository alias for "app.repository.constructor"
Sylius\Resource\Doctrine\Persistence\RepositoryInterface $constructorRepository alias for "app.repository.constructor"
Sylius\Resource\Factory\Factory $constructorFactory alias for "app.factory.constructor"
Sylius\Resource\Factory\FactoryInterface $constructorFactory alias for "app.factory.constructor"
app.controller.constructor Sylius\Bundle\ResourceBundle\Controller\ResourceController
app.controller_state_machine.constructor alias for "sylius.resource_controller.state_machine"
app.factory.constructor Sylius\Resource\Factory\Factory
app.manager.constructor alias for "doctrine.orm.default_entity_manager"
app.repository.constructor Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository
La classe AsResource propose tout un tas de paramètres lors de son utilisation.
Pour le moment, nous n'avons rien mis, mais voici toutes les variables possibles :
<?php
// ...
final class AsResource
{
public function __construct(
private ?string $alias = null,
private ?string $section = null,
private ?string $formType = null,
private ?string $templatesDir = null,
private ?string $routePrefix = null,
private ?string $name = null,
private ?string $pluralName = null,
private ?string $applicationName = null,
private ?string $identifier = null,
private ?array $normalizationContext = null,
private ?array $denormalizationContext = null,
private ?array $validationContext = null,
private ?string $class = null,
private string|false|null $driver = null,
private ?array $vars = null,
private ?array $operations = null,
) {
}
]
// ...
Voyons ensemble quelques-uns de ces paramètres :
Dans Sylius, une ressource est définie avec plusieurs options qui influencent son comportement et son affichage dans les templates Twig.
alias → Définition de la ressource
Cet alias permet d’identifier la ressource dans l’application. De la forme <applicationName>.<name>
Dans le cadre d'un plugin, cela pourrait être maximehuran_games_plugin.constructor ou on pourrait mettre app.constructeur
⚠️ La partie <name> va servir à Sylius pour définir tous les services automatiquement générés par Sylius pour ses ressources comme vu précédemment
En mettant app.constructeur cela renommerait tous les services. Si vous voulez changer ce nom, soyez prudents !
#[AsResource(alias: 'app.constructeur')]
name → Nom de la variable dans les templatesconstructor sera remplacée par constructeur si l’on définit :#[AsResource(name: 'constructeur')]
pluralName → Nom au pluriel dans les templates#[AsResource(pluralName: 'constructeurs')]
id. Il est possible de le modifier avec l’attribut identifier.#[AsResource(identifier: 'code')]
Le but n'est pas de tout détailler, mais de découvrir au fur et à mesure les possibilités offertes par tous ces paramètres.
Dans le prochain tutoriel. Nous aborderons la génération des fixtures pour notre entité Constructor. Cela permettra de bien appréhender la création de celle-ci avec des champs simples dans un premier temps (Notre entité étant très basique). Ensuite, nous aurons du concret, car viendra le temps des affichages dans le panneau d'administration.