ワンクリックで
add-model
Add a Doctrine entity as a Sylius Resource
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Add a Doctrine entity as a Sylius Resource
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Implement the fix described in a GitHub issue and open a Pull Request that closes it
Apply the latest review feedback to a Pull Request and push it to the PR branch
Add an admin autocomplete form type for a Sylius Resource (translatable or not), optionally injected into another form via an extension
Add an admin FormType for an existing Sylius Resource
Add a Sylius admin grid for an existing Sylius Resource
Add a multiple images collection (OneToMany) to an existing Sylius Resource
| name | add-model |
| description | Add a Doctrine entity as a Sylius Resource |
| argument-hint | [ModelName] |
| allowed-tools | AskUserQuestion, Bash, Read, Edit, Write, Glob, Grep |
Ask the user for the ModelName if not provided, the list of fields with their types, and any relations to other resources.
Group by domain like Sylius-Standard (src/Entity/Product/, src/Entity/Customer/):
{Parent}Image, {Parent}Translation, …) → src/Entity/{Parent}/src/Entity/{ModelName}/src/Entity/{ModelName}/{ModelName}Interface.php:
<?php
declare(strict_types=1);
namespace $SYLIUS_NAMESPACE\Entity\{ModelName};
use Sylius\Resource\Model\ResourceInterface;
interface {ModelName}Interface extends ResourceInterface
{
public function getId(): ?int;
// declare the getter (and setter if mutable) for every field and relation added in step 2
}
src/Entity/{ModelName}/{ModelName}.php:
<?php
declare(strict_types=1);
namespace $SYLIUS_NAMESPACE\Entity\{ModelName};
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
#[ORM\Table(name: '${SYLIUS_PREFIX}_{model_snake}')]
class {ModelName} implements {ModelName}Interface
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
protected ?int $id = null;
public function getId(): ?int
{
return $this->id;
}
// add your fields here
}
For fields that require validation, add Symfony constraints directly on the property:
use Symfony\Component\Validator\Constraints as Assert;
#[Assert\NotBlank]
#[Assert\Length(max: 255)]
#[ORM\Column(length: 255)]
private ?string $title = null;
For relations to another resource in the same project, always use the target's interface as targetEntity — Sylius's ResolveTargetEntityListener resolves it at runtime from the interface: key in the resource config. In forms, EntityType does not go through this listener — pass the concrete class or use /sylius-plugin:add-autocomplete.
ManyToOne — {ModelName} belongs to one {RelatedModel}:
#[ORM\ManyToOne(targetEntity: {RelatedModel}Interface::class)]
private ?{RelatedModel}Interface ${related_model} = null;
OneToMany (inverse side) — {ModelName} has many {RelatedModel}. Initialize the collection in the constructor. Requires the owning side ({RelatedModel} entity) to declare a matching ManyToOne field named {model_snake}:
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
#[ORM\OneToMany(mappedBy: '{model_snake}', targetEntity: {RelatedModel}Interface::class)]
private Collection ${related_model_plural};
public function __construct()
{
$this->{related_model_plural} = new ArrayCollection();
}
Add the canonical Sylius adder/remover pair so LiveCollectionType and other form types sync the inverse side correctly:
public function add{RelatedModel}({RelatedModel}Interface ${related_model}): void
{
if (!$this->{related_model_plural}->contains(${related_model})) {
$this->{related_model_plural}->add(${related_model});
${related_model}->set{ModelName}($this);
}
}
public function remove{RelatedModel}({RelatedModel}Interface ${related_model}): void
{
if ($this->{related_model_plural}->removeElement(${related_model})) {
${related_model}->set{ModelName}(null);
}
}
Same adder/remover pattern for ManyToMany — omit the inverse sync call (no owning-side field to update on the other entity).
ManyToMany:
#[ORM\ManyToMany(targetEntity: {RelatedModel}Interface::class)]
private Collection ${related_model_plural};
public function __construct()
{
$this->{related_model_plural} = new ArrayCollection();
}
To reach a Sylius core entity from a plugin (e.g. attach plugin data to Product), do not add a relation on the plugin entity — use /sylius-plugin:extends-model + a plugin-provided trait instead (the FK lives on the extended core entity).
Create config/resources/{model_snake}.yaml at the plugin root (one file per resource — matches ProductBundlePlugin / MolliePlugin convention). Add the glob import once to the plugin's config/config.yaml: - { resource: "resources/*.yaml" }. The test app loads @{PluginBundle}/config/config.yaml via its own tests/TestApplication/config/config.yaml, which cascades the import.
sylius_resource:
resources:
${SYLIUS_PREFIX}.{model_snake}:
driver: doctrine/orm
classes:
model: $SYLIUS_NAMESPACE\Entity\{ModelName}\{ModelName}
interface: $SYLIUS_NAMESPACE\Entity\{ModelName}\{ModelName}Interface
The plugin's DI extension declares the DoctrineMigrations namespace via PrependDoctrineMigrationsTrait, so generate into it:
vendor/bin/console doctrine:migrations:diff --namespace=DoctrineMigrations
Always review the generated migration before applying. doctrine:migrations:diff captures every difference between mapping and DB — including pre-existing schema drift unrelated to your model (e.g. ALTER TABLE messenger_messages ... from a Sylius update never migrated locally). The migration should only contain CREATE TABLE ${SYLIUS_PREFIX}_{model_snake} + its indexes/FKs.
If unrelated SQL is present, manually trim the migration up()/down() to keep only your table — the drift belongs to the test app baseline, not your plugin.
Then apply:
vendor/bin/console doctrine:migrations:migrate --no-interaction
vendor/bin/console cache:clear
vendor/bin/console sylius:debug:resource '$SYLIUS_NAMESPACE\Entity\{ModelName}\{ModelName}' prints the resource metadata (alias ${SYLIUS_PREFIX}.{model_snake}, model + interface classes)vendor/bin/console doctrine:query:sql "DESCRIBE ${SYLIUS_PREFIX}_{model_snake}" lists the expected columns (id, plus user fields)/sylius-plugin:add-form to add an admin form/sylius-plugin:add-translatable-model if the model needs translations/sylius-plugin:add-grid, then /sylius-plugin:add-routes, then /sylius-plugin:add-menu