2014-01-31 2 views
5

Что мне нужно

Я должен создать модуль, который позволяет вводить очень простые платные заглушки. Классы, представляющие это, являются PayStub и Detail, которые являются POPO и постоянными. Кроме того, Detail s должно быть сбалансировано относительно Fee s, что в свою очередь относится к классу, принадлежащему классу Tariff. Таким образом, у Detail есть информация о Fee, которые оплачиваются.Symfony2 - Передача данных между событиями

Чтобы сделать вещи немного более сложными, Fee пользователь должен платить напрямую зависит от того, что EducationLevelEnrolment имеет, который принадлежит к Student, который также принадлежит к Person.

То, что я

PayStub имеет:

  • расчетном листке Номер
  • Оплата Дата
  • Способ оплаты
  • Наблюдения

И в Detail час как:

  • Плата
  • Проверить, если
  • уплаченная сумма
  • процент Стипендия

Fee имеет:

  • Номер платы
  • Pri се

Который принадлежит к 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; 
} 

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

Что касается поля выбора плата, я не использовал тип объекта, поскольку он будет включать запрос 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); 
       } 
      )); 
     } 
    }); 

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

Я правильно подошел к этой проблеме? Есть ли более чистый способ сделать это, или я могу просто решить это право таким образом? Спасибо заранее.

+8

Я чувствую, что ваш вопрос слишком сложный. Что именно ты пытаешься сделать? –

+4

Посмотрите, где ваша проблема, а затем просто разместите соответствующие строки. Мы не здесь, чтобы найти вашу проблему. –

+0

Итак, я понимаю, что проблема заключается в вычислении одного из полей формы (платы) на основе значений других полей формы (тип и тариф).Это в основном означает, что это вычисленное поле напрямую не контролируется пользователем, поэтому не должно быть поле формы или части вашего типа PayStubType/DetailType. – nikita2206

ответ

0

Я хотел бы предложить пару соображений:
Первый о коде, я думаю, что логика внутри вашей формы начинает немного сложнее, лучше избегать слишком много строк кода в одном классе, поэтому Я хотел бы подумать о рефакторе в соответствии с SRP (принцип единой ответственности).

Во-вторых, я не знаю, правильно ли ваш подход.
Я мог бы предположить, что это возможно, и, возможно, использование PRE_SUBMIT может облегчить все, но я хотел бы обратить больше внимания на вашу архитектуру.

Что я имею в виду, нам нужно больше узнать о проблеме сбора.
Если вы считаете, что, чтобы получить значение будет потреблять время, а также может замедлить процесс представить в виде (который должен быть как можно быстрее), Может быть, стоит подумать о некоторых альтернатив:

  • Разделить форму в 2 подформы (пример 2 страницы, шаг1 и шаг2);
  • реструктурирует данные модели, создавая, например, другую таблицу, или лучше вид или Api, которые могли бы быстро получить значение;
  • Рассчитайте значение позже с помощью задания cron.

Надеюсь, что эта точка зрения может быть полезна.

Смежные вопросы