symfony:如何使用复选框列表编辑 class json_array 属性?
symfony : how to render edit a class json_array attribute with a list of checkboxes?
在我的 symfony2 应用程序中,我有一个 json_array 类型的属性:
/**
* @ORM\Column(name="rights", type="json_array", nullable=true)
*/
protected $rights = array();
该属性的数据是一个关联数组,如下所示:
$allRights = array(
Associate::READ_PROFILE => array('all' => false),
Associate::UPDATE_PROFILE => array('all' => false),
Associate::READ_CONTACT => array('all', 'created' => false),
);
我希望能够使用一组复选框集合编辑此属性,即。我想要第一级的每个键一行,然后第二级的每个键一个复选框。
我有一个调用自定义类型的表单类型:
<?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';
}
}
在这个自定义类型中我添加了一个 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';
}
}
在这个数据转换器中,我确保数据以正确的格式输出:
<?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;
}
}
我有一个自定义视图,可以生成正确的视觉输出:
{% 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 %}
但是,我发送表单时返回的数据是原始数据输出,而不是修改后的数据。
我想我在视图中做错了。我怎样才能正确编辑这些数据并能够使用我的数据转换器的反向转换功能来操作它?
您的问题是您正在创建许多 symfony 对其一无所知的输入字段(复选框)。事实上,当您提交表单时,它可能会抛出一个异常,说明它收到了一些它没有预料到的字段。您需要将这些字段转换为 symfony 可以理解的内容。您可以通过两种方式进行:
- 您可以拦截 JavaScript 中的提交事件,并使用这些复选框来构建应在原始字段的数据中发送回 symfony 的数据(并取消设置复选框,以便它们不会被发送到后端)
- 您可以在控制器中提交表单时测试这些字段的存在,并使用它们来构造您需要的数据(也可以取消设置它们,以便 symfony 在验证表单时不会抱怨)
在我的 symfony2 应用程序中,我有一个 json_array 类型的属性:
/**
* @ORM\Column(name="rights", type="json_array", nullable=true)
*/
protected $rights = array();
该属性的数据是一个关联数组,如下所示:
$allRights = array(
Associate::READ_PROFILE => array('all' => false),
Associate::UPDATE_PROFILE => array('all' => false),
Associate::READ_CONTACT => array('all', 'created' => false),
);
我希望能够使用一组复选框集合编辑此属性,即。我想要第一级的每个键一行,然后第二级的每个键一个复选框。
我有一个调用自定义类型的表单类型:
<?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';
}
}
在这个自定义类型中我添加了一个 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';
}
}
在这个数据转换器中,我确保数据以正确的格式输出:
<?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;
}
}
我有一个自定义视图,可以生成正确的视觉输出:
{% 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 %}
但是,我发送表单时返回的数据是原始数据输出,而不是修改后的数据。 我想我在视图中做错了。我怎样才能正确编辑这些数据并能够使用我的数据转换器的反向转换功能来操作它?
您的问题是您正在创建许多 symfony 对其一无所知的输入字段(复选框)。事实上,当您提交表单时,它可能会抛出一个异常,说明它收到了一些它没有预料到的字段。您需要将这些字段转换为 symfony 可以理解的内容。您可以通过两种方式进行:
- 您可以拦截 JavaScript 中的提交事件,并使用这些复选框来构建应在原始字段的数据中发送回 symfony 的数据(并取消设置复选框,以便它们不会被发送到后端)
- 您可以在控制器中提交表单时测试这些字段的存在,并使用它们来构造您需要的数据(也可以取消设置它们,以便 symfony 在验证表单时不会抱怨)