phpsymfonysymfony4sonata-adminsonata

Symfony 4: Use existing form type class in Sonata's configureFormFields method


I know I can pull individual form elements from the type's builder into the form mapper as described in the documentation:

You can add Symfony FormBuilderInterface instances to the FormMapper. This allows you to re-use a model form type. When adding a field using a FormBuilderInterface, the type is guessed.

Given you have a PostType like this:

use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\AbstractType;

class PostType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('author', EntityType::class, [
                'class' => User::class
            ])
            ->add('title', TextType::class)
            ->add('body', TextareaType::class)
        ;
    }
}

you can reuse it like this:

use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use App\Form\PostType;

class Post extend AbstractAdmin
{
    protected function configureFormFields(FormMapper $formMapper)
    {
        $builder = $formMapper->getFormBuilder()->getFormFactory()->createBuilder(PostType::class);

        $formMapper
            ->with('Post')
                ->add($builder->get('title'))
                ->add($builder->get('body'))
            ->end()
            ->with('Author')
                ->add($builder->get('author'))
            ->end()
        ;
    }
}

However, this feels clunky if all you want is for Sonata to use that exact type as is.

I was therefore wondering if there is a shorthand that tells sonata to simply use the entire form type as is.

Something like:

protected function configureFormFields(FormMapper $formMapper)
{
    $formMapper->mapForm((new PostType()));
}

Solution

  • Maybe the shorter version using inherit_data might be what you are looking for.

    https://symfony.com/doc/current/form/inherit_data_option.html

    From: How to inherit FormType in Sonata Admin?

    With the Post example

    use Sonata\AdminBundle\Form\FormMapper;
    use Sonata\AdminBundle\Admin\AbstractAdmin;
    use App\Form\PostType;
    
    class PostAdmin extend AbstractAdmin
    {
        protected function configureFormFields(FormMapper $formMapper)
        {
            $formMapper
                ->add(
                    'post',  // name does not seem to matter
                    PostType::class, 
                    [
                        'inherit_data' => true,
                    ]
                );
        }
    }
    
    

    Using PostAdmin (and PostType) to map a child record in a 1:m relationship works too, but has problems with inline options and the table view does not seem to render it in separate columns as expected.

    // Thread 1:m Post
    
    /**
     * @ORM\Entity
        ...
     */
    class Thread
    {
        protected $title = '';
    
        /**
         * @var Post[]|ArrayCollection
         *
         * @ORM\OneToMany(...)
         */
        protected posts;
    }
    
    class Post extend AbstractAdmin
    {
        protected function configureFormFields(FormMapper $formMapper)
        {
            $formMapper->
                ->with('Thread')
                ->add('title')
                ->add(
                    'posts',
                    'sonata_type_collection',
                    [
                        'label'        => 'Posts',
                        'required'     => false,
                        'by_reference' => false,
                    ],
                    [
                        'edit'     => 'inline', // does not seem to work
                        'inline'   => 'table',  // takes up one column in table
                        'multiple' => true,     // one row per entry
                    ]
                );
        }
    }