Création d'une resource avec Sylius 2
Une fois le schéma de données spécifié, nous allons maintenant créer une première ressource simple.
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.
Entité Constructor
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;
}
Explications
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 champscreated_at
etupdated_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;
}
}
Explications
- Nous utilisons l'attribut PHP 8 AsResource pour signaler à Sylius que notre classe doit être considérée comme une ressource.
- Nous déclarons dès maintenant le repository que nous allons utiliser pour cette entité : ConstructorRepository.
- Nous utilisons TimestampableTrait qui nous permet d'avoir les méthodes nécessaires pour les champs
created_at
etupdated_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.
Repository pour l'entité Constructor
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);
}
}
Explications
- Nous étendons ServiceEntityRepository proposé par Doctrine
- Nous utilisons le ResourceRepositoryTrait qui nous permet d'implémenter les méthodes de la RepositoryInterface étendue par notre ConstructorRepositoryInterface
- Dans la méthode __construct, nous appelons la méthode du parent avec la classe de notre entité en second paramètre Constructor::class
Génération de la migration doctrine
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
Utiliser le debug pour vérifier notre ressource
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.
---
Les services crées par Sylius automatiquement
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
Explication des paramètres d'une ressource
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 templates
Cette option permet de renommer la variable utilisée dans les templates Twig.
Par exemple, dans les templates Twig, la variableconstructor
sera remplacée parconstructeur
si l’on définit :
#[AsResource(name: 'constructeur')]
-
pluralName
→ Nom au pluriel dans les templates
De la même manière, cette option définit le nom utilisé pour les collections d’éléments dans les templates.
Par exemple :
#[AsResource(pluralName: 'constructeurs')]
- Modification de l’identifiant de la ressource
Par défaut, l’identifiant d’une ressource est sonid
. Il est possible de le modifier avec l’attributidentifier
.
Par exemple, si vous avez une entité avec un champ code unique, vous pouvez l'utiliser :
#[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.
⚠️ La suite de la formation est en cours de rédaction