【问题标题】:How to use a custom type correctly in Symfony?如何在 Symfony 中正确使用自定义类型?
【发布时间】:2020-06-03 18:47:08
【问题描述】:

我正在尝试使用 Symfony 的所有功能来构建一个站点。我已经有 2 年的 Symfony 经验,但我第一次尝试使用自定义表单类型的概念来创建特定的注册表单。我已经有一个基本用户的注册表单,但现在我想为经营酒店的经理创建另一个注册表。

我已经创建了一个名为 RegistrationFormType 的表单类型和另一个名为 HotelType 的表单类型。我的事情是我想在一个表单中使用这两种表单类型。但我不断收到一个例外,上面写着

既不是“用户”属性也不是“getUser()”方法之一, “user()”、“isUser()”、“hasUser()”、“__get()” 存在并公开 在“App\Entity\User”类中访问

我遵循了 Symfony 官方文档中关于自定义表单类型的内容。

我制作了这个表单类型 RegistrationHotelFormType,它由另一个表单 RegistrationFormType 组成,在其他地方用作基本用户创建帐户的表单和 Symfony 自身生成的 HotelType。

<?php

namespace App\Form;

use App\Entity\User;
use App\Form\HotelType;
use App\Form\RegistrationFormType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Validator\Constraints\IsTrue;
use Symfony\Component\Validator\Constraints\Regex;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Validator\Constraints\File;

class RegistrationHotelFormType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('user', RegistrationFormType::class, ['mapped' => false])
            ->add('hotel', HotelType::class, ['mapped' => false])
        ;
    }

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

上面的方法可以工作,但在 Symfony 文档中,我不需要将映射参数设置为 false,因为我知道我希望将表单值分配给酒店和用户的对象字段。我怎样才能完成这项工作? (https://symfony.com/doc/current/form/create_custom_field_type.html#creating-form-types-created-from-scratch)。

注册表格类型:

<?php

namespace App\Form;

use App\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Validator\Constraints\IsTrue;
use Symfony\Component\Validator\Constraints\Regex;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Validator\Constraints\File;

class RegistrationFormType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('email', EmailType::class, ['error_bubbling'=>true, 'label' => 'Email', 'attr' => ['type'=>'text','class'=>'form-control', 'placeholder'=>'Email', 'aria-label'=>"Username", 'aria-describedby'=>"basic-addon1"]])
            ->add('plainPassword', RepeatedType::class, [
                'type' => PasswordType::class,
                'label' => 'Mot de passe',
                'attr' => ['error_bubbling'=>true, 
                'type'=>'text',
                'class'=>'form-control', 
                'placeholder'=>'Mot de passe', 
                'aria-label'=>"Username", 
                'aria-describedby'=>"basic-addon1"],
                'mapped' => false,
                'constraints' => [
                    new NotBlank([
                        'message' => 'Mot de passe requis',
                    ]),
                    new Length([
                        'min' => 8,
                        'minMessage' => 'Le mot de passe doit avoir au moins {{ limit }} caractères',
                        // max length allowed by Symfony for security reasons
                        'max' => 128,
                        'maxMessage' => 'Le mot de passe ne doit pas dépasser {{ limit }} caractères',
                    ]),
                    // new Regex([
                    //     'pattern' => '/^\S*(?=\S*[a-z])(?=\S*[A-Z])(?=\S*[\d])\S*$/',
                    //     'message' => 'Le mot de passe doit contenir au moins 1 lettre et 1 chiffre',
                    // ])
                ],
            ])
            ->add('firstname', TextType::class, ['error_bubbling'=>true, 'label' => 'Prénom', 'attr' => ['type'=>'text','class'=>'form-control', 'placeholder'=>'Prénom', 'aria-label'=>"Username", 'aria-describedby'=>"basic-addon1"]])
            ->add('surname', TextType::class, ['error_bubbling'=>true, 'label' => 'Nom', 'attr' => ['type'=>'text','class'=>'form-control', 'placeholder'=>'Nom', 'aria-label'=>"Username", 'aria-describedby'=>"basic-addon1"]])
            ->add('phoneNumber', TextType::class, ['error_bubbling'=>true, 'label' => 'Téléphone', 'attr' => ['type'=>'text','class'=>'form-control', 'placeholder'=>'Téléphone', 'aria-label'=>"Username", 'aria-describedby'=>"basic-addon1"]])
            ->add('city', TextType::class, ['error_bubbling'=>true, 'label' => 'Ville', 'attr' => ['type'=>'text','class'=>'form-control', 'placeholder'=>'Ville', 'aria-label'=>"Username", 'aria-describedby'=>"basic-addon1"]])
            ->add('termsAccepted', CheckboxType::class, [
                'error_bubbling'=>true,
                'mapped' => false,
                'constraints' => new IsTrue(),
                'attr' => ['type'=>"checkbox", 'class'=>"form-check-input"]
            ])
            ->add('resumePDF', FileType::class, [
                'error_bubbling'=>true,
                'label' => 'CV (Fichier PDF)',
                'mapped' => false,
                'required' => true,
                'constraints' => [
                    new File([
                        'maxSize' => '1024k',
                        'mimeTypes' => [
                            'application/pdf',
                            'application/x-pdf',
                        ],
                        'mimeTypesMessage' => 'Téléchargez un fichier PDF valide',
                    ])
                ],
                'attr' => ['type'=>"file", 'class'=>"custom-file-input"]
            ])
        ;
    }

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

酒店类型

<?php

namespace App\Form;

use App\Entity\Hotel;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class HotelType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name')
            ->add('address');
    }

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

RegistrationController.php

    /**
 * @Route("/inscription-hotel", name="app_register_hotel")
 */
public function registerHotel(Request $request, UserPasswordEncoderInterface $passwordEncoder, \Swift_Mailer $mailer): Response
{
    $session = new Session();
    // $session->start();

    $user = new User();
    $form = $this->createForm(RegistrationHotelFormType::class, $user);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
    }

    return $this->render('registration/register-hotel.html.twig', [
        'registrationForm' => $form->createView(),
    ]);
}

提前感谢您的帮助

【问题讨论】:

  • 这是因为您的酒店注册表单类型正在寻找一个名为 user ($user->user) 的属性以传递给注册表单类型。除非您有一个名为 $user->hotel 的属性,否则您可能会遇到与酒店相同的问题。您可能需要一个 RegisteredUser 实体,其中包含 User 和 Hotel 实体。

标签: php forms symfony


【解决方案1】:

Cerad 诊断出错误触发的原因(将使用createForm 的第二个参数,表单将尝试访问其上的userhotel 属性),最简单的解决方案如下:

我会从组合表单中删除data_class,并在您的控制器中省略createForm 的第二个参数。 $form-&gt;getData() 的返回值将是一个数组:

['user' =&gt; {User object}, 'hotel' =&gt; {Hotel object}]

(您也可以为您的createForm 调用提供一个类似结构的数组作为第二个参数)

当然,您可以创建一个包含用户和酒店的新类...

【讨论】:

    猜你喜欢
    • 2018-03-12
    • 1970-01-01
    • 2021-02-05
    • 1970-01-01
    • 2020-08-02
    • 2016-04-05
    • 2018-01-20
    • 2020-02-13
    • 2013-01-29
    相关资源
    最近更新 更多