Search code examples
phpsymfonysonata-admin

ValueObject for sonata admin edit form instead of entity


Curently for edit entity, we pass pure Entity class to Symfony Form for example:

<?php
declare(strict_types=1);

class Foo 
{
    // private properties
    public function setFoo(?string $foo): void
    {
        $this->foo = $foo;
    }
    // more setters
}

this situation is bad because for a moment we have entity in invalid state.

Is any way to pass data form to ValueObject and after validation pass data into Entity? I don't want to have nullable every field in entity.

The same situation for getters for create new record.


Solution

  • We use custom model manager, that can works with dto, you can find it here https://gitlab.com/symfony-bro/sonata-things/blob/master/Admin/ModelManager/AbstractDtoManager.php Unfortunately we are using it in internaly projects, so no documentation. This is short example how to use:

    use SymfonyBro\SonataThings\Admin\ModelManager\AbstractDtoManager;
    
    class CatalogModelManager extends AbstractDtoManager
    {
        protected function doCreate($dto)
        {
            $result = new Catalog($dto->title, $dto->parent);
            $result->setDescription($dto->description);
    
            return $result;
        }
    
        protected function getModelClassName(): string
        {
            return CatalogDto::class;
        }
    
        protected function getSubjectClass(): string
        {
            return Catalog::class;
        }
    }
    

    You should define this as service (for example app_inventory.sonata_admin.catalog_model_manager) and update admin config

        app_inventory.admin.catalog:
            class: 'App\InventoryBundle\Admin\CatalogAdmin'
            arguments: [~, 'App\InventoryBundle\Entity\Catalog', 'SonataAdminBundle:CRUD']
            calls:
                - ['setModelManager', ['@app_inventory.sonata_admin.catalog_model_manager']]
            tags:
                - { name: 'sonata.admin', manager_type: 'orm', group: 'Equipment', label: 'Equipment type' }
    
    

    and this is dto

    class CatalogDto
    {
        public $id;
        public $title;
        public $description;
        public $parent;
        public $items;
    
        public function __construct()
        {
            $this->items = [];
        }
    
        public function getId()
        {
            return $this->id;
        }
    
        public function __toString()
        {
            return (string)$this->title;
        }
    }