doulutian4843 2014-06-25 19:44
浏览 54
已采纳

为什么symfony只在这里渲染一个嵌套的表单集合元素?

Edit: I have since figured out the issue. Explanation below and my work-around.

I have an app I'm working on for my HR department which will be used to perform employee annual evaluations. The way they've requested it, there are pages of bullet points grouped by subject (Business Sense, Skills, etc), and each bullet point is assigned a score by the reviewer. Every position in the company will have the same three pages of bullet points, but each department may elect to add more for the department as a whole, or for each position.

I have my entity for this designed and working properly.

The issue I'm running into is that I'm having some trouble getting the form to render. Right now, for testing purposes, I'm just rendering the form with {{ form(evaluation) }}. It's built with forms nested in a collection.

I've checked the builders with var_dump, and the EvaluationType (the outer form) shows the pages registred in the form, and if I var_dump the EvaluationPage object, it displays the bullet points registered to the object, but when the form renders, only the LAST bullet point renders. None of the other points from any other page display, only the last one added. I've checked and rechecked, and I'm sure it's something simple, but I can't find the issue.

Here are my code snippets:

EvaluationController (getModernEvaluationLocker just uses dummy data:

namespace Company\PerformanceBundle\Controller;

use Company\PerformanceBundle\Entity\Noncommitable\EvaluationLocker;
use Company\PerformanceBundle\Form\Builders\EvaluationType;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class EvaluationController extends Controller
{
    /**
     * @Route("/strive/evaluation", name="eval")
     * @Template("CompanyPerformanceBundle:Evaluation:Evaluation.html.twig")
     */
    function evaluationEntryAction()
    {

        $locker = $this->getModernEvaluationLocker();

        $em = $this->getDoctrine()->getManager();
        $form = $this->createForm(new EvaluationType($em, $locker));



        return array(
            'sidebarTitle' => 'Strive Evaluations Manager',
            'sidebar' => null,
            'function' => 'test',
            'title' => 'test',
            'evaluation' => $form->createView(),
        );
    }

    private function getModernEvaluationLocker()
    {
        $locker = new EvaluationLocker();

        $locker ->addPage('Brand Pillars and Core Values')
                    ->addBullet('Inspires a passion for the industry and ensures that the needs of all customers (internal and external) are met, benefitting both the customer and organization.')
                    ->addBullet('Completes work to high standards and continually looks for ways to improve performance.')
                    ->addBullet('Delivers remarkable customer service 100% of the time, each and everytime to both our internal and external customers.')
                ->addPage('Business Acumen')
                    ->addBullet('Clear understanding of The Company’s mission, initiatives and direction.')
                    ->addBullet('Has a broad and deep understanding of the issues that affect the organization, industry and the business environment.');

        return $locker;
    }  
}

EvaluationType (The outer form):

namespace Company\PerformanceBundle\Form\Builders;

use Doctrine\ORM\EntityManager;
use Company\PerformanceBundle\Entity\Noncommitable\EvaluationLocker;
use Company\PerformanceBundle\Entity\Noncommitable\EvaluationLockerPage;
use Company\PerformanceBundle\Form\EventListener\EvaluationPageSubscriber;
use Company\PerformanceBundle\Form\Fields\EvaluationPage;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;

class EvaluationType extends AbstractType {
    private $entityManager;
    private $evalLocker;

    public function __construct(EntityManager $em, EvaluationLocker $locker)
    {
        $this->entityManager = $em;
        $this->evalLocker = $locker;
    }

    public function getName() {

        return 'evaluation';

    }
    public function buildForm(FormBuilderInterface $builder, array $options) {

         $builder->addEventSubscriber(new EvaluationPageSubscriber($this->evalLocker));

         $builder
                ->add('employeeID', 'text', array(
                    'label' => 'Employee ID:',
                    'required' => true,
                    'trim' => true,
                    'error_bubbling' => true,
                    ))
                ->add('managerLogin', 'text', array(
                    'label' => 'Manager Login:',
                    'required' => true,
                    'trim' => true,
                    'error_bubbling' => true,
                    'mapped' => false,
                    ))
                ->add('managerPassword', 'password', array(
                    'label' => 'Manager Password:',
                    'required' => true,
                    'trim' => true,
                    'error_bubbling' => true,
                    'mapped' => false,
                    ))
                ->add('appraisalType', 'choice', array(
                    'choices' => array('0' => '90 Day', '1' => 'Annual'),
                    'required' => true,
                    'expanded' => true,
                    'multiple' => false,
                    'label' => 'Appraisal Type:',
                    'error_bubbling' => true,
                ))
                ->add('pages', 'collection');

         for($i =0; $i<=$this->evalLocker->getPageCount(); $i++)
         {
             $page = ($i==0 ? $this->evalLocker->rewind() : $this->evalLocker->next());
             if ($page)
             {  
                $builder->get('pages')->add('page_' . $i, new EvaluationPage($page));
             }
         }

    }    

}

EvaluationPage (The inner form):

namespace Company\PerformanceBundle\Form\Fields;

use Company\PerformanceBundle\Entity\Noncommitable\EvaluationLockerPage;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;

class EvaluationPage extends AbstractType {

    private $page;

    public function __construct( EvaluationLockerPage $page)
    {
        $this->page = $page;
    }

    public function getName() {

        return 'evaluationPage';

    }

    public function buildForm(FormBuilderInterface $builder, array $options) 
    {

        $builder->add('bullets', 'collection');

        $i =0;
        foreach ($this->page as $bullet => $value)
        {
            if ($bullet)
            {   
                $builder->get('bullets') -> add('bullet_'.$i, 'text', array(
                    'label' => $bullet,
                    'data'  => $value,
                    'required' => true,
                    'trim' => true,
                    ));
            }

            $i++;    
        }
    }
}

EvaluationLocker and EvaluationLockerPage are simply objects with the ArrayAccess and Iterator interfaces, and a few simple functions such as getPageCount and similar ops.

Think of EvaluationLocker as an array of EvaluationLockerPage arrays. Each EvaluationLockerPage entry is a key/value pair where the key is the bullet point text, and the value is the score it's been assigned.

So, when the page renders, the only bullet point that displays is 'Has a broad and deep understanding of the issues that affect the organization, industry and the business environment.' along with its text box. The rest of the form displays fine, but only that one bullet point is present.

I'm still a little new to Symfony, so if I've done something in a weird way or done something dumb, that's probably why.

What am I missing?

  • 写回答

1条回答 默认 最新

  • dsxsou8465 2014-07-01 19:57
    关注

    The Answer

    The issue was twofold, caused by the way collection field types were being handled, as well as a mistake in my event subscriber.

    The symfony engine does not render collection entries unless they have an actual value assigned to them. Since these text boxes were empty, symfony was ignoring them, expecting the boxes to be added to the form via javascript and prototypes.

    That caused the form lines not to display. However, remember that ONE line was displaying.

    That was caused by my event subscriber. It was a relic of a way I had previously tried to get this working, and forgot to remove it. It was looping over the locker entries and reassigning a "pages_" text field with the information for each iteration because I forgot to append an iterator to the end of the field. ( pages_1, pages_2, etc) Adding the iterator to the field and eliminating the foreach loop in the EvaluationType file got all the fields successfully rendering.

    I added a data-grouping attribute to the field assignment in the subscriber to set which page the question should appear on, rendered the bullet points in a hidden div, then used javascript to move the dom nodes into their proper place in the page divs by looping over

    document.getElementById('page' + pageNum + '_div').appendChild(
        document.querySelectorAll('[data-grouping="page' + pageNum + '"]').parentNode);
    

    where pageNum is the page number I'm currently building.

    A bit of a clunky work-around, but it works, and I still have all my hair.

    The updated event subscriber:

    <?php
    
    namespace Company\PerformanceBundle\Form\EventListener;
    
    use Company\PerformanceBundle\Entity\Noncommitable\EvaluationLocker;
    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    use Symfony\Component\Form\FormEvent;
    use Symfony\Component\Form\FormEvents;
    
    class EvaluationPageSubscriber implements EventSubscriberInterface{
    
        private $EvaluationLocker;
    
        public function __construct(EvaluationLocker $locker)
        {
            $this->EvaluationLocker = $locker;
        }
    
    
        public static function getSubscribedEvents() {
    
            return array(FormEvents::PRE_SET_DATA => 'preSetData');
    
        }
    
        public function preSetData(FormEvent $event)
        {
            $form = $event->getForm();
    
            list($i,$j) = array(0,0);
    
            foreach ( $this->EvaluationLocker as $contents )
            {
                $i++;
    
                foreach ($contents as $bullet => $value)
                {
                    $j++;
                    $form->add('page_' . $i . '-bullet_' . $j, 'text', array(
                        'label' => $bullet,
                        'trim' => true,
                        'data' => $value,
                        'attr' => array(
                            'data-grouping' => 'page' . $i,
                            )
                        ));
                }
    
            }
    
        }
    
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 训练的多模态特征融合模型准确度很低怎么办
  • ¥15 kylin启动报错log4j类冲突
  • ¥15 超声波模块测距控制点灯,灯的闪烁很不稳定,经过调试发现测的距离偏大
  • ¥15 import arcpy出现importing _arcgisscripting 找不到相关程序
  • ¥15 onvif+openssl,vs2022编译openssl64
  • ¥15 iOS 自定义输入法-第三方输入法
  • ¥15 很想要一个很好的答案或提示
  • ¥15 扫描项目中发现AndroidOS.Agent、Android/SmsThief.LI!tr
  • ¥15 怀疑手机被监控,请问怎么解决和防止
  • ¥15 Qt下使用tcp获取数据的详细操作