PHP silex Formbuilder和具有对象数组的对象

时间:2017-07-05 12:56:21

标签: php symfony design-patterns silex formbuilder

我正在使用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回答

由于可能不清楚我的数据是如何组织的,因此以下是我数据库中的表格:

  • 用户
    • ID
    • 用户名
    • 显示名称
  • 容量
    • id
    • 标签
    • 地方
  • user_capacity
    • id_user
    • id_capacity

我的项目建模可能存在问题,但我有一个Capacity类和一个User类,User的属性包含一个包含所有{{1}的数组数据库中可用,并且此Capacity对象中的每一个都具有Capacity属性,如果表active中存在链接用户和容量的条目,则该属性设置为True。我想要的是一个表单,它允许我正确地将数据更新为表user和user_capacity。

2 个答案:

答案 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';
    }
}

这是按预期工作的,似乎过于复杂,但通过更改设计可能会有更简单的解决方案,欢迎对此发表任何评论!