Несколько форм для экземпляров сущностей — symfony3

Я пытаюсь создать форму, которая позволила бы менеджеру утвердить список запросов на отпуск (также планирую иметь список дел и хочу иметь возможность пометить их как выполненные).

Я прочитал [Генерировать один и тот же тип формы на одной и той же странице несколько раз Symfony2 (а также несколько других), и я близок к пониманию, но я довольно новичок в Symfony и не понимаю, какие части кода должны находиться в каких файлах . Я использую тип формы и контроллер в Symfony3 с Doctrine.

У меня есть список экземпляров сущности, которые были возвращены из запроса ($ em-> createQuery) в контроллере, и я хочу создать форму для каждого экземпляра сущности или даже две формы для каждой сущности (одна для утверждения и одна для отклонения) .

В указанном вопросе говорится, что вам нужен цикл для их отображения и сохранения. Мое намерение состоит в том, чтобы работать (отправлять) только по одному за раз. Я предполагаю, что эта часть кода будет идти в контроллере?

Я использую indexAction для контроллера, но использую его больше как действие Edit, так как я буду обрабатывать формы, поэтому я передаю объект Request и объекты в качестве параметров.

>

class HRMgrController extends Controller
{
    /**
     * Lists all manager role requests and provide a means to approve/deny.
     *
     * @Route("/", name="hrmgr_index")
     * @Method({"GET", "POST"})
     * @Security("has_role('ROLE_APP_MANAGER')")
     */    
public function indexAction(Request $request, TimeOffRequest $timeOffRequest)
{
    if (!empty($timeOffRequest)) {
            $form = $this->createForm('CockpitBundle\Form\TORApprovalType', $timeOffRequest);
        print "TOR Id = " . $timeOffRequest->getId() . "<BR>";
        $em = $this->getDoctrine()->getManager();
        $form->handleRequest($request);
        print "Form name = " . $form->getName() . "<BR>";
        if ($form->isSubmitted() && $form->isValid()) {
            if ($form->get('approve')->isClicked()) {
                print "This puppy was approved";
                $timeOffRequest['status'] = 4;
            }
            if ($form->get('reject')->isClicked()) {
                print "This puppy was rejected";
                $timeOffRequest['status'] = 1;
            }
            $this->getDoctrine()->getManager()->flush();
            print "At least its there<BR>";
            // return $this->redirectToRoute('hrmgr_index');
        } else {
            print "did not detect form submission<BR>";
        }
    } 

    $emp = new \CockpitBundle\Entity\Employee();

    $date = new \DateTime();
    $year = $date->format('Y');
    $username = $this->getUser()->getUserName();
    $user = $em->getRepository('CockpitBundle:Employee')->findByUsername($username);
    $employees = $em->getRepository('CockpitBundle:Employee')->htmlContact($user);
    $tors = $em->getRepository('CockpitBundle:TimeOffRequest')->findMgrUnapprovedTORs($user->getId());
    $timeoff = "<h3>Unapproved Time Off Requests</h3>";
    $actions = true;

    $torforms = [];
    foreach ($tors as $tor) {
        $target = $this->generateUrl('hrmgr_index',array("tor_id" => $tor->getId()));
        $torforms[] = $this->actionForm($tor,$target)->createView();
    }
    return $this->render('hrmgr/index.html.twig', array(
        'torforms' => $torforms,
    ));

У меня есть формы, работающие сейчас, но когда я отправляю их, isSubmitted(), похоже, не работает. В настоящее время он выводит «не обнаружено отправку формы».

Итак, когда у меня есть несколько форм и я отправляю одну, получает ли handleRequest правильную форму? Я думаю, что здесь я тоже могу спутать два понятия. Недавно я изменил код, чтобы отправить идентификатор timeOffRequest в качестве параметра маршрута. Он правильно подбирает это, что позволяет мне потенциально обновлять форму, но эта часть кода, похоже, не работает.

Я заметил, что если я смотрю на отладчик, я получаю что-то вроде:

>   approval_form_2 
   [▼
     "reject" => ""
     "_token" => "IE1rGa5c0vaJYk74_ncxgFsoDU7wWlkAAWWjLe3Jr1w"
   ]

если я нажму кнопку отклонения. Я получаю аналогичную форму с «одобрить», если нажимаю кнопку «одобрить», поэтому кажется, что я близок. Кроме того, правильный идентификатор отображается из маршрута, указанного в действии.

Вот генератор форм:

<?php

namespace CockpitBundle\Form;


use CockpitBundle\Entity\Employee;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\ButtonType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;

class TORApprovalType extends AbstractType
{

    private $nameSuffix = null;
    private $name = 'time_req_approval';
    public function __constructor(string $suffix = null)   {
        //parent::__construct();

        $this->nameSuffix = $this->generateNameSuffix();
    }

    private function generateNameSuffix() {
        if ($this->nameSuffix == null ||  $this->nameSuffix == '') {
            $generator = new SecureRandom();
            //change data to alphanumeric string
            return bin2hex($generator->nextBytes(10));
        }

        return $this->nameSuffix;
    }
    public function setNameSuffix($suffix){
        $this->nameSuffix = $suffix;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // Build your form...
        $builder->add('approve', SubmitType::class, array(
            'label' => "Approve",
            'attr' => array("class"=>"action-approve"),
        ));
        $builder->add('reject', SubmitType::class, array(
            'label' => "Reject",
            'attr' => array("class"=>"action-reject"),
        ));
        //$builder->add('employee');

    }
    public function getName()    {
        if ($this->nameSuffix == null || $this->nameSuffix == "" ) {
            $this->nameSuffix = $this->generateNameSuffix();
        }
        return $this->name .'_'. $this->nameSuffix;
    }
    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'CockpitBundle\Entity\TimeOffRequest'
        ));
    }

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


}

