且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何在 Symfony2 中创建一个包含一个实体的多行的表单

更新时间:2023-11-19 23:00:22

这是一个可能的解决方案的开始.下面的示例采用单个实体技能并在单个页面上显示所有这些.我不知道的是这种技术是否可以用于持久化子对象.我希望可以遍历返回的数据并根据需要保留.

下面的代码会生成一个页面,其中包含所有可能的技能列表和一个用于声明每个技能已启用或已启用的复选框.

在控制器中:

 $skills = $em->getRepository("TruckeeMatchingBundle:Skill")->getSkills();$formSkills = $this->createForm(new SkillsType(), array('skills' => $skills));...if ($request->getMethod() == 'POST') {$formSkills->handleRequest($request);foreach ($skills as $existingSkill) {$em->persist($existingSkill);}}...返回 ['formSkills' =>$formSkills->createView(),...]

在模板中:

{% for Skills in formSkills.skills %}{{ 技能.vars.value.skill }}<input type="hidden" name="skills[skills][{{ loop.index0 }}][skill]" value="{{ Skill.vars.value.skill }}"><input type="checkbox" name="skills[skills][{{ loop.index0 }}][enabled]"{%if Skill.vars.value.enabled %}checked="checked"{%endif%}{% 结束为 %}

First I've read documents for both Collection Field Type and How to Embed a Collection of Forms ... The example is about one entity (Task) that has one-to-many relation with another entity (Tag), and I understand it, but I can not adapt it to what I want!

To make it simpler, let say I have a Task entity, this task entity has some relations with other objects like user and project (each task can have one user and one project)

I want to make one form, inside this form a list of Tasks, each task in one row of a table that shows information like task.title, task.startdate, task.user.name, task.user.company.name, task.project.name, And it has 2 fields editable, textbox "Description" and checkbox "active". You can edit multiple tasks and submit the form using one button at the bottom of the table in the main form, so basically you should be able to update multiple records in one transaction (instead of making one form and one submit button per row and therefor one record update per submit).

I have many issues with this complicated design:

First I wanted to follow the sample to embed a collection of forms inside the main form, So I made a Form Type for my Task that should be like one form per row. I made these files:

Form Type for Task:

// src/Acme/TaskBundle/Form/Type/TaskType.php
namespace AcmeTaskBundleFormType;

use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolverInterface;

class TaskType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
         $builder->add('description', 'text', ['label' => false, 'required' => false, 'attr' => ['placeholder' => 'description']]);
         $builder->add('active', 'checkbox', ['label' => false, 'required' => false, 'data' => true]);
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AcmeTaskBundleEntityTask',
        ));
    }

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

Form Type for main form:

// src/Acme/TaskBundle/Form/Type/SaveTasksType.php
namespace AcmeTaskBundleFormType;

use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolverInterface;
use AcmeTaskBundleFormTypeTaskType.php;

class SaveTasksType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('tasksCollection', 'collection', ['type' => new TaskType()]);
        $builder->add('tasksSubmit', 'submit', ['label' => 'Save']);
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults([
            'attr' => ['class' => 'form-horizontal'],
            'method' => 'POST'
        ]);
    }

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

Tasks Form Controller:

// src/Acme/TaskBundle/Controller/ManageTasksController.php
namespace AcmeTaskBundleController;

use AcmeTaskBundleEntityTask;
use AcmeTaskBundleFormTypeSaveTaskType;
use SymfonyComponentHttpFoundationRequest;
use SymfonyBundleFrameworkBundleControllerController;

class ManageTasksController extends Controller
{
    public function showListAction(Request $request)
    {
        $repository = $this->getDoctrine()->getRepository('ExampleBundle:Task');
        $tasks = $repository->findAll();

        $taskSaveForm = $this->createForm(new SaveTasksType(['tasks' => $tasks]));

        return $this->render('AcmeTaskBundle:Task:list.html.twig', array(
            'taskSaveForm' => $taskSaveForm->createView(),
        ));
    }
}

