簡體   English   中英

Symfony 3-編輯表單-用數據庫數據填充字段(數組)

[英]Symfony 3 - Edit form - populate fields with db data (array)

我需要一個帶有3個動態選擇框(choicetypes)的表單,提交表單后,這些表單將作為序列化數組保存在數據庫中。

我設法使它最終運行,但是現在我在編輯項目時努力用數據庫值填充下拉列表。

項目實體

<?php

namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="projects")
 */
class Projects
{
    /**
     * @ORM\Column(type="string", length=255)
     */
    protected $projectName;
    /**
     * @ORM\Column(type="array")
     */
    protected $frequency;
    /**
     * No database fields for these.
     * They are used just to populate the form fileds
     * and the serialized values are stored in the frequency field
     */
     protected $update;
     protected $every;
     protected $on;

    /*
     * Project Name
     */
    public function getProjectName()
    {
        return $this->projectName;
    }
    public function setProjectName($projectName)
    {
        $this->projectName = $projectName;
    }
    /*
     * Frequency
     */
    public function getFrequency()
    {
        return $this->frequency;
    }
    public function setFrequency($frequency)
    {
        $this->frequency = $frequency;
    }
    /*
     * Update
     */  
    public function getUpdate()
    {
        return $this->update;
    }
    public function setUpdate($update)
    {
        $this->update = $update;
    }
    /*
     * Every
     */  
    public function getEvery()
    {
        return $this->every;
    }
    public function setEvery($every)
    {
        $this->every = $every;
    }
    /*
     * On
     */  
    public function getOn()
    {
        return $this->on;
    }
    public function setOn($on)
    {
        $this->on = $on;
    }
}

項目負責人

<?php

namespace AppBundle\Controller;

use AppBundle\Entity\Projects;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;

/**
 * Projects controller.
 */
class ProjectsController extends Controller
{
    /**
     * @Route("/projects/new", name="projects_new")
     */
    public function newAction(Request $request)
    {
        $project = new Projects();
        $form = $this->createForm('AppBundle\Form\ProjectsType', $project);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            // This is where the data get's saved in the frequency field
            $frequency = array(
                "update" => $project->getUpdate(),
                "every" => $project->getEvery(),
                "on" => $project->getOn()
            );
            $project->setFrequency($frequency);

            $em->persist($project);
            $em->flush($project);

            return $this->redirectToRoute('projects_show', array('id' => $project->getId()));
        }

        return $this->render('projects/new.html.twig', array(
            'project' => $project,
            'form' => $form->createView(),
        ));
    }

    /**
     * @Route("/projects/edit/{id}", name="projects_edit", requirements={"id": "\d+"})
     * @ParamConverter("id", class="AppBundle:Projects")
     */
    public function editAction(Request $request, Projects $project)
    {
        $editForm = $this->createForm('AppBundle\Form\ProjectsType', $project);
        $editForm->handleRequest($request);

        if ($editForm->isSubmitted() && $editForm->isValid()) {
            // This is where the data get's saved in the frequency field
            $frequency = array(
                "update" => $project->getUpdate(),
                "every" => $project->getEvery(),
                "on" => $project->getOn()
            );
            $project->setFrequency($frequency);

            $this->getDoctrine()->getManager()->flush();

            return $this->redirectToRoute('projects_edit', array('id' => $project->getId()));
        }

        return $this->render('projects/edit.html.twig', array(
            'project' => $project,
            'edit_form' => $editForm->createView(),
            'delete_form' => $deleteForm->createView(),
        ));
    }
}

項目類型表格

<?php

namespace AppBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use AppBundle\Entity\Projects;

class ProjectsType extends AbstractType
{
    private function setUpdateChoice(Projects $project)
    {
        return $project->getFrequency()['update'];
    }

    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('projectName', null, array());

        $builder->add('update', ChoiceType::class, array(
                'label'         => 'Update',
                'attr'          => array(
                    'class' => 'update_selector',
                ),
                'choices' => array(
                    'Daily' => 'Daily',
                    'Weekly' => 'Weekly',
                    'Monthly' => 'Monthly'
                ),
                'data' => $this->setUpdateChoice($builder->getData())
            )
        );

        $addFrequencyEveryField = function (FormInterface $form, $update_val) {
            $choices = array();
            switch ($update_val) {
                case 'Daily':
                    $choices = array('1' => '1', '2' => '2');
                    break;

                case 'Weekly':
                    $choices = array('Week' => 'Week', '2 Weeks' => '2 Weeks');
                    break;

                case 'Monthly':
                    $choices = array('Month' => 'Month', '2 Months' => '2 Months');
                    break;

                default:
                    $choices = array();
                    break;
            }
        };

        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($addFrequencyEveryField) {
                $update = $event->getData()->getUpdate();
                $update_val = $update ? $update->getUpdate() : null;
                $addFrequencyEveryField($event->getForm(), $update_val);
            }
        );
        $builder->addEventListener(
            FormEvents::PRE_SUBMIT,
            function (FormEvent $event) use ($addFrequencyEveryField) {
                $data = $event->getData();
                $update_val = array_key_exists('update', $data) ? $data['update'] : null;
                $addFrequencyEveryField($event->getForm(), $update_val);
            }
        );

        $addFrequencyOnField = function (FormInterface $form, $every_val) {
            $choicesOn = array();
            switch ($every_val) {
                case 'Week':
                    $choicesOn = array(
                        'Monday' => 'Monday',
                        'Tuesday' => 'Tuesday',
                        'Wednesday' => 'Wednesday',
                        'Thursday' => 'Thursday',
                        'Friday' => 'Friday',
                        'Saturday' => 'Saturday',
                        'Sunday' => 'Sunday',
                    );
                break;

                case 'Month':
                    $choicesOn = array(
                        '1' => '1',
                        '2' => '2',
                        '3' => '3',
                        '4' => '4',
                        '5' => '5',
                        '6' => '6',
                        '7' => '7',
                    );
                break;

                default:
                    $choicesOn = array();
                break;
            }

            $form->add('on', ChoiceType::class, array(
                'choices'     => $choicesOn,
            ));

        };
        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($addFrequencyOnField) {
                $every = $event->getData()->getEvery();
                $every_val = $every ? $every->getEvery() : null;
                $addFrequencyOnField($event->getForm(), $every_val);
            }
        );
        $builder->addEventListener(
            FormEvents::PRE_SUBMIT,
            function (FormEvent $event) use ($addFrequencyOnField) {
                $data = $event->getData();
                $every_val = array_key_exists('every', $data) ? $data['every'] : null;
                $addFrequencyOnField($event->getForm(), $every_val);
            }
        );
    }
    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\Projects'
        ));
    }

    /**
     * {@inheritdoc}
     */
    public function getBlockPrefix()
    {
        return 'appbundle_projects';
    }
}

