Symfony2 - 在事件之间传递数据

Car*_*ara 5 php oop symfony-forms symfony symfony-2.3

我需要的

我必须构建一个允许输入非常简单的工资单的模块.表示这个的类是PayStubDetail,它们是POPO和持久性的.而且,Details必须与s进行平衡,Fees又是属于Tariff类的类.因此,Detail有关于该Fee付款的信息.

为了使事情稍微复杂一点,Fee用户必须支付的费用直接取决于EducationLevelEnrolment拥有的,属于a的Student,也属于a Person.

是)我有的

PayStub有:

  • 支付存根号码
  • 付款日期
  • 付款方法
  • 意见

并且Detail:

  • 费用
  • 检查,如果有的话
  • 支付的金额
  • 奖学金百分比

Fee有:

  • 费用数量
  • 价钱

属于一个Tariff类:

  • 总金额
  • 教育程度

问题

当我构建表单时,整个问题就出现了.

PayStubType:

class PayStubType extends AbstractType
{
    //I need to pass the years and the DAOs because I need to use them later
    public function __construct(School $c, DAOPerson $dao, $years = array(), DAOFee $dc)
    {
        $this->c = $c;
        $this->dao = $dao;
        $this->years = $years;
        $this->dc = $dc;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $sch = $this->c;
        $std = $this->dao->getEnroledStudents($sch)[0];
        $builder->add('student', 'entity', array(
                    'label' => 'Student',
                    'class' => 'System\SchoolsBundle\Person\Person',
                    'mapped' => false,
                    'query_builder' => $this->dao->getEnroledStudents($sch, true)
                ))->add('payDate', 'datetime', array(
                    'label' => 'Payment Date',
                    'widget' => 'single_text',
                    'input' => 'datetime',
                    'format' => 'dd/MM/yyyy'
                ))->add('payMethod', 'choice', array(
                    'label' => 'Payment Method',
                    'choices' => EPaymentMethod::$arrPayMethods
                ))->add('stubNumber', 'text', array(
                    'label' => 'Pay Stub No.',
                    'required' => false
                ))->add('observation', 'textarea', array(
                    'label' => 'Observations',
                    'max_length' => 1024,
                    'required' => false
                ));
        $years = $this->years;
        $dc = $this->dc;
        $builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) use ($sch, $std, $years, $dc) {
            $form = $event->getForm();
            $data = $event->getData();
            $stdRole = $std->getInfoContainer()->getRole('STUDENT');
            $form->add('details', 'collection', array(
                'type' => new DetailType($sch, $std, $years, $dc),
                'label' => false,
                'allow_add' => true,
                'by_reference' => false
            ));
        });

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

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'System\SchoolsBundle\Payments\PayStub'
        ));
    }

    private $c;
    private $dao;
    private $years;
    private $dc;
}
Run Code Online (Sandbox Code Playgroud)

DetailType:

class DetailType extends AbstractType
{
    public function __construct(School $c, Student $al, $years = array(), DAOFee $dc)
    {
        $this->c = $c;
        $this->al = $al;
        $this->years = array_reverse($years, true);
        $this->dc = $dc;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $sch = $this->c;

        $list = array(); //List of scholarship percentages
        for ($i=0; $i<=100; $i++) {
            $list[(string)($i/100)] = $i."%";
        }

        $pref = min($cole->getSchoolYear(), array_values($this->years)[0]);

        $builder->add('ct', 'choice', array(
                    'label' => false,
                    'mapped' => false,
                    'choices' => Fee::$arrFees //A list of possible fees. The only possible values are the enrolment price and one fee per school month. Read after the code for a longer explanation about how this works.
                ))->add('year', 'choice', array(
                    'mapped' => false,
                    'label' => false,
                    'choices' => $this->years, //Years that have tariffs registered
                    'preferred_choices' => array($pref) //The minimum between the current school year and the last year where tariffs were registered
                ))->add('cheque', 'entity', array(
                    'label' => false,
                    'class' => 'System\SchoolsBundle\Payments\Cheque',
                    'property' => 'numberAndBank',
                    'required' => false,
                    'empty_value' => 'Select Cheque',
                    'query_builder' => function(EntityRepository $er) use ($sch) {
                        return $er->createQueryBuilder('u')
                                ->where('u.school = ?1')
                                ->orderBy('u.number')
                                ->setParameter(1, $sch);
                    }
                ))->add('amount', 'text', array(
                    'label' => false,
                ))->add('scholarshipPerc', 'choice', array(
                    'label' => false,
                    'choices' => $list
                ));
        // From here on, it gets blurry. Read below for more.
    }

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

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'System\SchoolsBundle\Payments\Detail'
        ));
    }

    private $c;
    private $al;
    private $years;
    private $dc;
}
Run Code Online (Sandbox Code Playgroud)

关于费用选择字段,我没有使用实体类型,因为它涉及AJAX查询,其中,每次我更新学生或年份,我将不得不重新加载集合类型的原型,加载新的费用为年,并添加极其复杂的事件,我不确定这将是否正常工作.所以我决定使用通用列表并稍后进行处理.

不过,这里的事情变得复杂了.我正在玩这些事件并决定一个PRE_SUBMIT事件能够捕获年份和费用,所以我只是查询它并将其添加到对象中.但是,事件不处理映射的数据类型,所以我必须将这个新信息传递给另一个事件,我决定这是这样做的方法:

$builder->addEventListener(FormEvents::PRE_SUBMIT, function(FormEvent $event) use ($sch, $al) {
        $form = $event->getForm();
        $data = $event->getData();
        if (array_key_exists('ct', $data) == true && array_key_exists('year', $data) == true) {
            $et = $al->getEnrolmentBySchool($sch, $data['year'])->getEducationLevel();
            $year = $data['year'];
            $feeNumber = $data['ct'];
            $form->add('fee', 'entity', array(
                'label' => false,
                'class' => 'System\SchoolsBundle\Payments\Fee',
                'property' => 'feeName',
                'query_builder' => function(EntityRepository $er) use ($et, $year, $feeNumber) {
                    return $er->createQueryBuilder('u')
                            ->innerJoin('u.tariff', 'a')
                            ->innerJoin('a.edType', 'et')
                            ->where('et = ?1')
                            ->andWhere('a.year = ?2')
                            ->andWhere('u.feeNumber = ?3')
                            ->orderBy('u.feeNumber')
                            ->setParameter(1, $et)
                            ->setParameter(2, $year)
                            ->setParameter(3, $feeNumber);
                }
            ));
        }
    });
Run Code Online (Sandbox Code Playgroud)

我以为我可以稍后收到数据,手工映射,然后丢弃它(即从表单中删除它).但是,POST_SUBMIT事件未正确接收对象,无论是形式(空值)还是对象(同一问题).

我正确地解决了这个问题吗?有没有更简洁的方法来做到这一点,还是我可以这样解决这个问题?先谢谢你了.