是否可以使用只读类作为 symfony 表单的 DTO?

问题描述 投票:0回答:1

我有一个简单的 symfony 表单,用于创建

ThingEntity

我有一个

CreateThingType
和一个
CreateThing
DTO:

DTO

namespace App\DataTransfer;

use App\Validator\UniqueNameForParent;
use Symfony\Component\Validator\Constraints\GreaterThan;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;


#[UniqueNameForParent]
readonly class CreateThing
{

    function __construct(
        #[GreaterThan(0)]
        public int    $parent,

        #[NotBlank]
        #[Length(min: 3, max: 6)]
        public string $name,
    )
    {
    }

}

类型:

namespace App\Form\Type;

use App\DataTransfer\CreateThing;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class CreateThingType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {

        $builder->add('name', TextType::class)
            ->add('parent', IntegerType::class)
            ->add('save', SubmitType::class);
    }

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

}

还有一个简单的控制器来处理这个事情:

namespace App\Controller;

use App\Entity\ThingEntity;
use App\Form\Type\CreateThingType;
use App\ThingRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

#[Route('/create')]
class CreateController extends AbstractController
{
    function __construct(private readonly ThingRepository $thingRepository)     {}

    public function __invoke(Request $request): Response
    {
        $form = $this->createForm(CreateThingType::class);

        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $thing = $form->getData();
            
            $thingEntity = new ThingEntity(
                id: null,
                parent: $thing->parent,
                name: $thing->name
            );
            $this->thingRepository->save($thingEntity);

            return $this->redirectToRoute('app_thing_list');
        }

        return $this->render('create.html.twig', [ 'form' => $form ]);
    }

}

未提交表单时,表单正确显示:

form ok

但是当我提交表单时,出现错误,如下所示:

函数 App\DataTransfer\CreateThing::__construct() 的参数太少,0 传入 /U/a/symfony-form-dto-shared-repro/vendor/symfony/form/Extension/Core/Type/FormType.php在第 134 行,正好是预期的 2 行

我可以通过删除

readonly
关键字并使参数/属性可选,通过使用空默认值来使其工作(我不希望这样做,因为我希望 DTO 清楚“一切都是必需的” “当我在其他地方重复使用它时)

是否可以在 Symfony 表单中使用只读 DTO?怎么办?

php symfony symfony-forms php-8.2
1个回答
0
投票

PropertyAccessor
无法了解你的构造函数。您可以更改变量名称,或者在构造函数中以不同的方式应用它们。

据我所知,symfony 使用

PropertyAccessor
组件通过使用 setter 或设置属性(如果属性是公共的)来将属性设置为 data_class。其中任何一个都无法将您的 Dto 设置为只读。

我也不认为这对于 Symfony Form 来说是不可能的,因为您可以设置默认值,这些默认值可以通过使用 setter 或使用由 PropertyAccessor 组件完成的 Dto 的公共属性来由您的表单覆盖.

简而言之,跳过只读部分和构造函数,并使用 getter 和 setter 创建简单的模型。

© www.soinside.com 2019 - 2024. All rights reserved.