2012-08-15 72 views
9

我用的是PropelBundle的Symfony 2.1窗體,我試圖重構一個有對象下拉列表(從中進行選擇)的表單,而不是使用jQuery自動填充字段(使用AJAX)。對於下拉列表,我在我的表單類型使用下面的代碼(這非常完美的下拉列表):如何在Symfony2表單中爲集合添加自動填充字段並使用Propel?

$builder->add('books', 'collection', array(
    'type'   => 'model', 
    'options'  => array(
     'class'  => 'MyVendor\MyBundle\Model\Book', 
     'property' => 'title', 
    ), 
    'allow_add'  => true, 
    'allow_delete' => true, 
    'by_reference' => false, 
    'required'  => false, 
)); 

而提供一點背景知識的緣故,讓我們說,我們正在創造一個新的「閱讀器「對象,並且我們希望從可用的」書籍「對象列表中選擇讀者喜愛的書籍。使用集合類型,可以在新的「閱讀器」表單中選擇許多「喜歡的書」。現在,我想改變上面的使用自動完成。爲此,我嘗試實施Data Transformer to be able to get a Book object from a simple text field,該功能可用於自動填充功能,以傳遞書籍ID,如the answer to this Question中所示。但是,我無法弄清楚如何使數據轉換器與集合類型和Propel類一起工作。我創建了一個BookToIdTransformer類如Symfony的食譜指示,試圖在「ReaderType」文件如下:

$transformer = new BookToIdTransformer(); 
$builder->add(
     $builder->create('books', 'collection', array(
      'type'   => 'text', 
      'allow_add'  => true, 
      'allow_delete' => true, 
      'by_reference' => false, 
      'required'  => false, 
     ))->addModelTransformer($transformer) 
); 

通過上述,我得到一個「調用未定義的方法:的getId」異常(顯然變壓器預期書的PropelCollection,不是一個Book對象..)。有誰知道如何去做呢?或者讓我知道是否有其他方法可以使用Propel在Symfony中實現自動完成,並允許選擇多個對象(例如書籍集合)?

回答

14

我最終的解決方案與我以前的答案略有不同。我最終在我的「ReaderType」表單中使用了「text」字段類型而不是「collection」字段類型,因爲我最終使用了允許選擇多個對象(例如「Favorite Book」)的Loopj Tokeninput jQuery plugin,對象(例如「Reader」對象)的形式。考慮到這一點,我創建了一個「數據轉換器」,用於將傳遞的對象ID(在文本字段中以逗號分隔的列表)轉換爲Propel對象集合。代碼共享如下,包括一個示例ajax對象控制器。

的「ReaderType」的重要組成部分表格如下所示:

$transformer = new BooksToIdsTransformer(); 
$builder->add(
    $builder->create('books', 'text', array(
     'required' => false, 
    ))->addModelTransformer($transformer) 
); 

「數據變壓器」文件是這樣的:

// src/MyVendor/MyBundle/Form/DataTransformer/BooksToIdsTransformer.php 
namespace MyVendor\MyBundle\Form\DataTransformer; 

use \PropelObjectCollection; 
use Symfony\Component\Form\DataTransformerInterface; 
use Symfony\Component\Form\Exception\UnexpectedTypeException; 
use MyVendor\MyBundle\Model\BookQuery; 

class BooksToIdsTransformer implements DataTransformerInterface 
{ 
    public function transform($books) 
    { 
     if (null === $books) { 
      return ""; 
     } 

     if (!$books instanceof PropelObjectCollection) { 
      throw new UnexpectedTypeException($books, '\PropelObjectCollection'); 
     } 
     $idsArray = array(); 
     foreach ($books as $book) { 
      $idsArray[] = $book->getId(); 
     } 
     $ids = implode(",", $idsArray); 
     return $ids; 
    } 

    public function reverseTransform($ids) 
    { 
     $books = new PropelObjectCollection(); 

     if ('' === $ids || null === $ids) { 
      return $books; 
     } 

     if (!is_string($ids)) { 
      throw new UnexpectedTypeException($ids, 'string'); 
     } 
     $idsArray = explode(",", $ids); 
     $idsArray = array_filter ($idsArray, 'is_numeric'); 
     foreach ($idsArray as $id) { 
      $books->append(BookQuery::create()->findOneById($id)); 
     } 
     return $books; 
    } 
} 

Ajax控制器返回的JSON集合「書」Tokeninput自動完成功能如下:

namespace MyVendor\MyBundle\Controller; 

use Symfony\Bundle\FrameworkBundle\Controller\Controller; 
use Symfony\Component\HttpFoundation\Request; 
use Symfony\Component\HttpFoundation\Response; 
use MyVendor\MyBundle\Model\BookQuery; 


class ClassAjaxController extends Controller 
{ 
    public function bookAction(Request $request) 
    { 
     $value = $request->get('q'); 

     $books = BookQuery::create()->findByName('%'.$value.'%'); 

     $json = array(); 
     foreach ($books as $book) { 
      $json[] = array(
       'id' => $book->getId(), 
       'name' => $book->getName() 
      ); 
     } 

     $response = new Response(); 
     $response->setContent(json_encode($json)); 

     return $response; 
    } 
} 

最後,th e路由器在「routing.yml」文件中:

ajax_book: 
    pattern: /ajax_book 
    defaults: { _controller: MySiteBundle:ClassAjax:book } 
+0

感謝您的詳細解釋。如果您有許多控制器操作應該返回JSON響應,我建議您使用FOSRestBundle – Narretz 2013-01-24 14:56:52

+0

您可以添加視圖/表單的片段嗎? – timaschew 2013-06-20 05:53:03

+0

@timaschew如果我記得不錯(我最終不需要它),視圖中的代碼只是用於symfony表單的標準代碼。該字段是常規文本輸入。 Tokeninput插件使用輸入的id使用javascript添加自動完成功能:$(「#my-text-input」)。tokenInput(「/ url/to/your/script /」); – RayOnAir 2013-06-21 00:06:08

相關問題