symfony 3.4表单中的新实体中的空值(无默认值)

时间:2018-12-13 15:58:59

标签: symfony symfony-forms

我有一个实体“ administration”,其中有一个字段“ firstPeriod”。此字段不可为空(在类定义或数据库中均不可为空),也不应该为null,因为此字段永远不应该为空,因此应用程序将失败。

但是,该字段没有默认值,因为如果遗忘的用户仅提交表单而不更改默认值,就会造成混乱。用户必须在这里做出自觉的选择。已经进行了验证,以确保该字段不为空并且在可接受的范围内。

当我尝试呈现表单时,formbuilder组件的'propertyAccessor'抛出此异常:

  

类型错误:AppBundle \ Entity \ Administration :: getFirstPeriod()的返回值必须为整数类型,返回null

formbuilder似乎试图在设置字段之前获取字段的值,这当然会导致所述异常。

如何处理这种情况,以便在不向用户提供默认值的情况下呈现表单?

要进一步说明:空不是可以的,但是我不能提供任何默认值,用户必须做出有意识的决定。任何直接实例化此实体的开发者也是如此。必须在实体持久化之前提供它,但是我不能给出默认值,因为如果保留默认值,该应用程序将无法运行12次(共13次)。

  • 如果我在实体字段“?int”上允许null,那么我实际上是在使字段可为null的不应为null
  • 如果我提供默认值,则默认值可能会被盲目接受,这会导致错误的结果在应用程序中进一步出现,这对于大多数用户来说很难发现。
  • 我已经尝试过将formType中的'empty_data => 0'设置为无效

很抱歉出现下面的混乱情况,“代码示例”无法很好地处理此代码

我的(已截断的)实体

namespace AppBundle\Entity;

将Doctrine \ ORM \ Mapping用作ORM;

/ **  *行政  *  * @ORM \ Table(name =“ administration”)  * @ORM \ Entity(repositoryClass =“ AppBundle \ Repository \ AdministrationRepository”)  * / 班级管理 {     / **      * @var int      *      * @ORM \ Column(name =“ id”,type =“ integer”)      * @ORM \ Id      * @ORM \ GeneratedValue(strategy =“ AUTO”)      * /     私人$ id;

/**
 * @var int
 *
 * @ORM\Column(name="first_period", type="smallint", nullable=false)
 */
private $firstPeriod;

/**
 * Get id.
 *
 * @return int
 */
public function getId()
{
    return $this->id;
}


/**
 * @return int
 */
public function getFirstPeriod(): int
{
    return $this->firstPeriod;
}

/**
 * @param int $firstPeriod
 */
public function setFirstPeriod(int $firstPeriod): void
{
    $this->firstPeriod = $firstPeriod;
}

}

我的(被截断的)formType(据我所知,这是我最好的格式):

    public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('firstPeriod', null, [
            'label' => 'First period'
        ])
    ;
}

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

public function getBlockPrefix()
{
    return 'app_bundle_administration_type';
}

}

我的控制器:


namespace AppBundle\Controller\Admin;

class AdministrationController extends Controller
{
    public function editAction(
        EntityManager $em,
        Router $router,
        Security $security,
        Session $session,
        LoggerInterface $logger,
        Request $request,
        Administration $administration = null
    ): Response {

        if ($administration === null) {
            $new = true;
            $administration = new Administration();
            $pageTitle = 'New';
        } else {
            $new = false;
            $pageTitle = 'Edit';
        }
        $breadcrumbs->add($crumbs);

        $form = $this->createForm(AdministrationType::class, $administration);

        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {

            /** @var Administration $administration */
            $administration = $form->getData();

            try {
                $em->persist($administration);
                $em->flush();
            } catch (ORMException $e) {
                $logger->critical($e->getMessage());

                $session->getFlashBag()->add('error', 'Database error.');

                if ($new) {
                    return $this->redirectToRoute('administration_new');
                } else {
                    return $this->redirectToRoute(
                        'administration_edit',
                        ['administration' => $administration->getId()]
                    );
                }
            }

            $session->getFlashBag()->add('success', 'Success!');

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

        return $this->render(':Admin/Administration:edit.html.twig', [
            'administrationForm' => $form->createView(),
            'pageTitle' => $pageTitle
        ]);
    }
}

我的验证:

AppBundle\Entity\Administration:
properties:
    firstPeriod:
        - NotBlank:
              message: 'adm.firstperiod.empty'
        - Range:
              min: 1
              max: 13
              minMessage: 'adm.firstperiod.too_low'
              maxMessage: 'adm.firstperiod.too_high'

1 个答案:

答案 0 :(得分:1)

由于symfony表单使用属性修饰符,如@Cerad所说,您可以在表单中添加未映射的字段,并在表单事件中获取/设置该字段,并添加获取未初始化$ first_period的特定方法...

示例代码可能是...

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass="App\Repository\AdministrationRepository")
 */ 
class Administration
{ 
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()   
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="integer")
     */
    private $first_period;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getFirstPeriod(): int
    {
        return $this->first_period;
    }

    public function setFirstPeriod(int $first_period): self
    {
        $this->first_period = $first_period;

        return $this;
    }

    public function getFirstPeriodOrNull(): ?int
    {
        return $this->first_period;
    }
}

表格

<?php

namespace App\Form;

use App\Entity\Administration;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

class AdministrationType extends AbstractType
{ 
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('first_period', null, [
                'mapped' => false,
                'required' => false,
            ])
            ->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) {
                /** @var Administration */
                $a = $event->getData();

                $event->getForm()->get('first_period')->setData($a->getFirstPeriodOrNull());

            })
            ->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) {
                $f = $event->getForm()->get('first_period')->getData();

                if (is_int($f)) {
                    /** @var Administration */
                    $a = $event->getData();
                    $a->setFirstPeriod($f);
                }
            });
        ;
    }

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

在Symphony 4.2中可以正常工作