2013-04-25 73 views
-2

我目前正在使用Symfony2重新構建Web應用程序。我希望用戶更新他們在我們的MySQL數據庫上的特定記錄。但是,用戶對計算機用戶並不自信,並且不喜歡Web應用程序(以其當前形式)的工作方式。 因此,從UI/UX的角度來看,我決定使用2種形式來編輯特定的數據,而不是用戶不喜歡的當前1形式。如何在Symfony2中將表單保存到數據庫中,而不是實體

有問題的MySQL數據庫表包含許多信息領域,例如他們的個人信息和與他們相關的其他信息。表單被分割以反映這一點,其中一個表單更新個人細節,一個表單更新其餘表單,因此用戶不必處理一個長表單。

此刻雖然,當我去使用一個形式,我得到的錯誤:

The class 'Symfony\Component\Form\Form' was not found in the chain configured namespaces during Form Submission

此錯誤是在這個question解決。但是,這給我留下了一個問題。目前,由於我將表單分成兩部分,因此我無法將此數據保存到數據庫。我可以通過使用一種形式來克服這一點,但這違背了數據庫用戶的意願。此外,我知道完全有可能使用兩種或更多種形式將特定數據添加到單個數據庫,就像我之前完成的那樣,而不是在Symfony中。

有誰知道,或有建議,我該如何克服這一點?由於當前數據量龐大,因此更改數據庫不存在問題。

UPDATE

這裏是缺少視圖,控制器並形成文件。

view.html.twig

<!-- Modal Windows: Edit Instructor Personal Details --> 
<div id="editPersonal" style="display:none;"> 
    <div class="modal-head"> 
     <h2>Edit Personal Details For: <font-color="red !important">{{instructor.firstName}} {{instructor.surname}}</font></h2> 
    </div> 
    <div class="modal-body"> 
     <form action="#" method="post" {{ form_enctype(ipde) }} id="editPersonalDetails" class="modaledit"> 
     <table class="modalform-col1"> 
      <tbody> 
       <tr class="hidden"> 
        <th>{{ form_label(ipde.id, 'ID*', { 'attr': {'class': 'title'} }) }}</th> 
        <td> 
         {{ form_errors(ipde.id) }} 
         {{ form_widget(ipde.id, { 'attr': {'class': 'textfield'}}) }} 
        </td> 
       </tr> 
       <tr> 
        <th>{{ form_label(ipde.firstName, 'First Name*', { 'attr': {'class': 'title'} }) }}</th> 
        <td> 
         {{ form_errors(ipde.firstName) }} 
         {{ form_widget(ipde.firstName, { 'attr': {'class': 'text'}}) }} 
        </td> 
       </tr> 
       <tr> 
        <th>{{ form_label(ipde.surname, 'Surname*', { 'attr': {'class': 'title'} }) }}</th> 
        <td> 
         {{ form_errors(ipde.surname) }} 
         {{ form_widget(ipde.surname, { 'attr': {'class': 'text'}}) }} 
        </td> 
       </tr> 
       <tr> 
        <th>{{ form_label(ipde.address1, 'Address Line 1*', { 'attr': {'class': 'title'} }) }}</th> 
        <td> 
         {{ form_errors(ipde.address1) }} 
         {{ form_widget(ipde.address1, { 'attr': {'class': 'text'}}) }} 
        </td> 
       </tr> 
       <tr> 
        <th>{{ form_label(ipde.address2, 'Address Line 2', { 'attr': {'class': 'title'} }) }}</th> 
        <td> 
         {{ form_errors(ipde.address2) }} 
         {{ form_widget(ipde.address2, { 'attr': {'class': 'text'}}) }} 
        </td> 
       </tr> 
       <tr> 
        <th>{{ form_label(ipde.town, 'Town*', { 'attr': {'class': 'title'} }) }}</th> 
        <td> 
         {{ form_errors(ipde.town) }} 
         {{ form_widget(ipde.town, { 'attr': {'class': 'text'}}) }} 
        </td> 
       </tr> 
       <tr> 
        <th>{{ form_label(ipde.county, 'County*', { 'attr': {'class': 'title'} }) }}</th> 
        <td> 
         {{ form_errors(ipde.county) }} 
         {{ form_widget(ipde.county, { 'attr': {'class': 'text'}}) }} 
        </td> 
       </tr> 
       <tr> 
        <th>{{ form_label(ipde.postcode, 'Postcode*', { 'attr': {'class': 'title'} }) }}</th> 
        <td> 
         {{ form_errors(ipde.postcode) }} 
         {{ form_widget(ipde.postcode, { 'attr': {'class': 'text'}}) }} 
        </td> 
       </tr> 
       <tr> 
        <th>{{ form_label(ipde.email, 'Email*', { 'attr': {'class': 'title'} }) }}</th> 
        <td> 
         {{ form_errors(ipde.email) }} 
         {{ form_widget(ipde.email, { 'attr': {'class': 'text'}}) }} 
        </td> 
       </tr> 
      </tbody> 
     </table> 
    </div> 
    <div class="modal-footer"> 
     <div class="modal-placeright"> 
      <a href="#close" rel="modal:close" class="closebutton">Close Without Saving</a> 
      <input type="submit" value="Save Changes" id="savebuttonpr" class="savebutton" /> 
      {{ form_rest(ipde) }} 
     </div> 
    </div> 
