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 请问如何在openpcdet上对KITTI数据集的测试集进行结果评估?
  • ¥15 powerbuilder中的datawindow数据整合到新的DataWindow
  • ¥20 有人知道这种图怎么画吗?
  • ¥15 pyqt6如何引用qrc文件加载里面的的资源
  • ¥15 安卓JNI项目使用lua上的问题
  • ¥20 RL+GNN解决人员排班问题时梯度消失
  • ¥60 要数控稳压电源测试数据
  • ¥15 能帮我写下这个编程吗
  • ¥15 ikuai客户端l2tp协议链接报终止15信号和无法将p.p.p6转换为我的l2tp线路
  • ¥15 phython读取excel表格报错 ^7个 SyntaxError: invalid syntax 语句报错