How to add a custom translatable model? ======================================= In this guide we will create a new translatable model in our system, which is quite similar to :doc:`adding a simple model `, although it requires some additional steps. As an example we will take a **translatable Supplier entity**, which may be really useful for shop maintenance. 1. Define your needs -------------------- A Supplier needs three essential fields: ``name``, ``description`` and ``enabled`` flag. The **name and description** fields need to be translatable. 2. Generate the SupplierTranslation entity ------------------------------------------ Symfony, the framework Sylius uses, provides the `Symfony MakerBundle `_, that simplifies the process of adding a model. .. warning:: Remember to have the ``MakerBundle`` imported in the AppKernel, as it is not there by default. You need to use such a command in your project directory. .. code-block:: bash php bin/console make:entity The generator will ask you for the entity name and fields. See how it should look like to match our assumptions. .. image:: ../../_images/generating_translation_entity.png :align: center As you can see we have provided only the desired translatable fields. Below the final ``SupplierTranslation`` class is presented, it implements the ``ResourceInterface``. .. code-block:: php id; } /** * @param string $name */ public function setName($name) { $this->name = $name; } /** * @return string */ public function getName() { return $this->name; } /** * @param string $description */ public function setDescription($description) { $this->description = $description; } /** * @return string */ public function getDescription() { return $this->description; } } 3. Generate the Supplier entity ------------------------------- While generating the entity, similarly to the way the translation was generated, we are providing only non-translatable fields. In our case only the ``enabled`` field. .. image:: ../../_images/generating_basic_entity.png :align: center Having the stubs generated, we need to extend our class with a connection to SupplierTranslation. * implement the ``ResourceInterface``, * implement the ``TranslatableInterface``, * use the ``TranslatableTrait``, * initialize the translations collection in the constructor, * add the ``createTranslation()`` method, * implement getters and setters for the properties that are held on the translation model. As a result you should get such a ``Supplier`` class: .. code-block:: php initializeTranslationsCollection(); } /** * @var int */ private $id; /** * @var bool */ private $enabled; /** * @return int */ public function getId() { return $this->id; } /** * @param string $name */ public function setName($name) { $this->getTranslation()->setName($name); } /** * @return string */ public function getName() { return $this->getTranslation()->getName(); } /** * @param string $description */ public function setDescription($description) { $this->getTranslation()->setDescription($description); } /** * @return string */ public function getDescription() { return $this->getTranslation()->getDescription(); } /** * @param boolean $enabled */ public function setEnabled($enabled) { $this->enabled = $enabled; } /** * @return bool */ public function getEnabled() { return $this->enabled; } /** * {@inheritdoc} */ protected function createTranslation() { return new SupplierTranslation(); } } 4. Register your entity together with translation as a Sylius resource ---------------------------------------------------------------------- If you don't have it yet, create a file ``config/packages/sylius_resource.yaml``. .. code-block:: yaml # config/packages/sylius_resource.yaml sylius_resource: resources: app.supplier: driver: doctrine/orm # You can use also different driver here classes: model: App\Entity\Supplier translation: classes: model: App\Entity\SupplierTranslation To check if the process was run correctly run such a command: .. code-block:: bash php bin/console debug:container | grep supplier The output should be: .. image:: ../../_images/container_debug_supplier_translation.png :align: center 5. Update the database using migrations --------------------------------------- Assuming that your database was up-to-date before adding the new entity, run: .. code-block:: bash php bin/console doctrine:migrations:diff This will generate a new migration file which adds the Supplier entity to your database. Then update the database using the generated migration: .. code-block:: bash php bin/console doctrine:migrations:migrate 6. Prepare new forms for your entity, that will be aware of its translation --------------------------------------------------------------------------- You will need both ``SupplierType`` and ``SupplierTranslationType``. Let's start with the translation type, as it will be included into the entity type. .. code-block:: php add('name', TextType::class) ->add('description', TextareaType::class, [ 'required' => false, ]) ; } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'app_supplier_translation'; } } On the ``SupplierTranslationType`` we need to define only the translatable fields. Then let's prepare the entity type, that will include the translation type. .. code-block:: php add('translations', ResourceTranslationsType::class, [ 'entry_type' => SupplierTranslationType::class, ]) ->add('enabled', CheckboxType::class, [ 'required' => false, ]) ; } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'app_supplier'; } } 7. Register the new forms as services ------------------------------------- Before the newly created forms will be ready to use them, they need to be registered as services: .. code-block:: yaml # config/services.yaml services: app.supplier.form.type: class: App\Form\Type\SupplierType tags: - { name: form.type } arguments: ['%app.model.supplier.class%', ['sylius']] app.supplier_translation.form.type: class: App\Form\Type\SupplierTranslationType tags: - { name: form.type } arguments: ['%app.model.supplier_translation.class%', ['sylius']] 8. Register the forms as resource forms of the Supplier entity -------------------------------------------------------------- Extend the resource configuration of the ``app.supplier`` with forms: .. code-block:: yaml # config/resources.yaml sylius_resource: resources: app.supplier: driver: doctrine/orm # You can use also different driver here classes: model: App\Entity\Supplier form: App\Form\Type\SupplierType translation: classes: model: App\Entity\SupplierTranslation form: App\Form\Type\SupplierTranslationType 9. Define grid structure for the new entity ------------------------------------------- To have templates for your Entity administration out of the box you can use Grids. Here you can see how to configure a grid for the Supplier entity. .. code-block:: yaml # config/packages/_sylius.yaml sylius_grid: grids: app_admin_supplier: driver: name: doctrine/orm options: class: App\Entity\Supplier fields: name: type: string label: sylius.ui.name sortable: translation.name enabled: type: twig label: sylius.ui.enabled options: template: "@SyliusUi/Grid/Field/enabled.html.twig" actions: main: create: type: create item: update: type: update delete: type: delete 10. Create template ------------------- .. code-block:: twig # App/Resources/views/Supplier/_form.html.twig {% from '@SyliusAdmin/Macro/translationForm.html.twig' import translationForm %} {{ form_errors(form) }} {{ translationForm(form.translations) }} {{ form_row(form.enabled) }} 11. Define routing for entity administration -------------------------------------------- Having a grid prepared we can configure routing for the entity administration: .. code-block:: yaml # config/routes.yaml app_admin_supplier: resource: | alias: app.supplier section: admin templates: "@SyliusAdmin\\Crud" redirect: update grid: app_admin_supplier vars: all: subheader: app.ui.supplier templates: form: App:Supplier:_form.html.twig index: icon: 'file image outline' type: sylius.resource prefix: admin 12. Add entity administration to the admin menu ----------------------------------------------- .. tip:: See :doc:`how to add links to your new entity administration in the administration menu `. 13. Check the admin panel for your changes ------------------------------------------ .. tip:: To see what you can do with your new entity access the ``http://localhost:8000/admin/suppliers/`` url. Learn more ---------- * `GridBundle documentation `_ * `ResourceBundle documentation `_ * :doc:`Customization Guide `