</div> 

DefaultController.php

<?php 

namespace PCUK\InstructorBundle\Controller; 

use Symfony\Bundle\FrameworkBundle\Controller\Controller; 
use PCUK\InstructorBundle\Form\IpdeType; 
use PCUK\InstructorBundle\Form\IrType; 
use PCUK\InstructorBundle\Form\BaType; 
use Symfony\Component\HttpFoundation\Request; 

class DefaultController extends Controller 
{ 

    public function viewAction($instructor, Request $request) 
    { 
     // Database connection 
     $insrep = $this->getDoctrine()->getManager(); 

     // Get Instructor from Entity for Form use 
     $instructorQ = $insrep->getRepository('InstructorBundle:MapInstructors')->find($instructor); 

     // Get Shared Branches from Entity for Form use 
     $instructorS = $insrep->getRepository('InstructorBundle:MapInstructorShared')->find($instructor); 

     // Generate Form to edit Instructor Personal Details 
     $ipde = $this->createForm(new IpdeType(), $instructorQ); 

     // Handle Form submission to edit Instructor Personal Details 
     if ($request->getMethod() == 'POST') { 
      $ipde->bind($request); 

      if ($ipde->isValid()) { 
       // perform some action, such as saving the task to the database 

       //if ($this->request->isXmlHttpRequest()){ 
         //return data ajax requires. 
       //} 
       $em = $this->getDoctrine()->getManager(); 
       $em->persist($ipde); 
       $em->flush(); 


       return $this->redirect($this->generateUrl('task_success')); 
      } 
     } 

     // Generate Form to edit Instructor Records 
     $ir = $this->createForm(new IrType(), $instructorQ); 

     // Generate Form to edit Instructor Records 
     $ba = $this->createForm(new BaType(), $instructorS); 

     // Return data to view 
     return $this->render('InstructorBundle:Default:view.html.twig', array(
      'ipde' => $ipde->createView(), 
      'ir' => $ir->createView(), 
      'ba' => $ba->createView() 
     )); 
    } 
} 

IpdeType.php - 個人資料表格

<?php 
// src/PCUK/InstructorBundle/Form/Type/IpdeType.php 
// This is to handle forms for the Instructor Personal Details Form 
namespace PCUK\InstructorBundle\Form; 

use Doctrine\ORM\EntityRepository; 
use Symfony\Component\Form\Form; 
use Symfony\Component\Form\AbstractType; 
use Symfony\Component\Form\FormBuilderInterface; 
use Symfony\Component\Form\FileField; 

