如果 Symfony 4 不存在数据则创建

Create if data doesn't exist with Symfony 4

我有一个用户填写了姓名的表格。基于这个名字,我在我的数据库上做了一个 AJAX 请求,以了解是否存在使用该名字的人。如果它存在,我将显示完整的表单,其中输入填充了数据库中的数据。否则我会显示一个空的完整表格。 在提交时,如果数据已经在数据库中,我想更新它们,但如果没有,我需要插入这些数据。插入新数据工作正常。

这是链接到表单提交的我的控制器函数:

    /**
     *@Route("adherent/new", name="adherent_new")
     */
    public function new(Request $request)
    {
        $adherent = new Adherent();
        $em = $this->getDoctrine()->getManager();

        $form = $this->createForm(AdherentType::class, $adherent);    
        $form->handleRequest($request);

        $produitRepository = $em->getRepository(Produit::class);
        $allProduit = $produitRepository->findAll();

        if($form->isSubmitted() && $form->isValid()){
            $id = $request->request->get('id');
            //if id exists then update
            //otherwise create a new entry

            $adherent = $form->getData();
            $em->persist($adherent);
            $em -> flush();

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


        return $this->render('adherent/new.html.twig', [
            'form' => $form->createView(),
            'produits' => $allProduit
        ]);

    }

有没有办法用 Symfony 来处理这个问题?还是我必须手动执行此操作?

提前致谢!

您可以从数据库中加载特定的追随者,而不是创建新的 $adherent。手动像在非常干净的 documentation but you can use Automatically Fetching Objects (ParamConverter) 中:

composer require sensio/framework-extra-bundle
// src/Controller/ProductController.php
use App\Entity\Product;

/**
 * @Route("/product/{id}", name="product_show")
 */
public function show(Product $product)
{
    // use the Product!
    // ...
}

然后,当您使用 $adherent 创建表单时,它现在是一个包含来自您数据库的信息的对象: $form = $this->createForm(AdherentType::class, $adherent);

它会自动用相应的数据填充表单字段。

我不是 symfony 的专业人士,但我使用过它 there。如果我理解得很好,请查看路线“/terminal/create”和“/terminal/{id}/edit”,这似乎与您想要实现的目标相似。

编辑

如果您在发送到数据库之前设置了对象的 ID,它将更新您的追随者,如果没有 ID,它将创建一个新的。我认为您只需添加:

if($id){
    $adherent->setId($id);
}

编辑

re-reading 在你的代码中 $adherent = $form->getData();如果 id 在您的表单中,则可能已经设置了对象的 id。这意味着它应该已经像您期望的那样工作了(如果在您的表单上设置了 id,则更新 adherent,如果 id 为空,则创建 adherent)。如果没有,你能把你的实体和形式的代码放在一起吗?

好的,我明白你的意思了。我在 adherent class 中没有 id 属性 因为它扩展了一个 superclass abstract class Demandeur 有这个 id。所以在我的adherentType表单中我没有把id属性放在里面,而是直接在html模板中添加了。这解释了为什么我尝试用

获取它
$id = $request->request->get('id');

因为我尝试使用 getData() 并且因为我的实体 Adherent 没有 ID 属性 等等 setId() 方法,所以我遇到了一个异常:

Could not determine access type for property "id" in class "App\Entity\Adherent": Neither the property "id" nor one of the methods "addId()"/"removeId()", "setId()", "id()", "__set()" or "__call()" exist and have public access in class "App\Entity\Adherent".

这是真的。在此之前,我尝试了添加功能,一切正常,ID 和关系。

class AdherentType extends AbstractType
{
    /**
     *{@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {     
        $builder 
            ->add('id', IntegerType::class)
            ->add('nom', TextType::class, [
                'constraints' => [
                    new NotBlank(),
                    new Length(['max'=>50]),
                ]
            ])
            ->add('prenom', TextType::class, [
                'constraints' => [
                    new NotBlank(),
                    new Length(['max'=>50]),
                ]
            ])
            ->add('numSocietaire', IntegerType::class, [
                'constraints' => [
                    new NotBlank(),
                    new Length(['max'=>30]),
                ]
            ])
            ->add('anciennete', IntegerType::class, [
                'required' => 'false',
            ])
            ->add('contratActif', IntegerType::class, [
                'required' => 'false',
            ])
            ->add('dateNaiss', DateType::class, [
                'widget' => 'single_text',
                'required' => 'false',
            ])
            ->add('dateAdhes', DateType::class,[
                'widget' => 'single_text',
                'required' => 'false',
                'empty_data' => '',
            ])
            ->add('datePremMut', DateType::class, [
                'widget' => 'single_text',
                'required' => 'false',
            ])
            ->add('nbBenef', IntegerType::class, [
                'required' => 'false',
            ])
            ->add('nbIncidPaimt', IntegerType::class, [
                'required' => 'false',   
            ])
            ->add('detailContrat', DetailContratType::class)
            ->add('formule', EntityType::class, [
                'class' => Formule::class,
                'query_builder' => function (EntityRepository $er) {
                    return $er->createQueryBuilder('u')
                        ->orderBy('u.libelle', 'ASC');
                },
                'choice_label' => 'libelle',
                'required' => 'false',
            ])
            ->add('ancienneFormule', TextType::class, [
                'required' => 'false',
            ])
            ->add('resiliation', ResiliationType::class)
            ->add('save', SubmitType::class, ['label' => 'Créer l\'adhérent']);


    }

我只是试图在我的附属表格中添加 ID 为 属性 的 Demandeur(超级 class)表格,但它是 Adherent 和 Demandeur 之间的继承,而不是关系。

class DemandeurType extends AbstractType
{
    /**
     *{@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {     
        $builder 
            ->add('id', IntegerType::class);
    }
}

class AdherentType extends AbstractType
{
    /**
     *{@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {     
        $builder 
            ->add('demandeur', EntityType::class, [
                'class' => Demandeur::class
            ])
            ....
    }
}

有些事情我不明白,因为它没有按照我认为应该的方式工作...

编辑: 我添加了

parent::buildForm($builder, $options);

在我的 adherenttype class 中,我不再有任何错误,但仍然不想更新任何内容,只是添加...

编辑:我设法让它工作了!所以我提出了我的解决方案,以防有一天有人感兴趣! 我在 EventListener 文件夹中创建了一个 UpdateDemandeur.php 文件。我将函数 preUpdate 放入其中但为空,因为在更新之前不需要对 Demandeur table 执行任何操作。 棘手的部分在我的控制器中。因为我没有向我的表单发送任何对象,所以当表单被提交时,如果我因为实体管理器而使用 setId($id) 函数,我得到的对象对于 Symfony 事件来说是新的。我不得不使用合并功能。这是我正在使用的代码,它正在运行。

        if($request->isMethod('POST')){
            foreach($forms as $form){
                $form->handleRequest($request);
                if( !$form->isSubmitted()) continue;

                if($form->isValid()){
                    $demandeur = $form->getData();
                    $id = $request->request->get($type)['id'];
                    if($id > 0) {
                        $demandeur->setId($id);
                        //Need to merge the new demandeur Object filled 
                        //with data from the form to update it in database
                        $dem = $em->merge($demandeur);

                    } else {
                        $em->persist($demandeur);
                    }
                    $em->flush();
                    return $this->redirectToRoute('demandeur_add');
                }
            }
        }

希望对大家有所帮助!