Любые подсказки? (извините, я в отпуске, поэтому не очень быстро с обновлениями.


person Hinson    schedule 15.03.2017    source источник
comment
То, как вы это делаете, это одна форма с двумя кнопками отправки, одна из которых называется approve, а другая — reject. Это было бы совершенно нормально, но я думаю, что вы немного запутались в синтаксисе и использовании нескольких форм. Не могли бы вы предоставить код TimeOffRequestType?   -  person KhorneHoly    schedule 15.03.2017


Ответы (2)


Вы можете сделать несколько кнопок отправки: проверьте тип формы

    ->add('approve', 'submit')
    ->add('reject', 'submit')

затем в вашем контроллере

 if ($form->isValid()) {
        // ... do something

        // the save_and_add button was clicked
        if ($form->get('approve')->isClicked()) {
            // probably redirect to the add page again
        }
        if ($form->get('reject')->isClicked()) {
            // probably redirect to the add page again
        }

        // redirect to the show page for the just submitted item
    }
person Youssef Saoubou    schedule 15.03.2017
comment
Я создаю файл TORApprovalType (отличный от редактирования CRUD), который будет генерировать желаемую форму. Мне нужно, чтобы он мог создавать несколько форм, которые будут отображаться на одной странице. - person Hinson; 15.03.2017
comment
Вы можете дать более подробную информацию ? - person Youssef Saoubou; 16.03.2017

Я смог заставить его работать со следующим строителем.

   $builder->add('approve', SubmitType::class, array(
        'label' => "Approve",
        'attr' => array("class"=>"action-approve"),
    ));
    $builder->add('reject', SubmitType::class, array(
        'label' => "Reject",
        'attr' => array("class"=>"action-reject"),
    ));

Затем в форме контроллера я генерирую и обрабатываю формы как таковые. Не уверен, что это оптимальный способ, но он работает. Конечно, этот подход каждый раз перерисовывает весь список, но это нормально для того, что я делаю.

class HRMgrController extends Controller
{
    /**
     * Lists all manager role requests and provide a means to approve/deny.
     *
     * @Route("/", name="manager_home")
     * @Method({"GET"})
     * @Security("has_role('ROLE_APP_MANAGER')")
     */
    public function indexAction()
    {
        $em = $this->getDoctrine()->getManager();
        $emp = new \CockpitBundle\Entity\Employee();
        $employeeSummary = [];
        $date = new \DateTime();
        $year = $date->format('Y');
        $username = $this->getUser()->getUserName();
        $user = $em->getRepository('CockpitBundle:Employee')->findByUsername($username);
        $myemployees = $em->getRepository('CockpitBundle:Employee')->findManagersEmployees($user);
        $torRep = $em->getRepository('CockpitBundle:TimeOffRequest');
        $toas = [];
        $torforms = [];
        foreach ($myemployees as $employee) {
            $tors = $torRep->findAllMine($employee,$year);
            $toas[$employee->getDisplayName()] = $em->getRepository('CockpitBundle:TimeOffAllocation')->getEmpAllocation($employee->getId(),$year);
            $employeeSummary[$employee->getDisplayName()] = $torRep->mySummary($tors,$toas[$employee->getDisplayName()]);
            if (array_key_exists('items',$employeeSummary[$employee->getDisplayName()]['Vacation']['Requested'])) {
                foreach ($employeeSummary[$employee->getDisplayName()]['Vacation']['Requested']['items'] as $tor) {
                    $target = $this->generateUrl('hrmgr_tor_approval',array("tor_id" => $tor->getId()));
                    $torforms[] = $this->actionForm($tor,$target)->createView();
                }
            }
            if (array_key_exists('items',$employeeSummary[$employee->getDisplayName()]['Sick Time']['Requested'])) {
                foreach ($employeeSummary[$employee->getDisplayName()]['Sick Time']['Requested']['items'] as $tor) {
                    $target = $this->generateUrl('hrmgr_tor_approval',array("tor_id" => $tor->getId()));
                    $torforms[] = $this->actionForm($tor,$target)->createView();
                }
            }
            if (array_key_exists('Time Off',$employeeSummary[$employee->getDisplayName()]) && 
                    array_key_exists('items',$employeeSummary[$employee->getDisplayName()]['Time Off']['Requested'])) {
                foreach ($employeeSummary[$employee->getDisplayName()]['Time Off']['Requested']['items'] as $tor) {
                    $target = $this->generateUrl('hrmgr_tor_approval',array("tor_id" => $tor->getId()));
                    $torforms[] = $this->actionForm($tor,$target)->createView();
                }
            }
        }

        return $this->render('hrmgr/index.html.twig', array(
            'employeeSummary' => $employeeSummary,
            'torforms' => $torforms,
            'year' => $year,
        ));
    }
    /**
     * Lists all manager role requests and provide a means to approve/deny.
     *
     * @Route("/{tor_id}", name="hrmgr_tor_approval")
     * @Method({ "POST" })
     * @ParamConverter("timeOffRequest", class="CockpitBundle:TimeOffRequest", options={"id"="tor_id"})
     * @Security("has_role('ROLE_APP_MANAGER')")
     */
    public function approvalAction(Request $request, TimeOffRequest $timeOffRequest)
    {
        if (!empty($timeOffRequest)) {
            $form = $this->createForm('CockpitBundle\Form\TORApprovalType', $timeOffRequest);
            $id = $timeOffRequest->getId();
            $em = $this->getDoctrine()->getManager();
            $form->handleRequest($request);
            $postparams = $request->request->all();

            if (array_key_exists("approval_form_$id",$postparams)) {
                // Form was submitted
                if (array_key_exists("approve",$postparams["approval_form_$id"])) {
                    $status = $em->getReference('CockpitBundle\Entity\TimeOffStatus', 4);
                    $timeOffRequest->setStatus($status);
                    $timeOffRequest->setApprovedDate(new \DateTime);
                    $em->persist($timeOffRequest);
                    $em->flush($timeOffRequest);
                }
                if (array_key_exists("reject",$postparams["approval_form_$id"])) {
                    $status = $em->getReference('CockpitBundle\Entity\TimeOffStatus', 1);
                    $timeOffRequest->setStatus($status);
                    $timeOffRequest->setApprovedDate(new \DateTime);
                    $em->persist($timeOffRequest);
                    $em->flush($timeOffRequest);
                }
            } else {
                print "Form did not exist<BR>";
            }
            return $this->redirectToRoute('manager_home');
        } 
    }
    public function actionForm($tor,$target) {
        return $this->get('form.factory')->createNamedBuilder('approval_form_'.$tor->getId(), \CockpitBundle\Form\TORApprovalType::class, $tor,
             array("action"=> $target))->getForm();        
    }
}
person Hinson    schedule 07.06.2017