Symfony2 DataTransformer for choice field

choicefield, mongodb, php, symfony

Solution

I finally found the solution. The culprit was the datatransformer (and mine, of course :-)) In this way the form shows the preselected values:

<?php
namespace www\DefaultBundle\Form\DataTransformer;

use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Extension\Core\ObjectChoiceList;
use Symfony\Component\Form\Exception\TransformationFailedException;
use Doctrine\Common\Persistence\ObjectManager;
use Acme\TaskBundle\Entity\Issue;

class AccessorioTransformer implements DataTransformerInterface
{
    /**
     * @var ObjectManager
     */
    private $om;

    /**
     * @param ObjectManager $om
     */
    public function __construct(ObjectManager $om)
    {
        $this->om = $om;
    }


    public function transform($values)
    {
        if ($values === null) return array();

        $choices = array();
        foreach ($values as $object)
        {
           $choices[] = sprintf("%s_%s", $object->getId(), basename(str_replace('\\', '/', get_class($object))));
        }

        return $choices;
    }


    public function reverseTransform($values)
    {
        if (!$values) return array();

        $array = array();

        foreach ($values as $value)
        {
          list($id, $type) = explode("_", $value);
          $array[] = $this->om->getRepository('wwwDefaultBundle:' . $type)->find($id);
        }

        return $array;
    }
}

Problem

I'm trying to create a custom choice list field. And almost all seems working, except the preselected values on the edit part. Basically i'm creating a mixed list field with multiple object type (the backend is mongodb), i know that is a dirty way to operate but i didn't find a better solution (keeping things simple). The process is working, i have a mixed objects in the backend and i can choose which one in the edit form, but the form doesn't show the preselected (with the values extracted from mongo) ``` <?php namespace www\DefaultBundle\Form\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use www\DefaultBundle\Form\DataTransformer\AccessorioTransformer; use Doctrine\Common\Persistence\ObjectManager; use Symfony\Component\OptionsResolver\OptionsResolverInterface; class AccessorioType extends AbstractType { /** * @var ObjectManager */ private $om; /** * @param ObjectManager $om */ public function __construct(ObjectManager $om) { $this->om = $om; } public function buildForm(FormBuilderInterface $builder, array $options) { $transformer = new AccessorioTransformer($this->om); $builder->addModelTransformer($transformer); } public function setDefaultOptions(OptionsResolverInterface $resolver) { $choices = array(); $data = array(); $documents = array( 'Document1', 'Document2', 'Document3', ); foreach ($documents as $document) { $objects = $this->om->getRepository('wwwDefaultBundle:' . $document)->findAll(); foreach ($objects as $object) { if (@!$object->getId()) print_r($object); $key = sprintf("%s_%s", $object->getId(), basename(str_replace('\\', '/', get_class($object)))); $value = sprintf("%s (%s)", $object, basename(str_replace('\\', '/', get_class($object)))); $choices[$key] = $value; } } $resolver->setDefaults(array( 'choices' => $choices, 'expanded' => false, 'multiple' => true, )); } public function getParent() { return 'choice'; } public function getName() { return 'accessorio'; } } ``` the datatransformer: ``` <?php namespace www\DefaultBundle\Form\DataTransformer; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Extension\Core\ObjectChoiceList; use Symfony\Component\Form\Exception\TransformationFailedException; use Doctrine\Common\Persistence\ObjectManager; use Acme\TaskBundle\Entity\Issue; class AccessorioTransformer implements DataTransformerInterface { /** * @var ObjectManager */ private $om; /** * @param ObjectManager $om */ public function __construct(ObjectManager $om) { $this->om = $om; } public function transform($values) { return array(); // i tried everything here but none working } public function reverseTransform($values) { if (!$values) return null; $array = array(); foreach ($values as $value) { list($id, $type) = explode("_", $value); $array[] = $this->om->getRepository('wwwDefaultBundle:' . $type)->find($id); } return $array; } } ``` the form builder: ``` <?php namespace www\DefaultBundle\Form; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolverInterface; class ValvolaType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder // [snip] ->add('ref', 'accessorio', array( 'label_attr' => array('class' => 'control-label col-sm-2'), 'attr' => array('class' => 'form-control '), )) ; } public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( 'data_class' => 'www\DefaultBundle\Document\Valvola', 'attr' => array('class' => 'press form-horizontal'), )); } public function getName() { return 'www_defaultbundle_valvolatype'; } } ``` Did someone faced the same problem? How "choice" field should be transformed? How managed mixed object in the same field? Someone can enlighten me? Regards

Original source