2012-08-15 4 views
9

私はPropelBundleでSymfony 2.1フォームを使用しています。オブジェクトのドロップダウンリストを持つフォームをリファクタリングして、jqueryのオートコンプリートフィールド(AJAXで作業する)を代わりに使用しようとしています。ドロップダウンリストについては、私は自分のフォームタイプで(ドロップダウンのために完璧に働いていた)次のコードを使用していました:Propelを使って、コレクションのためのSymfony2フォームにオートコンプリートフィールドを追加するには?

$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, 
)); 

少しコンテキストを与えるために、我々は新しい「リーダーを作成しているとしましょう利用可能な「書籍」オブジェクトのリストからReaderのお気に入りの書籍を選択したいと考えています。コレクションタイプは、新しい「リーダー」フォームで多くの「お気に入りの書籍」を選択できるように使用されます。今、私はオートコンプリートを使用するために上記を変更したいと思います。そのために、the answer to this Questionに示されているブックIDを渡すオートコンプリート機能に使用できるData Transformer to be able to get a Book object from a simple text fieldを実装しようとしました。しかし、私はData Transformerをコレクション型とPropelクラスで動作させる方法を理解することができませんでした。私はsymfonyのクックブックに示されているようにBookToIdTransformerクラスを作成し、「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)。誰もそれについて行く方法を知っていますか?あるいは、Propelを使ってSymfonyでオートコンプリートを実装し、複数のオブジェクト(例えば、書籍のコレクション)を選択できる他の方法があるかどうか教えてください。

答えて

14

私が最終的に行った解決策は、以前の回答と少し異なります。私はLoopj Tokeninput jQuery pluginを使用して終了して以来、私の "ReaderType"フォームに "collection"フィールドタイプの代わりに "text"フィールドタイプを使用してしまいました。これは、複数のオブジェクト(例えば "お気に入りブック")を選択して、フォーム内のオブジェクト(例えば "Reader"オブジェクト)。それを考慮して、渡されたオブジェクトのID(テキストフィールドのカンマ区切りリスト)をPropel Object Collectionに変換するための "Data Transformer"を作成しました。このコードは、サンプルajaxオブジェクトコントローラを含め、以下のように共有されています。

次のように「ReaderType」フォームの重要な部分が見えます:

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

「データトランス」ファイルは次のようになりますのJSONコレクションを返し

// 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のコントローラTokeninputオートコンプリート関数の "books"は、次のとおりです。

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 "routing.yml"ファイル内のルータ:

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

徹底的な説明をありがとう。 JSONレスポンスを返さなければならないコントローラのアクションがたくさんある場合は、FOSRestBundle – Narretz

+0

のビュー/フォームのスニペットを追加できますか? – timaschew

+0

@timaschew私がよく覚えていれば(私はそれを必要としなくなりました)、ビュー内のコードはsymfonyフォームに使用されている標準的なものです。フィールドは通常のテキスト入力です。オートコンプリート機能は、入力のIDを使用してjavascriptを使用してTokeninputプラグインによってその入力に追加されます:$( "#my-text-input")tokenInput( "/ url/to/your/script /"); – RayOnAir

関連する問題