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

PHP silex Formbuilder and object with array of object

我将 PHP 与 Silex framework 一起使用,在尝试找到令人满意的解决方案几个小时后,我仍然被以下有关包含对象数组的表单和对象的问题所困扰。花费的时间让我找到了一个可行的解决方案,但我希望有更好的方法可以使用 Silex 来做到这一点。

在我的应用程序中,我有一个 User class 定义如下:

class User implements UserInterface
{
    private $id;
    private $username;
    private $displayname;
    private $capacities;
    //...
}

$capacities 变量包含来自另一个 class (Capacity) 的对象数组。 Capacity 是我的应用程序中的一个特定角色,具有各种信息(标签、容量位置......),我在 Capacity class 中添加了一个布尔值,告诉它容量是否当通过 $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 的回答

由于可能不清楚我的数据是如何组织的,这里是我的数据库中的 table:

我的项目建模可能有问题,但我有 Capacity class 和 User class 和 User具有包含数据库中所有可用 Capacity 的数组的属性,并且此 Capacity 对象中的每个对象都有一个 active 属性,如果 [=102] 中有条目,则该属性设置为 True =] user_capacity 链接用户和容量。我想要的是一种允许我将数据正确更新到 tables 用户和 user_capacity.

的表格

如果我没理解错的话 Capacity 是您想要 link 的另一个实体。在这种情况下,您可以使用更具体的 EntityType,然后使用 query_builder 属性过滤值的数量,如 documentation:

中所述
$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',
));

我找到了一个我认为可以接受并且可能对登陆此页面的人有用的解决方案。所以我所做的是更改 User class 以便 $capacities 属性现在仅包含与用户相关的 Capacity 对象。但是为了获得表单上的所有可用容量,我将它们作为一个选项 (allCapacities) 传递并遍历它们以找到 User->capacities 中存在的容量以在表单中检查它们。

用于构建表单的更新class如下:

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

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