Creating a Custom Data Mapper for Symfony2 Forms


Symfony 2 has an amazing Form Component, however it is very complex and most users will have a hard time understanding the component. In the future I suspect that there will be more data mappers that you can use along with an easier way to configure these by creating a service and telling the configuration files to use your data mapper or even a different one.

The problem that I have run into time and time again is that I want the ability to use an EAV data model, but the form component does not allow this out of the box. So in order for me to use an EAV data model, I need to create a custom EAV data mapper.

By default, symfony 2 using a data mapper that uses getters and setters to modify objects. What if your object doesn’t have any getters or setters, and instead has a list of various attributes associated with it?

The first step to this is to create your custom data mapper.

<?php

namespace AppBundle\Form\DataMapper;

use Symfony\Component\Form\DataMapperInterface;

class EavMapper implements DataMapperInterface
{
    private $_em;

    public function __construct($manager)
    {
        $this->_em = $manager;
    }

    public function mapDataToForms($data, $forms)
    {
        // ...
    }

    public function mapFormsToData($forms, &$data)
    {
        // ...
    }
}

Next you will need to setup the form factory to use your custom data mapper.

<?php

namespace AppBundle\Controller;

use AppBundle\Form\EntityForm;
use AppBundle\Form\DataMapper\EavMapper;

// ...

    private function makeForm($entity)
    {
        $factory = $this->container->get('form.factory');
        $builder = $factory->createBuilder(new EntityForm(), $entity, array(
            'action' => $this->generateUrl('admin_eav_entity_create'),
            'method' => 'POST',
        ));
        $builder->setDataMapper(new EavMapper($this->getDoctrine()->getManager()));
        $form = $builder->getForm();

        return $form;
    }

// ...

This code will go into one of your controllers. You can play around with this Data Mapper and get it working the way you want.

The only reason you would ever want to do something like this is when you have objects that do not conform to a getter and setter model. If your objects have getters and setters, this is not what you want to do. Instead look into using events or data transformers.

Here are some links to some more information about the form component: