找到了答案。簡而言之,您可以查看This Matt Daum post。
下面是完整的示例,不僅介紹如何創建自定義表單驗證程序,還介紹如何注入服務和額外數據以形成表單(因爲這是我的情況)。
如果你想簡單receipe,直接去底部。
讓我們DTO:
class MyFormDTO
{
/** @var string */
private $name;
/** @var string */
private $surname;
/** @var string */
private $phone;
/** getters and setters ommited */
}
現在,在窗體中定義的依賴。前兩個是服務,最後一個(Calendar
)是控制器所需的一些額外數據。
class MyForm extends AbstractType
{
(fields hidden)
/**
* @param Sender $sender
* @param TranslatorInterface $translator
* @param Calendar $calendar
*/
public function __construct(Sender $sender, TranslatorInterface $translator, Calendar $calendar)
{
$this->translator = $translator;
$this->sender = $sender;
$this->calendar = $calendar;
}
}
現在有兩種方法 - 如果您只需要表單中的服務,則可以將表單定義爲服務。如果你和我一樣,都需要額外的數據,你需要編寫形式工廠服務:
class MyFormFactory
{
(fields hidden)
/**
* @param Sender $sender
* @param TranslatorInterface $translator
*/
public function __construct(Sender $sender, TranslatorInterface $translator)
{
$this->sender = $sender;
$this->translator = $translator;
}
/**
* @param Calendar $calendar
*
* @return MyForm
*/
public function getMyForm(Calendar $calendar)
{
return new MyForm($this->sender, $this->translator, $calendar);
}
}
讓我們定義這家工廠與正確的依賴服務:
mybundle.form.myform_factory:
class: MyBundle\Service\FormFactory\MyFormFactory
arguments: [ @text_message.sender, @translator ]
如何獲得在控制器形式?易爲:
class MyController extends Controller
{
/**
* @ParamConverter("calendar", options={"mapping"={"calendarId":"id"}})
*
* @param Request $request
* @param Calendar $calendar
*
* @return Response
* @throws Exception
*/
public function myAction(Request $request, Calendar $calendar)
{
$formDTO = new MyFormDto();
$myForm = $this->get('mybundle.form.myform_factory')->getMyForm($calendar);
$form = $this->createForm($myForm, $formDTO);
(handling post hidden)
}
}
而現在最重要的部分 - 我們必須適當注入到我們的形式服務。如何使用它們並驗證選定的數據?像這樣:
class MyForm extends AbstractType
{
(fields hidden, constructor shown in previous example)
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
/** @var MyFormDTO $myDTO */
$myDTO = $options['data'];
(build form as usual, using services and data from $options and $this->calendar injected by controller and factory)
}
/**
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
parent::setDefaultOptions($resolver);
$resolver->setDefaults([
'csrf_protection' => true,
'constraints' => [
new Callback(function (MyFormDTO $data, ExecutionContextInterface $context) //notice that we have access to fully propageted DTO here
{
//use injected service
$isValid = $this->sender->validateSomething($data->getSurname(), $data->getPhone());
if (false === $isValid)
{
$context
->buildViolation($this->translator->trans('wrong_surname_phone_pair'))
->addViolation();
}
return $isValid;
})
],
]);
}
}
而只是一點提示。如果你的'Callback'處理重邏輯,你可以將它移出來分開'Constraint'。 [以下是如何操作](http://symfony.com/doc/current/cookbook/validation/custom_constraint.html) – ex3v