2015-01-12 57 views
5

我有一個自定義的FormType,當父窗體仍然存在時,它需要將其自身添加到父實體。Symfony2(> = 2.3):如何從小孩那裏收聽父母表單事件?

在Symfony的< 2.3,這可以通過執行以下操作來完成:

class FooType extends AbstractType 
{ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     parent::buildForm($builder, $options); 
     ... 
     $builder->getParent()->addEventSubscriber(new FooSubscriber) 
    } 
} 

class FooSubscriber implements EventSubscriberInterface 
{ 
    static function getSubscribedEvents() 
    { 
     return array(
      FormEvents::POST_SUBMIT => 'postSubmit' 
     ); 
    } 
} 

但升級至2.6的Symfony我發現$builder->getParent()已被刪除後。但現在我不能聽到提交的父母。

因此,我將偵聽器添加到我的構建器,並在訂閱服務器中引用了父項。但是,這並沒有真正的工作,因爲我做了檢查父窗體上是有效的 - 它不是,因爲它尚未提交:

function postSubmit(FormEvent $e) 
{ 
    if ($e->getForm()->getParent()->getRoot()->isValid()) { 
     //this gives 'false' 

這種錯誤是由下一段代碼引起的:

// Symfony\Component\Form\Form.php @ line 744 
public function isValid() 
{ 
    if (!$this->submitted) { 
     return false; 
    } 

而且因爲父窗體首先遍歷所有孩子的,並陳述說,對自己設定$this->submitted = true之前......我不知道,如果父母是有效的。


TL; DR

我怎麼能一個事件監聽添加到我的父窗體,而無需調整我的父窗體?我希望我的FooType是我可以添加到所有表單的東西,而不必知道/記住爲特定的FooType執行一些邏輯。

+0

正如你所說,getParent在2.3中被刪除。你能更詳細地描述用例嗎?可能是更好的解決方案。 – Cerad

+1

這是一個可以添加到另一個實體的實體。在這種情況下,它是一個MenuItem,它在持續頁面時創建。 這個MenuItem是基於頁面的標題,所以它需要它的父母輸入。但我不希望頁面'知道'有一個MenuItem依賴於他。所以之前,我只能將一個MenuItem添加到PageAdmin中,就是這樣。 現在,我_要在管理員中添加訂閱者 - 這感覺**髒** – Oskar

+0

有同樣的問題,我想知道如果根表單是有效的,我找不到方法在2。6 :( – Tiois

回答

0

我需要相同的功能,因爲我有一個自定義表單字段,所有映射字段已更新後需要父實體。不幸的是,子表單的POST_SUBMIT在父級的SUBMIT運行之前被調用。

我最終將eventDispatcher傳遞給了孩子,並將偵聽器綁定在那裏。我需要兩個聽衆來完成這項工作:一個獲取處理過的值,一個更新主要實體。通過引用將$ generatedPassword傳遞給閉包允許您將子事件的數據共享給父項。

家長:: buildForm

$builder->add('generate_password', GeneratePasswordType::class, [ 
    'event_dispatcher' => $builder->getEventDispatcher(), 
]); 

兒童:: buildForm

//first listed to submit even to get current field value 
$generateNewPassword = false; 
$builder->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) use (&generateNewPassword) { 
    $generateNewPassword = null !== $event->getData(); 
}); 

//then run updater after parent entity has been updated 
$parentDispatcher = $options['event_dispatcher']; 
$parentDispatcher->addListener(FormEvents::POST_SUBMIT, function (FormEvent $event) use (&$generateNewPassword) { 
    $user = $event->getData(); 
    if(true === $generateNewPassword){ 
     //update password & email user new credentials 
    } 
} 

(自定義字段被標記爲 '生成對保存新密碼' 爲用戶管理模塊的複選框。它的電子郵件用戶生成的密碼,這就是爲什麼我需要主要實體的最新電子郵件地址)

+0

這是一個想法,但它仍然需要修改父窗體,並且像OP一樣,我無法修改它。 –