class IpdeType extends AbstractType 
{ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $builder->add('id', 'integer', array('required'=>false)); 
     //Personal Details 
     $builder->add('firstName', 'text', array('required'=>false)); 
     $builder->add('surname', 'text', array('required'=>false)); 
     $builder->add('address1', 'text', array('required'=>false)); 
     $builder->add('address2', 'text', array('required'=>false)); 
     $builder->add('town', 'text', array('required'=>false)); 
     $builder->add('county', 'text', array('required'=>false)); 
     $builder->add('postcode', 'text', array('required'=>false)); 
     $builder->add('email', 'text', array('required'=>false)); 
     $builder->add('phone', 'text', array('required'=>false)); 
     $builder->add('mobile', 'text', array('required'=>false)); 
     $builder->add('notes', 'text', array('required'=>false)); 
    } 

    public function getName() 
    { 
     return 'ipde'; 
    } 
} 

IrType.php - 其他信息表

<?php 
// src/PCUK/InstructorBundle/Form/Type/IrType.php 
// This is to handle forms for the Instructor Records Form 
namespace PCUK\InstructorBundle\Form; 

use Doctrine\ORM\EntityRepository; 
use Symfony\Component\Form\Form; 
use Symfony\Component\Form\AbstractType; 
use Symfony\Component\Form\FormBuilderInterface; 
use Symfony\Component\Form\FileField; 

class IrType extends AbstractType 
{ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $builder->add('id', 'integer', array('required'=>false)); 
     $builder->add('primaryArea', 'integer', array('required'=>false)); 
     $builder->add('primaryBranch','entity', array('class'=>'PCUK\InstructorBundle\Entity\MapBranches', 'property'=>'branchname')); 
     $builder->add('begin', 'date', array('required'=>false)); 
     $builder->add('lastCrb', 'date', array('required'=>false)); 
     $builder->add('latestCpd', 'date', array('required'=>false)); 
     $builder->add('preferredLevel','entity', array('class'=>'PCUK\InstructorBundle\Entity\MapInstructorLevels', 'property'=>'name')); 
     $builder->add('preferredDiscipline','entity', array('class'=>'PCUK\InstructorBundle\Entity\MapInstructorLevels', 'property'=>'name')); 
     $builder->add('currentLevel','entity', array('class'=>'PCUK\InstructorBundle\Entity\MapInstructorLevels', 'property'=>'name')); 
     $builder->add('bhs', 'checkbox', array('required'=>false)); 
     $builder->add('visiting','entity', array('class'=>'PCUK\InstructorBundle\Entity\MapInstructorVis', 'property'=>'name')); 
    } 

    public function getName() 
    { 
     return 'ir'; 
    } 
} 

更新:29/04/13 繼james_t的建議,我在兩個,每個分別形式拆分實體。但是,原始錯誤仍然存​​在。

我也在控制器中創建了一個新的操作,並且由於拆分實體沒有解決問題,我恢復爲使用單個實體。我現在控制器看起來如下:

的viewAction 公共職能的viewAction($講師,請求$請求) {// 數據庫連接 $ insrep = $這個 - > getDoctrine() - > getManager();

// Get IPDE from Entity for Form use 
$instructorIpde = $insrep->getRepository('InstructorBundle:MapInstructors')->find($instructor); 

// Generate Form to edit Instructor Personal Details 
$ipde = $this->createForm(new IpdeType(), $instructorIpde); 

// Get IR from Entity for Form use 
$instructorIr = $insrep->getRepository('InstructorBundle:MapInstructors')->find($instructor); 

// Generate Form to edit Instructor Records 
$ir = $this->createForm(new IrType(), $instructorIr); 

// Get Shared Branches from Entity for Form use 
$instructorBa = $insrep->getRepository('InstructorBundle:MapInstructorShared')->find($instructor); 

// Generate Form to edit Instructor Records 
$ba = $this->createForm(new BaType(), $instructorBa); 

// Return data to view 
return $this->render('InstructorBundle:Default:view.html.twig', array(
    'pagename' => $iname . ' - Instructors', 
    'ipde' => $ipde->createView(), 
    'ir' => $ir->createView(), 
    'ba' => $ba->createView(), 
     'iid' => $instructor 
)); 

}

ipdeAction

公共函數ipdeAction($指導員,請求$請求) { //數據庫連接 $ insrep = $這 - > getDoctrine() - > getManager();

// Get IPDE from Entity for Form use 
$instructorIpde = $insrep->getRepository('InstructorBundle:MapInstructors')->find($instructor); 

// Generate Form to edit Instructor Personal Details 
$ipde = $this->createForm(new IpdeType(), $instructorIpde); 

// Handle Form submission to edit Instructor Personal Details 
if ($request->getMethod() == 'POST') { 
    $ipde->bind($request); 

    if ($ipde->isValid()) { 
     // perform some action, such as saving the task to the database 

     //if ($this->request->isXmlHttpRequest()){ 
       //return data ajax requires. 
     //} 
     $em = $this->getDoctrine()->getManager(); 
     $em->persist($ipde); 
     $em->flush(); 

     $params = array(
      'instructor' => $instructor, 
     ); 

     return $this->redirect($this->generateUrl('instructor_viewinstructor', $params)); 
    } 
} 

}

我也修正了這個更新,我view.html.twig文件:

<form action="#" method="post" {{ form_enctype(ipde) }} id="editPersonalDetails" class="modaledit"> 

這樣:

<form action="{{ path('instructor_viewinstructor_ipde', {'instructor' :iid}) }}" method="post" {{ form_enctype(ipde) }} id="editPersonalDetails" class="modaledit"> 

我的路由。 yml文件現在看起來也是這樣:

instructor_viewinstructor: 
    pattern: /instructors/view/{instructor} 
    defaults: { _controller: InstructorBundle:Default:view } 

instructor_viewinstructor_ipde: 
    pattern: /instructors/view/{instructor}/ipde 
    defaults: { _controller: InstructorBundle:Default:ipde } 
    requirements: 
     _method: POST 
+0

表單和控制器的代碼將會很有幫助。表單是單獨編輯還是一個接一個地進行編輯(如設置嚮導)? – 2013-04-25 09:42:13

+0

對不起,知道有些事我忘了!我已經將它們添加到了那裏,供您查看。 – mickburkejnr 2013-04-25 09:50:31

+0

當你說數據庫,你的意思是表?將Native Queries與Doctrine一起使用並讀取請求變量沒有什麼問題,它只是更多的代碼,但是它可以工作。另外,表單不需要實體。這聽起來像你有一個顯示問題,只需使用[嵌入窗體](http://symfony.com/doc/current/book/forms.html#embedding-a-single-object),然後使用你的模板來製作它'容易'爲您的用戶。 – 2013-04-25 17:54:49

回答

1

經過大量搜索,我在Symfony2 Cookbook中遇到了這個條目。

說實話,我跳過了構建表格等的整個部分,因爲我覺得我沒有做錯(這是辯論我知道)。我覺得這個問題關心的是將這些數據保存到數據庫中,因此我跳到了cookbook的這一部分,該部分講述了將數據保存到數據庫的代碼。

我的代碼一直是這樣的:

// Database connection 
$insrep = $this->getDoctrine()->getManager(); 

if ($ipde->isValid()) { 
    // perform some action, such as saving the task to the database 

    //if ($this->request->isXmlHttpRequest()){ 
      //return data ajax requires. 
    //} 
    $em = $this->getDoctrine()->getManager(); 
    $em->persist($ipde); 
    $em->flush(); 

    $params = array(
     'instructor' => $instructor, 
    ); 

    return $this->redirect($this->generateUrl('instructor_viewinstructor', $params)); 
} 

在本文檔中,它是:

if ($form->isValid()) { 
    $registration = $form->getData(); 

    $em->persist($registration->getUser()); 
    $em->flush(); 

    return $this->redirect(...); 
} 

return $this->render(
    'AcmeAccountBundle:Account:register.html.twig', 
    array('form' => $form->createView()) 
); 

我發現我一直在使用$em = $this->getDoctrine()->getManager();中,而文檔建議您使用的差異$registration = $form->getData();。我改變了我的代碼,使用->getData()代碼,它的工作原理。沒有更多的錯誤,並且數據被保存到數據庫!

1

這似乎有點奇怪我的事實,你正在生成3種形式(其中1兩次相同的實體,$ IR$ IPDE)。你得到的錯誤可能與此有關。

我過去就這麼做過,我可以分享一些指引你:

  • 你不需要爲每個表單一個單獨的實體,您需要爲您的實體單獨的形式。不要誤會我的意思,它可以以任何方式工作,但它並沒有真正改變。在你的代碼中,你只需要使用比所需連接多兩倍的連接。

  • 您正在向您的視圖傳遞3個表單,但只呈現一個,爲什麼?,除非您使用AJAX,否則它沒有任何意義。

讓我描述的路要走:

  1. 創建實體您的應用需求(每桌通常一個),你可以將它們分割但是這通常只需要更多的工作時,複雜的邏輯(即不同用戶對同一行的不同類型的許可/所有權,雖然這是smelly)。

  2. 如果你想使用驗證組件,以確保您得到良好的數據,使用validation groups,一組爲每個表單要構建)。

  3. 爲每個要構建的表單創建表單類型。聽起來很明顯。你可以爲任何實體提供儘可能多的表單類型。在每個表單上,只包含您感興趣的字段。

  4. 爲每個表單創建一個視圖。非常直截了當。

  5. 這裏是事情變化最大的地方。你真正需要的是,每個表格一個控制器動作,不要混合它們,你什麼都不存儲。每個控制器動作應:

    • 加載您有興趣
    • 實體構建正確類型的一種形式。
    • 如果GET,然後渲染只是一個的形式並返回。
    • 如果POST,綁定請求,保存並做一些事情。

基本工作流程是這樣的:

  • 用戶想編輯的實體ID = X,
  • 你叫可以滿足您要編輯的數據控制器和返回表單。
  • 用戶提交表單並保存數據。你可以玩重定向鏈接進程的兩個部分,只是重定向到你的第二個處理擴展信息的控制器的url。如果您正在鏈接,則可能會發現使用flash messages可讓用戶知道信息已保存。

希望這會有所幫助。

+0

我已經玩過使用單獨的控制器操作來執行保存,但這個該死的錯誤仍然出現。我覺得這個問題是無法將表單提交給數據庫。我打算使用AJAX,但我想要一個回落,以防他們沒有Javascript。所以我試圖讓它在最基本的層面上工作,然後再進入AJAX調用。此外,有三種形式用於UX用途,所以我不會用大量數據壓倒計算機文盲。 – mickburkejnr 2013-04-29 15:03:44

+0

我從用戶體驗的角度瞭解您的意思,但從服務器應用程序設計角度來看,混合這樣的東西似乎並不是一個好習慣。有一種叫做[單一責任原則](http://en.wikipedia.org/wiki/Single_responsibility_principle)。您還需要在使用AJAX時保持控制器分離,並使用模板繼承將所有3種表單合併到同一頁面上。保持它自己的位置可以幫助你防止這些錯誤。 – Xocoatzin 2013-04-29 15:13:39

+0

我不認爲我完全關注你對控制器的分離。我知道我應該分開控制器,現在我已經完成了。但是這個錯誤仍然會發生,當它不應該? – mickburkejnr 2013-04-29 15:15:24

相關問題