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 用visual studi code完成html页面
  • ¥15 聚类分析或者python进行数据分析
  • ¥15 逻辑谓词和消解原理的运用
  • ¥15 三菱伺服电机按启动按钮有使能但不动作
  • ¥15 js,页面2返回页面1时定位进入的设备
  • ¥50 导入文件到网吧的电脑并且在重启之后不会被恢复
  • ¥15 (希望可以解决问题)ma和mb文件无法正常打开,打开后是空白,但是有正常内存占用,但可以在打开Maya应用程序后打开场景ma和mb格式。
  • ¥20 ML307A在使用AT命令连接EMQX平台的MQTT时被拒绝
  • ¥20 腾讯企业邮箱邮件可以恢复么
  • ¥15 有人知道怎么将自己的迁移策略布到edgecloudsim上使用吗?