Symfony 2 GenemuFormBundle how to create a jQuery Select2 with Ajax

I'm trying to add a Select2 input using the GenemuFormBundle as described in the "Use jQuery Select2 with Ajax" doc. Adding a jQuery Select2 Field following the jQuery Select2 Field documentation works just fine.

But the documentation on how to implement an Ajax-loading Select2 form is very inconclusive. If I unterstand the doc correctly, it aims to create the same as mentioned in the Select2 documentation. This is exactly the thing I'd like to create. I added hidden field as well as the required JavaScript, but the only thing that I get is a Variable "id" does not exist in xBundle:x:new.html.twig at line x .

Form builder (taken directly form the mentioned doc):

...
->add('field_name', 'genemu_jqueryselect2_hidden', array(
    'configs' => array(
        'multiple' => true // Wether or not multiple values are allowed (default to false)
    )
))
->add('field_name', 'genemu_jqueryselect2_entity', array(
    'class' => 'xBundle:Entity',
    'property' => 'foo',
))

View (also taken directly form the doc):

{% block stylesheets %}
    {{ form_stylesheet(form) }}
{% endblock %}

{% block javascript %}
    {{ form_javascript(form) }}
{% endblock %}

{% block genemu_jqueryselect2_javascript %}

    <script type="text/javascript">
        $field = $('#{{ id }}');

        var $configs = {{ configs|json_encode|raw }};

        // custom configs
        $configs = $.extend($configs, {
            query: function (query) {
                var data = {results: []}, i, j, s;
                for (i = 1; i < 5; i++) {
                    s = "";
                    for (j = 0; j < i; j++) {s = s + query.term;}
                    data.results.push({id: query.term + i, text: s});
                }
                query.callback(data);
            }
        });
        // end of custom configs

        $field.select2($configs);
    </script>

{% endblock %}

I just struggled with this exact issue and thought I would throw in my own findings for anyone that happens to stumble across this. I did find a solution, but I would probably still recommend just going with the ZenStruckFormBundle recommended by Doug because it seems to actually be designed to work as a solution for a select2 field type that loads via ajax and relates back to an entity.

The real reason this doesn't work is that the the genemu_jqueryselect2_* types for the GenemuFormBundle do not implement a data transformer that will work with an entity when you need an ajax-loading select2 field. It doesn't seem like it was ever designed to work this way. When you use the genemu_jqueryselect2_hidden type and have the “multiple' config option set to true, then it adds an ArrayToStringTransformer. This will not work with an entity.

To fix this you need to make a new form field type and define that its parent is genemu_jqueryselect2_hidden then make a few customizations. It would look something like this…

namespace AcmeDemoBundleFormType;

use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use AcmeDemoBundleFormDataTransformerEntityCollectionToIdTransformer;
use DoctrineCommonPersistenceObjectManager;
use SymfonyComponentOptionsResolverOptionsResolverInterface;

class EntityCollectionSelectorType extends AbstractType
{
    /**
     * @var ObjectManager
     */
     protected $om;

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

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $transformer = new EntityCollectionToIdTransformer($this->om, $options['configs']['entity']);
        $builder->resetViewTransformers();
        $builder->addModelTransformer($transformer);
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'invalid_message' => 'The selected entity does not exist',
            'required' => true,
            'auto_initialize' => false,
            'configs' => array('multiple' => true),
            'error_bubbling' => false, 
        ));
    }

    public function getParent()
    {
        return 'genemu_jqueryselect2_hidden';
    }

    public function getName()
    {
        return 'entity_collection_selector';
    }
}

Then you will also need to add the new data transformer used in the above form field type, so that it can translate the values between the form field and the entity…

namespace AcmeDemoBundleFormDataTransformer;

use SymfonyComponentFormDataTransformerInterface;
use SymfonyComponentFormExceptionTransformationFailedException;
use DoctrineORMPersistentCollection;
use DoctrineCommonPersistenceObjectManager;
use DoctrineCommonCollectionsArrayCollection;

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

    /**
     * @var string The Doctrine entity type to use
     */
    private $entityType;

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

    /**
     * Transforms a collection of entities to a comma separated string
     *
     * @param  ArrayCollection $entities
     * @return string
     */
    public function transform($entities)
    {
        if (null == $entities || empty($entities)) {
            return '';
        }

        $results = '';
        foreach ($entities as $entity) {
            $results .= $entity->getId() . ',';
        }
        $results = trim($results, ' ,');

        return $results;
    }

   /**
    * Transforms a string of comma separated IDs to a PersistentCollection for Doctrine
    *
    * @param  string $values
    * @return PersistentCollection|ArrayCollection
    * @throws TransformationFailedException if entity is not found.
    */
    public function reverseTransform($values)
    {
        if (!$values) {
            return new ArrayCollection();
        }
        $values = explode(',', $values);

        $collection = array();
        foreach ($values as $id) {
            $item = $this->om->getRepository($this->entityType)->findOneById($id);

            if (!is_null($item)) {
                $collection[] = $item;
            }
            else {
                throw new TransformationFailedException(sprintf(
                    'An entity with ID "%s" does not exist!',
                    $value
                ));
            }
        }

        return new PersistentCollection($this->om, $this->entityType, new ArrayCollection($collection));
    }
}

Now make sure you define your new field type in your config for your services…

<?xml version="1.0" ?>

<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

    <parameters>
        ...
        <parameter key="acme_demo.form.type.entity_collection_selector.class">AcmeDemoBundleFormTypeEntityCollectionSelectorType</parameter>
        ...
    </parameters>

    <services>
        ...
        <service id="acme_demo.form.type.entity_collection_selector"
            class="%acme_demo.form.type.entity_collection_selector.class%">
            <argument type="service" id="doctrine.orm.default_entity_manager" />
            <tag name="form.type" alias="entity_collection_selector" />
        </service>
        ...
    </services>
</container>

Now you can use it as such…

$builder->add('customers', 'entity_collection_selector', array(
    'configs' => array('entity' => 'AcmeDemoBundle:Customer')
));
链接地址: http://www.djcxy.com/p/78392.html

上一篇: 可靠的1.6>使用

下一篇: Symfony 2 GenemuFormBundle如何用Ajax创建jQuery Select2