我有一个实体合同,它与一个,一个实体客户端相关联。要选择哪个客户端链接到正在创建的合同,我将通过AJAX搜索呈现select2,将一些客户端加载到组件上。表示客户端的元素必须是ChoiceType。
在我的后端,我需要:
ClientesBundle/
├── Controller
│ └── DefaultController.php
├── DataTransformer
│ └── ClienteTransformer.php
├── Entity
│ ├── Cliente.php
│ └── Contrato.php
├── Form
│ └── ClienteType.php
├── Repository
│ ├── ClienteRepository.php
│ └── ContratoRepository.php
└── Resources
├── config
│ ├── routing.yml
│ └── services.yml
└── views
└── ...
在这个结构中,我会在ClienteTransformer.php
中使用ClienteType.php
并直接在DefaultController中调用
$form = $this->createFormBuilder(Cliente::class)->add('titular', ClienteType::class);
$form->getForm();
->addModelTransformer($clientTransformer);
导致错误。由此得出,我们无法定义CallbackTransformer
内联,或其他不涉及this post中公开的解决方案的选项。 Symfony文档中给出的示例对于我在渲染之前如何创建,检索或修改表单并不清楚。在"How to Create a Custom Form Field Type"中,我可以理解所有内容,直到使用字段类型,这是在另一个自定义字段中完成的:我应该如何直接在控制器中使用自定义字段类型?就像我一样已定义的类型。以下代码有效。但是,如果我将TextType更改为ClienteType(这是我的自定义字段类型),我会收到错误 - Expected argument of type "object, array or empty", "string" given
- 。 DefaultController.php
public function buildFormContrato($entity = null)
{
$logger = $this->get('logger');
$form = $this->createFormBuilder($entity ?? new Contrato());
$form->add('titular', TextType::class);
return $form;
}
<?php
namespace ClientesBundle\Form;
use ...
class ClienteType extends AbstractType
{
protected $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$clienteTransformer = new ClienteTransformer($this->em);
$builder
->add('titular', ChoiceType::class,
['placeholder' => 'Selecciona un cliente']
);
$builder->get('titular')
->addModelTransformer($clienteTransformer);
$builder->addEventListener(FormEvents::PRE_SUBMIT,
function (FormEvent $event)
{
$data = $event->getData();
$form = $event->getForm();
$form->add('titular', ClienteType::class,
['choices' => [
$this->em->getRepository(Cliente::class)
->find($data['titular'])
]
]
);
});
return $builder;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Cliente::class,
'compound' => true // Set to true tipped by error 'You cannot add children to a simple form. Maybe you should set the option "compound" to true?'
));
}
public function getParent()
{
return ChoiceType::class;
}
}
<?php
namespace ClientesBundle\DataTransformer;
use ...
class ClienteTransformer implements DataTransformerInterface
{
private $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
/**
* Transforms an object (cliente) to a string (string).
*
* @param Cliente|null $cliente
* @return string
*/
public function transform($cliente)
{
if (null === $cliente) {
return '';
}
return $cliente->getDni();
}
/**
* Transforms a string (dni) to an object (cliente).
*
* @param string $issueNumber
* @return Cliente|null
* @throws TransformationFailedException if object (cliente) is not found.
*/
public function reverseTransform($clienteDni)
{
// no issue number? It's optional, so that's ok
if (!$clienteDni) {
return null;
}
$cliente = $this->em
->getRepository(Cliente::class)
// query for the issue with this id
->find($clienteDni)
;
if (null === $cliente) {
// causes a validation error
// this message is not shown to the user
// see the invalid_message option
throw new TransformationFailedException(sprintf(
'El cliente con dni "%s" no existe!',
$clienteDni
));
}
return $cliente;
}
}
services:
clientes.form.type:
class: ClientesBundle\Form\ClienteType
tags:
- { name: form.type, alias: clienteType }
arguments: [ '@doctrine.orm.entity_manager', '@form.factory']
<?php
namespace ClientesBundle\Controller;
use ...
class DefaultController extends Controller
{
...
public function buildFormContrato($entity = null)
{
$logger = $this->get('logger');
$form = $this->createFormBuilder($entity ?? new Contrato());
$form->add('titular', ClienteType::class);
return $form;
}
...
public function nuevoContratoAction(Request $request)
{
$logger = $this->get('logger');
$form = $this->buildFormContrato()
->add('finalizar', SubmitType::class) //THIS IS THE LINE I GET THE ERROR ON.
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{ ... }
return $this->render(
'ClientesBundle:Default:nuevoContrato.html.twig',
['form' => $form->createView()]);
}
}
我主要使用以下文件解决了这个问题:
答案 0 :(得分:0)
看一下示例:类IssueSelectorType扩展AbstractType 在https://symfony.com/doc/current/form/data_transformers.html
class TitularType extends AbstractType
{
private $transformer;
public function __construct(ClienteTransformer $transformer)
{
$this->transformer = $transformer;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addModelTransformer($this->transformer);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'invalid_message' => 'The selected NIF does not exist',
));
}
public function getParent()
{
return TextType::class;
}
}
将从您的服务定义中调用该构造:
services:
clientes.form.titular:
class: ClientesBundle\Form\TitularType
arguments: [ @clientes.transformer.client_nif ]
tags:
- { name: form.type, alias: titular }