最后,包含ajax的Edit Template

{% extends 'base.html.twig' %}
{% block body %}
    {% block content %}
      <h1>Edit Project</h1>

      {{ form_start(edit_form) }}
          {{ form_widget(edit_form) }}
          <input type="submit" value="Edit" />
      {{ form_end(edit_form) }}
    {% endblock content %}


    {% block javascripts %}
        <script>
          var $update =       $('#appbundle_projects_update');
          var $every =        $('#appbundle_projects_every');
          var $on_selector =  $('#appbundle_projects_on');

          // When update gets selected ...
          $update.change(function() {
            $every.html('');
            // ... retrieve the corresponding form.
            var $form = $(this).closest('form');
            // Simulate form data, but only include the selected update value.
            var data = {};
            data[$update.attr('name')] = $update.val();
            // Submit data via AJAX to the form's action path.
            $.ajax({
              url : $form.attr('action'),
              type: $form.attr('method'),
              data : data,
              success: function(html) {
                var options = $(html).find('#appbundle_projects_every option');
                for (var i=0, total = options.length; i < total; i++) {
                    $every.append(options[i]);
                }
              }
            });
          });
          // // When every gets selected ...
          $every.change(function() {
            $on_selector.html('');
            // ... retrieve the corresponding form.
            var $form = $(this).closest('form');
            // Simulate form data, but only include the selected every value.
            var data = {};
            data[$every.attr('name')] = $every.val();
            // Submit data via AJAX to the form's action path.
            $.ajax({
              url : $form.attr('action'),
              type: $form.attr('method'),
              data : data,
              success: function(html) {
                  var options = $(html).find('#appbundle_projects_on option');
                  for (var i=0, total = options.length; i < total; i++) {
                      $on_selector.append(options[i]);
                  }
              }
            });
          });
        </script>
    {% endblock javascripts %}
{% endblock %}

我能夠使用setUpdateChoice()在更新字段中設置選定的值,並將返回值分配給ProjectsType中的ChoiceType::class data 但是,這對every select或另一個都沒有任何影響, PRE_SET_DATA偵聽器返回null

我也嘗試了與其他兩個字段相同的方法,但是在偵聽器中呈現字段時, no such field (或類似內容)會導致錯誤

我還嘗試從控制器的頻率中獲取值,並在呈現表單之前使用setUpdate()setEvery()setOn() ,導致You can't modify a form that has already been submitted.

這是編輯項目時表單當前的呈現方式:

初始渲染

我需要這樣填充它:

在此處輸入圖片說明

我將如何解決這個問題的任何想法/建議/示例將不勝感激。

謝謝

PS。 如果我省略了一些內容,請告訴我,我將更新我的問題。

更新資料

多虧了Constantin的回答,我設法通過以下操作在控制器中設置了字段數據:

  public function editAction(Request $request, Projects $project)
  {
      $project->setUpdate($project->getFrequency()['update']);
      $project->setEvery($project->getFrequency()['every']);
      $project->setOn($project->getFrequency()['on']);

      $editForm = $this->createForm('AppBundle\Form\ProjectsType', $project);
      $editForm->handleRequest($request);

      if ($editForm->isSubmitted() && $editForm->isValid()) {
          $frequency = array(
              "update" => $project->getUpdate(),
              "every" => $project->getEvery(),
              "on" => $project->getOn()
          );


          $project->setFrequency($frequency);
          $this->getDoctrine()->getManager()->flush();

          return $this->redirectToRoute('projects_edit', array('id' => $project->getId()));
      }

      return $this->render('projects/edit.html.twig', array(
          'project' => $project,
          'edit_form' => $editForm->createView(),
          'delete_form' => $deleteForm->createView(),
      ));
  }

由於我沒有足夠的時間閱讀您的所有帖子,因此不確定是否會對您有所幫助。

首先(僅供參考),您可以在表單的3個字段( updateeveryon )中使用選項'mapped' => false並從您的實體中刪除這3個字段(這是一個映射您的實體,而不是數據庫)。

然后,您可以使用以下命令在控制器中訪問它們

$editForm->get('update')->getData(); //or setData( $data );

但是,當然可以保留這些屬性(如果需要),並且它對您更方便。 但是,如果要保留它們,請確保它們將始終反映您的頻率屬性中的數據。

接下來,我在您的編輯控制器中看到,在創建表單之前,您沒有設置3個字段的值。 由於這些字段未映射(這次與數據庫映射),因此當您獲取實體時,它們將為null (這是通過您的edit控制器中的paramConverter完成的)。 因此,在將$project作為創建表單中的參數傳遞之前,必須設置它們(反序列化或其他方式)。

希望對您有所幫助!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM