-2

我目前正在使用 Symfony2 重建一个网络应用程序。我希望用户更新他们在我们的 MySQL 数据库中的特定记录。但是,用户不是自信的计算机用户,也不喜欢 Web 应用程序(以其当前形式)的工作方式。因此,从 UI/UX 的角度来看,我决定使用 2 个表单来编辑特定数据,而不是当前用户不喜欢的 1 个表单。

有问题的 MySQL 数据库表包含许多信息字段,例如他们的个人详细信息和与他们相关的其他信息。表单被拆分以反映这一点,一个表单更新个人详细信息,一个表单更新其余的,因此用户不必处理一个长表单。

不过,目前,当我使用一种形式时,出现错误:

在表单提交期间,在链配置的命名空间中找不到类“Symfony\Component\Form\Form”

这个错误在这个问题中得到了解决。然而,它给我留下了一个问题。目前,因为我已将表单一分为二,我无法将这些数据保存到数据库中。我可以通过只使用一种形式来克服这个问题,但这违背了数据库用户的意愿。此外,我知道完全可以使用两个或多个表单将特定数据添加到单个数据库,就像我以前做过的那样,只是在 Symfony 中没有。

有谁知道或有一个建议,我可以如何克服这个问题?由于那里存在大量当前数据,因此更改数据库是不可能的。

更新

这是缺少的视图、控制器和表单文件。

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 public function viewAction($instructor, Request $request) { // 数据库连接 $insrep = $this->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

public function ipdeAction($instructor, Request $request) { // 数据库连接 $insrep = $this->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">

我的 routing.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
4

2 回答 2

1

对我来说,您正在生成 3 个表单(其中 1 个使用相同的实体$ir$ipde两次)这一事实似乎有点奇怪。您遇到的错误可能与此有关。

我以前做过,我可以为你分享一些指导方针:

  • 您不需要为每个表单使用单独的实体,您需要为您的实体使用单独的表单。不要误会我的意思,这两种方法都可以,但实际上并没有什么不同。在您的代码中,您使用的连接数是所需的两倍。

  • 您将 3 个表单传递给您的视图,但只呈现一个,为什么?除非您使用 AJAX,否则它没有意义。

让我描述一下要走的路:

  1. 创建您的应用程序需要的实体(通常每个表一个),您可以拆分它们,但这通常仅在使用更复杂的逻辑时才需要(即不同用户对同一行的不同类型的权限/所有权,尽管这有点)。

  2. 如果您想使用验证组件来确保您获得良好的数据,请使用验证组,一个组用于您要构建的每个表单)。

  3. 为您要构建的每个表单创建一个表单类型。听起来有点明显。您可以根据需要为任何实体拥有任意数量的表单类型。在每个表单上,仅包含您感兴趣的字段。

  4. 为每个表单创建一个视图。非常直截了当。

  5. 这是事情变化最大的地方。你真正需要的是,每个表单都有一个控制器动作,不要混合它们,你什么都没有。每个控制器动作应该:

    • 加载您感兴趣的实体
    • 建立一个正确类型的表格。
    • 如果 GET,则只渲染一个表单并返回。
    • 如果是 POST,绑定请求,保存并做一些事情。

基本上,工作流程将类似于:

  • 用户想要编辑实体id=X,
  • 您调用处理要编辑的数据的控制器并返回表单。
  • 用户提交表单,您保存数据。您可以使用重定向来链接过程的两个部分,只需重定向到处理扩展信息的第二个控制器的 url。如果您正在链接,您可能会发现使用Flash 消息让用户知道信息已保存很有用。

希望这可以帮助。

于 2013-04-29T12:31:36.680 回答
1

经过大量搜索,我在 Symfony2 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()代码,并且它可以工作。没有更多错误,数据保存到数据库中!!!!

于 2013-04-29T15:50:48.697 回答