【问题标题】:EntityType Form SYmfony add as Entity instead of intEntityType Form SYmfony 添加为 Entity 而不是 int
【发布时间】:2022-11-22 21:32:37
【问题描述】:

我来这里是因为我找不到解决问题的办法。我在 Symfony 6 中有一个表单,其中一个值是 id_client 并引用到另一个实体 Client(关系 ManyToOne)。

我测试了几种方法来使该字段成为所有客户的选择(我显示客户的名称)。它们中的每一个都有效,但是当我提交表单时,这个值是作为整个实体添加的,而不仅仅是 id。这是一个问题,因为我以此结尾:

Expected argument of type "int", "App\\Entity\\Client" given at property path "id_client".

在我的表格中,它看起来像这样:

<?php

namespace App\Form;

use App\Entity\Client;
use App\Entity\Group;
use App\Repository\ClientRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
class Group1Type extends AbstractType
{
    private $clientRepository;

    public function __construct(ClientRepository $clientRepository)
    {
        $this->clientRepository = $clientRepository;
        $this->clients = $clientRepository->findAll();
    }

    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('name', TextType::class, [
                'attr' => [
                    'class' => 'form-control'
                ],
                'label' => 'Name: '
            ])
            ->add('can_display', CheckboxType::class, [
                'label' => 'Can display : ',
                'attr' => [
                    'class' => 'my-3 mx-2'
                ]
            ])
            ->add('id_client', EntityType::class, [
                'class' => Client::class,
                // 'choices' => $this->clientRepository->findAllNameAlphabetical(),
                // 'query_builder' => function (ClientRepository $client) {
                //     return $client->findAllNameAlphabetical();
                // },
                'choice_label' => 'name',
                'expanded' => false,
                'multiple' => false,
                'attr' => [
                    'class' => 'form-control'
                ]
            ])
        ;
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => Group::class,
        ]);
    }
}

树枝:

<section class="container my-3">
    <div class="row">
        <div class="col">
            {{ form_start(form) }}
                {{ form_row(form.name) }}
                {{ form_row(form.can_display) }}
                {{ form_row(form.id_client) }}
                <button class="btn btn-primary my-3">{{ button_label|default('Save') }}</button>
            {{ form_end(form) }}
        </div>
    </div>
</section>

控制器(如果我让它与开始时一样,我会得到相同的结果):

#[Route('/new', name: 'app_group_new', methods: ['GET', 'POST'])]
    public function new(Request $request, GroupRepository $groupRepository): Response
    {
        $group = new Group();
        $form = $this->createForm(Group1Type::class, $group);
        $form->handleRequest($request);
        // $group->id_client = $group->id_client->id;
        
        if ($form->isSubmitted()) {
            // dd('submit');
            // if(gettype($group->id_client)=="Client"){
                // dd($group);
                if($form->isValid()){
                    dd('valid');
                    $groupRepository->save($group, true);
                    $this->addFlash('success', 'The creation went successfully.');
                    return $this->redirectToRoute('app_group_index', [], Response::HTTP_SEE_OTHER);
                // }
            }
        }

        return $this->renderForm('group/new.html.twig', [
            'group' => $group,
            'form' => $form,
        ]);
    }

我的实体:

    #[ORM\Column]
    private ?int $id_client = null;

【问题讨论】:

  • 如果你只想要一个 id,那么你不应该使用 EntityType,因为它总是将 id 转换为一个实体,然后返回该实体。您可以改用 ChoiceType,因为它不会进行自动转换。但是您确定您的实体设置正确吗?我希望 Group 有一个 $client 属性,该属性包含一个 Client 对象,然后 ORM 会将 Client 对象存储在数据库中时将其转换为 id_client
  • 如果 $id_client 有关系,为什么要保存 int 而不是 Client 实体?你在混合概念,如果你想保存一个实体客户端,你应该有``` private ?Client $id_client = null; ``` 那么你可以在表单中使用 EntityType ,否则在表单中使用 ChoiceType 而不定义类属性。
  • 你在这里错过了 symfony 和学说的多个概念。我真的推荐你阅读Symfony documentation。在 Symfony 中开发了 2 年后,我仍然每天都使用它并且我喜欢它。太棒了!

标签: php forms symfony entity symfony-forms


【解决方案1】:

欢迎来到 SO!

在您的实体中,请勿使用 id 命名属性。组(?)实体中的客户端属性应命名为$client,而不是$id_client

然后,在您的表单中,将该字段命名为与组实体中的属性完全一样。 Doctrine(正如 DBAL 应该做的那样)通过实际 id 为您完成对象的幕后关联。

Group1Type.php

    ->add('client', EntityType::class, [
        'class' => Client::class,
        // ...
    ])

和你的集团实体(或 Group1?)

class Group
{
    // ...

    #[ORMManyToOne(targetEntity: Client::class, inversedBy: 'groups')]
    #[ORMJoinColumn(nullable: false)]
    private $client;

    // ...
}

它自己提交的表单和处理所选客户端的实体实例是完全正确的。您几乎从不处理 $id 值。这就是教义的特征之一!

有关如何使用 EntityType 字段的更多信息,请参阅 Symfony documentation


笔记:从你给的命名来看,我猜测你有错误的关系,也许应该是OneToMany? (你能告诉我们GroupClient 是如何相关的吗?1 Group 有多个客户吗?反之亦然?)


边注:在极少数情况下,当您确实需要与实体相关的数字时(例如,用户可以在其中输入客户编号然后转换为真实客户实体的文本输入),您可以使用 DataTransformer 来转换此类值。但这不是你想要的!

【讨论】:

    【解决方案2】:

    简单的解决方案是使用选择类型,这样你就不需要关系,当你提交时你将拥有客户的 ID。如果加载表单进行编辑(加载实体,它将显示从提交中选择的值)

    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
      $builder
         ->add('client', ChoiceType::class, [
                    'choices'=> $this->getClients(),
        ])
    }
    public function getClients(){
     $conn = $this->getEntityManager()->getConnection();
     $query = "SELECT `name`, `id` FROM `clients` order by `name`";
     $stmt = $conn->executeQuery($query);
     return $stmt->fetchAllKeyValue(); 
     }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多