Como criar um formulário com várias linhas de uma entidade no Symfony2

Primeiro eu li documentos para ambosTipo de campo de coleta eComo incorporar uma coleção de formulários ... O exemplo é sobre uma entidade (Tarefa) que tem relação um-para-muitos com outra entidade (Tag), e eu entendo, mas não consigo adaptá-lo ao que eu quero!

Para simplificar, digamos que eu tenha uma entidade Tarefa, essa entidade possui algumas relações com outros objetos, como usuário e projeto (cada tarefa pode ter um usuário e um projeto)

Quero criar um formulário, dentro desse formulário, uma lista de tarefas, cada tarefa em uma linha de uma tabela que mostra informações comotask.title, task.startdate, task.user.name, task.user.company.name, task.project.nameE tem 2 campos editáveis,caixa de texto "Descrição" ecaixa de seleção "ativo". Você pode editar várias tarefas e enviar o formulário usando um botão na parte inferior da tabela no formulário principal. Portanto, basicamente, você poderá atualizar vários registros em uma transação (em vez de criar um formulário e um botão de envio por linha e, portanto, uma atualização de registro por envio).

Tenho muitos problemas com esse design complicado:

Primeiro, eu queria seguir o exemplo para incorporar uma coleção de formulários dentro do formulário principal. Portanto, criei um Tipo de formulário para minha tarefa que deveria ser como um formulário por linha. Eu criei esses arquivos:

Tipo de formulário para tarefa:

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

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

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' => 'Acme\TaskBundle\Entity\Task',
        ));
    }

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

Tipo de formulário para o formulário principal:

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

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Acme\TaskBundle\Form\Type\TaskType.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';
    }
}

Controlador de formulário de tarefas:

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

use Acme\TaskBundle\Entity\Task;
use Acme\TaskBundle\Form\Type\SaveTaskType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

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(),
        ));
    }
}

Modelo de galho de formulário de tarefa (apenas parte relacionada):

<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>

MAS existe um problema aqui, quando recebo o resultado do construtor de consultas, é uma bagunça de matrizes contendo objetos neles, recebo um erro sobre

Espera-se que os dados de exibição do formulário sejam uma instância da classe Acme \ TaskBundle \ Entity \ Task, mas é uma matriz (n). Você pode evitar esse erro definindo a opção "data_class" como nula ou adicionando um transformador de exibição que transforma uma matriz (n) em uma instância de Acme \ TaskBundle \ Entity \ Task.

Esta é a consulta:

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

Então eu useiObjetos Parciais guia para ver se ele pode ajudar, ajuda a tornar o objeto de tarefa no resultado da consulta e eu poderia extraí-lo e enviá-lo para o formulário, mas ainda assim parece que o restante do formulário não tem conhecimento do restante dos objetos ...

Ok, então talvez eu esteja escolhendo a abordagem errada, não tenho certeza! por favor, se você tiver alguma sugestão sobre o que devo fazer, coloque uma nota aqui ... Estou lutando com isso por mais de uma semana! Agradeço antecipadamente pelo seu tempo! Mesmo que você não faça nenhuma anotação, eu aprecio que você gaste tempo lendo minha pergunta muito longa! Obrigado! :)

questionAnswers(2)

yourAnswerToTheQuestion