dongzai3917 2015-10-25 22:27
浏览 64
已采纳

symfony:如何使用复选框列表编辑类json_array属性?

In my symfony2 application, I have an attribute of type json_array :

/**
 * @ORM\Column(name="rights", type="json_array", nullable=true)
 */
protected $rights = array();

The data for this attributeis an associative array as follows :

    $allRights = array(
        Associate::READ_PROFILE => array('all' => false),
        Associate::UPDATE_PROFILE => array('all' => false),
        Associate::READ_CONTACT => array('all', 'created' => false),
);

I want to be able to edit this attribute with a collection of checkboxes collections ie. I want one line per key of the first level and then one checkbox per key of the second level.

I have starter a form type which calls a custom type :

<?php

namespace AppBundle\Form\User;

use AppBundle\Entity\User\Associate;
use AppBundle\Form\DataTransformer\RightsToArrayTransformer;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Validator\Constraints as Assert;

class AssociateRightsType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('rights', 'fmu_rights', array(
                'label' => false,
            ));
    }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\User\Associate',
            'validation_groups' => array('Default', 'rights'),
            'cascade_validation' => true,
        ));
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'appbundle_user_associate_rights';
    }
}

In this custom type I have added a dataTransformer :

<?php

namespace AppBundle\Form\Type;

use AppBundle\Application\User\AssociateManager;
use AppBundle\Entity\User\Associate;
use AppBundle\Form\DataTransformer\RightsToArrayTransformer;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class RightsType extends AbstractType
{
    /**
     * @var AssociateManager
     */
    private $associateManager;

    public function __construct(AssociateManager $associateManager)
    {
        $this->associateManager = $associateManager;
    }

    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $transformer = new RightsToArrayTransformer();
        $builder->addModelTransformer($transformer);


    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'fmu_rights';
    }

}

In this data transformer I make sure the data is ouputed in the right format :

<?php

namespace AppBundle\Form\DataTransformer;

use AppBundle\Entity\User\Associate;
use Symfony\Component\Form\DataTransformerInterface;

class RightsToArrayTransformer implements DataTransformerInterface
{
    /**
     * @param mixed $data
     * @return array|mixed
     */
    public function transform($data)
    {
        return is_array($data) ? $data + $this->getRights() : $this->getRights();
    }

    /**
     * @param mixed $data
     * @return array
     */
    public function reverseTransform($data)
    {
        return $data;
    }

    private function getRights()
    {
        $allRights = array(
            Associate::READ_PROFILE => array('all'),
            Associate::UPDATE_PROFILE => array('all'),
            Associate::READ_CONTACT => array('all', 'created'),
            Associate::UPDATE_CONTACT => array('all', 'created'),
            Associate::DELETE_CONTACT => array('all', 'created'),
            Associate::IS_BOSS => array('all'),
        );

        foreach ($allRights as $right => $parameters) {
            $allRights[$right] = array();
            foreach ($parameters as $parameter) {
                $allRights[$right][$parameter] = false;
            }

        }

        return $allRights;
    }
}

and I have a custom view that makes the right visual ouput :

{% block fmu_rights_widget %}

    {% if attr.class is defined %}
        {% set attr = attr|merge({'class': attr.class ~ ' input-sm form-control fmu_rights'}) %}
    {% endif %}

    {% set rights = form.vars.data %}

    {% for right, parameters in rights %}
        <div class="row padding-v">
            <div class="col-md-2">
                {{ right }}
            </div>
            <div class="col-md-10">
                {% for parameter, value in parameters %}
                    {% set name = id ~ '[' ~ loop.index ~ ']' ~ right ~ '[' ~ parameter ~ ']' %}
                        <label for="{{ name }}">{{ parameter }}</label>
                        <input type="checkbox" id="{{ name }}" name="{{ name }}" {% if value %}checked{% endif %}>
                {% endfor %}
            </div>
        </div>
    {% endfor %}

{% endblock %}

However, the data returned when I send my form is the original data output, not the modified data. I guess I've done it wrong in the view. How can I edit this data correctly and be able to manipulate it the reverse transform function of my data transformer ?

  • 写回答

1条回答 默认 最新

  • dongsu2807 2015-10-26 09:07
    关注

    Your problem is that you are creating a number of input fields (the checkboxes) of which symfony knows nothing about. In fact when you submit the form, it is probably going to throw an exception saying that it received some fields that it did not expect. You need to transform these fields into something that symfony can understand. You can do it in two ways:

    • You can intercept the submit event in JavaScript and use these checkboxes to construct the data which should be sent back to symfony in the data for the original field (and unset the checkboxes so that they are not sent to the backend)
    • You can test for the existence of these fields when the form is submitted in your controller and use them to construct the data you need (also unset them so that symfony does not complain when validating the form)
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 全部备份安卓app数据包括密码,可以复制到另一手机上运行
  • ¥15 Python3.5 相关代码写作
  • ¥20 测距传感器数据手册i2c
  • ¥15 RPA正常跑,cmd输入cookies跑不出来
  • ¥15 求帮我调试一下freefem代码
  • ¥15 matlab代码解决,怎么运行
  • ¥15 R语言Rstudio突然无法启动
  • ¥15 关于#matlab#的问题:提取2个图像的变量作为另外一个图像像元的移动量,计算新的位置创建新的图像并提取第二个图像的变量到新的图像
  • ¥15 改算法,照着压缩包里边,参考其他代码封装的格式 写到main函数里
  • ¥15 用windows做服务的同志有吗