我正在使用PHP Silex framework,并在几个小时后试图找到一个令人满意的解决方案,我仍然遇到以下有关包含对象数组的表单和对象的问题。花费的时间允许我找到一个有效的解决方案,但我希望有更好的方法来与Silex一起做。
在我的应用程序中,我有一个User
类,定义如下:
class User implements UserInterface
{
private $id;
private $username;
private $displayname;
private $capacities;
//...
}
$capacities
变量包含来自另一个类(Capacity
)的对象数组。 Capacity
是我的应用程序中的一个特定角色,包含各种信息(标签,容量位置......),我在Capacity
类中添加了一个布尔值,告知容量是否有效特定用户,当通过$capacities
数组附加到用户时。
目前,我可以使用以下代码创建看起来像我想要的表单:
use Planning\Domain\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints as Assert;
class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('username', TextType::class, array(
'required' => true,
'label' => "Login (pour Jean Durant → jdurant)"
))
->add('displayname', TextType::class, array(
'label' => "Nom à afficher"
));
$choices = array();
$choicesActive = array();
foreach ($builder->getData()->getCapacities() as $id => $capacity) {
$choices[$capacity->getLabel()] = $capacity->getId();
if ($capacity->getActive()) {
$choicesActive[] = $capacity->getId();
}
}
$builder->add('capacities', ChoiceType::class, array(
'choices' => $choices,
'data' => $choicesActive,
'label' => "Groupes",
'multiple' => True,
'expanded' => True
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => User::class,
));
}
public function getName()
{
return 'capacity';
}
}
但验证表单后我得到的User
对象包含容量:
[capacities:Planning\Domain\User:private] => Array
(
[0] => 2
[1] => 4
[2] => 1
)
capacities
变量包含已在表单中检查过的复选框的值列表。问题是我的User
对象与其定义不一致,即capacities
属性应该是Capacity
个对象的数组。我现在正在做的是,在$userForm->isSubmitted()
和$userForm->isValid()
时,我已将以下代码添加到我的控制器中:
// Getting the array from the returned user, should contain Capacity object but just contains the IDs.
$capacitiesChecked = $userForm->getData()->getCapacities();
// We regenerate the full array of capacities for this user
$user->setCapacities($app["dao.capacity"]->findAll());
// Then we will activate capacities that have been checked, one by one
foreach ($capacitiesChecked as $capacityChecked) {
$user->getCapacityById($capacityChecked)->setActive(True);
}
这是有效的,我很高兴但是对Silex和框架世界不熟悉,我很惊讶我找不到更容易的方法来回答我的问题,我认为这应该是很常见的。
我可能会错过Silex / Symfony哲学中的一些内容,我希望有人能够指出我找到正确的地方以获取更多信息或找到解决方案!
编辑以下@dbrumann回答
由于可能不清楚我的数据是如何组织的,因此以下是我数据库中的表格:
我的项目建模可能存在问题,但我有一个Capacity
类和一个User
类,User
的属性包含一个包含所有{{1}的数组数据库中可用,并且此Capacity
对象中的每一个都具有Capacity
属性,如果表active
中存在链接用户和容量的条目,则该属性设置为True。我想要的是一个表单,它允许我正确地将数据更新为表user和user_capacity。
答案 0 :(得分:0)
如果我理解正确Capacity
是您想要链接的另一个实体。在这种情况下,您可以使用更具体的EntityType
,然后使用documentation中描述的query_builder
属性过滤值的数量:
$builder->add('users', EntityType::class, array(
'class' => Capacity::class,
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('capacity')
->where('capacity.active = 1')
->orderBy('capacity.id', 'ASC');
},
'choice_label' => 'id',
));
答案 1 :(得分:0)
我找到了一个我认为可以接受的解决方案,可能对登陆此页面的人有用。所以我所做的就是我更改了User
类,以便$capacities
属性现在只包含与用户相关的Capacity
个对象。但是为了获得表单上的所有可用容量,我将它们作为一个选项(allCapacities
)传递并迭代它们以查找User->capacities
中存在哪一个以在表单中检查它们。
用于构建表单的更新类如下:
class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('username', TextType::class, array(
'required' => true,
'label' => "Login (pour Jean Durant → jdurant)"
))
->add('displayname', TextType::class, array(
'label' => "Nom à afficher"
));
$choices = array();
$choicesActive = array();
foreach ($options["allCapacities"] as $id => $capacity) {
$choices[] = $capacity;
if ($builder->getData()->hasCapacity($capacity)) {
$choicesActive[] = $capacity;
}
}
$builder->add('capacities', ChoiceType::class, array(
'choices' => $choices,
'data' => $choicesActive,
'choice_label' => function($category, $key, $index) {
return $category->getLabel();
},
'label' => "Groupes",
'multiple' => True,
'expanded' => True,
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => User::class,
));
$resolver->setRequired(array(
'allCapacities',
));
}
public function getName()
{
return 'capacity';
}
}
这是按预期工作的,似乎过于复杂,但通过更改设计可能会有更简单的解决方案,欢迎对此发表任何评论!