場所 (国、都市、またはスポット) を選択するためのオートコンプリート フィールドを提供するカスタム フォーム タイプを実装しています。フォーム タイプは 2 つのフィールドを作成します。1 つはオートコンプリート検索入力用のテキスト フィールドで、もう 1 つは選択された場所の選択された ID を保持するための非表示フィールドです。
テキスト フィールドに入力すると、サーバー呼び出しが行われ、jquery オートコンプリートによって結果が表示されます。場所を選択すると、選択した場所の ID が非表示フィールドに書き込まれ、場所の名前がテキスト フィールドに表示されます。サーバーでは、クライアント トランスフォーマーを使用して、隠しフィールドから渡された ID のエンティティを検索します。テキスト フィールドは無視されます。
私のモデル クラスは、NotNull 検証制約で注釈が付けられた場所エンティティを書き戻すプロパティを持つ場所フィールドを定義します。
これまでのところすべて問題なく動作していますが、場所を選択しないと、「この値は null であってはなりません」という検証メッセージが表示されます。2回表示されます。
バンドルは公開されており、私の github リポジトリで見つけることができます。関連するクラスは、LocationFieldTypeとLocationDataTransformerおよびフォームのテーマです。
次に、フォーム タイプをプロジェクトに統合する方法について説明します。コード全体を追加しました。大量に申し訳ありません;)
モデルでは、プロパティを次のように定義します。
class JourneyCreate
{
/**
* @Assert\NotNull()
* @Assert\Choice(choices = {"offer", "request"})
*/
public $type;
/**
* @Assert\NotNull()
* @Assert\Date()
*/
public $date;
/**
* @Assert\NotNull()
* @Assert\Time()
*/
public $time;
/**
* @Assert\NotNull()
*
*/
public $start;
/**
* @Assert\NotNull()
*
*/
public $destination;
public function buildJourney(User $owner)
{
switch($this->type)
{
case 'offer':
$journey = new JourneyOffer();
break;
case 'request':
$journey = new JourneyRequest();
break;
default:
throw new \InvalidArgumentException('Invalid journey type');
}
$journey->setDate($this->date);
$journey->setTime($this->time);
$journey->addStation(new JourneyStation($this->start));
$journey->addStation(new JourneyStation($this->destination));
$journey->setOwner($owner);
return $journey;
}
}
メインフォームでは、次のようにフィールドを追加します。
class JourneyCreateType extends BaseType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('type','choice', array(
'choices' => array(
'offer' => 'Driver',
'request' => 'Passanger',
),
'empty_value'=>'',
'multiple' => false,
'expanded' => true,
))
->add('date','date',array(
'widget' => 'single_text',
'format' => $this->getDateFormat(\IntlDateFormatter::TRADITIONAL),
))
->add('time','time',array(
'widget' => 'single_text',
))
->add('start','room13_geo_location')
->add('destination','room13_geo_location')
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\DemoBundle\Form\Model\JourneyCreate',
));
}
public function getName()
{
return 'journey_create';
}
}
そしてコントローラーコード:
/**
* @Route("/create/{type}", defaults={"type" = null})
* @Template()
*/
public function createAction($type=null)
{
if($type !== null && !in_array($type,array('request','offer')))
{
throw new NotFoundHttpException();
}
$journeyCreate = new JourneyCreate();
$journeyCreate->type = $type;
$form = $this->createForm(new JourneyCreateType(),$journeyCreate);
if($this->isPost())
{
$form->bind($this->getRequest());
if($form->isValid())
{
$journeyCreate = $form->getData();
$journey = $journeyCreate->buildJourney($this->getCurrentUser());
$this->persistAndFlush($journey);
return $this->redirect($this->generateUrl('acme_demo_journey_edit',array('id'=>$journey->getId())));
}
}
return array(
'form' => $form->createView(),
);
}
最後に、フォームを表示するためのテンプレート コード:
{% block page_body %}
<form class="form-horizontal" action="{{ path('acme_demo_journey_create') }}" method="post" novalidate>
{{form_widget(form)}}
<div class="form-actions">
<button class="btn btn-primary" type="submit">{{'form.submit'|trans}}</button>
<a href="{{path("acme_demo_journey_index")}}" class="btn">{{'form.cancel'|trans}}</a>
</div>
</form>
{% endblock %}
これは、2 つのフォーム フィールドを使用していることが原因である可能性がありますが、これを修正する方法がわかりません。これをよりエレガントに解決する方法についての提案は大歓迎です。