Task Form Twig Template (just related part):

<div class="innerAll">
    {{ form_start(taskSaveForm) }}
    {{ form_errors(taskSaveForm) }}

    <table class="table table-bordered table-striped table-primary list-table">
        <thead>
            <tr>
                <th>Task ID</th>
                <th>Title</th>
                <th>Start Date</th>
                <th>User</th>
                <th>Company</th>
                <th>Project</th>
                <th>Description</th>
                <th>Active</th>
            </tr>
        </thead>
        <tbody>
            {% for task in taskSaveForm.tasksCollection %}

                <tr>
                    <td>{{ task.id }}</td>
                    <td><a href="https://localhost/taskid={{ task.id }}">{{ task.title }}</a></td>
                    <td>{{ task.startDate }}</td>
                    <td>{{ task.userName }}</td>
                    <td>{{ task.companyName }}</td>
                    <td>{{ task.projectName }}</td>
                    <td>{{ form_widget(task.description) }}</td>
                    <td>{{ form_widget(task.active) }}</td>
                    <td></td>
                </tr>
            {% endfor %}
        </tbody>
    </table>
    <div>{{ form_row(taskSaveForm.tasksSubmit) }}</div>
    {{ form_end(taskSaveForm) }}
</div>

BUT there is an issue here, when I get the result from query builder it is a mess of arrays containing objects in them, I get an error about

The form's view data is expected to be an instance of class AcmeTaskBundleEntityTask, but is a(n) array. You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms a(n) array to an instance of AcmeTaskBundleEntityTask.

This is the query:

createQueryBuilder()
    ->select(
            "
            task.id,
            task.title,
            task.startDate,
            task.description,
            user.name as userName,
            company.name as companyName,
            project.name as projectName,
            "
    )
        ->from('AcmeTaskBundleEntityTask', 'task')
        ->innerJoin('task.project', 'project')
        ->innerJoin('task.user', 'user')
        ->innerJoin('AcmeTaskBundleEntityCompany', 'company', 'with', 'store.company = company')
        ->where('task.active = :isActive')->setParameter('isActive', true);

Soooo, I used Partial Objects guide to see if it can help, it helps to make the task object in the query result and I could extract it and send it to form, but still it seems the rest of form is unaware of the rest of objects...

Ok, so maybe I'm choosing the wrong approach, I'm not sure! please if you have any suggestions about what should I do, put a note here... I'm struggling with this for more than a week! Thanks in advance for your time! Even if you don't put any note, I appreciate that you spend time reading my very long question! Thanks! :)

Here's a start on a possible solution. The example below takes a single entity Skills and presents all of them on a single page. What I don't know is whether this technique can be used to persist children objects. I would expect one could loop through the returned data and persist as required.

The code below results in a page with a list of all possible Skills and a checkbox for declaring each enabled or enabled.

In a controller:

    $skills = $em->getRepository("TruckeeMatchingBundle:Skill")->getSkills();
    $formSkills = $this->createForm(new SkillsType(), array('skills' => $skills));
    ...
        if ($request->getMethod() == 'POST') {
            $formSkills->handleRequest($request);
            foreach ($skills as $existingSkill) {
                $em->persist($existingSkill);
            }
        }
    ...
    return ['formSkills' => $formSkills->createView(),...]

In a template:

{% for skill in formSkills.skills %}
    {{ skill.vars.value.skill }}
            <input type="hidden" name="skills[skills][{{ loop.index0 }}][skill]" value="{{ skill.vars.value.skill }}">
            <input type="checkbox" name="skills[skills][{{ loop.index0 }}][enabled]" 
            {%if skill.vars.value.enabled %}checked="checked"{%endif%}
{% endfor %}

登录 关闭
扫码关注1秒登录
如何在 Symfony2 中创建一个包含一个实体的多行的表单
发送“验证码”获取 | 15天全站免登陆

相关阅读

推荐文章