In my Symfony2 project, I need to produce a list of existing tables in a db. Since not all tables are used as entities in my project, and the list itself needs to be a simple array and not an entity, I have written an sql statement for this. This sql-statement is embedded in a function in a custom service (and has been thoroughly tested).
Now, in a form type I would like to populate a field with the result array of the function mentioned above. These become the options the user can choose from.
My question is how can I access the service in my form type?
There is a simple solution, which is pure OOP, no framework specific config. Just inject manually your service instance into your form type instance, using the constructor:
class SomeType extends AbstractType
{
private $provider;
public function __construct(DataBaseTableNameProvider $provider)
{
$this->provider = $provider;
}
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('tables', 'choices', array(
'choices' => $this->provider->getTableNames(),
));
}
}
Then, in your controller for exemple:
public function newAction()
{
$form = $this->createForm(new SomeType($this->get('table_name_provider'));
// more stuff
}
The exact same can be done using framework config, by following http://symfony.com/doc/2.0/cookbook/form/create_custom_field_type.html#creating-your-field-type-as-a-service .
The only difference is that it takes care about instanciating your type using DIC, and injecting the correct dependencies. Then, you just need to modify your controller:
public function newAction()
{
$form = $this->createForm('some_type_alias');
// more stuff
}
example with translation service access in form type:
your form type class:
class TaskType extends AbstractType {
....
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
't' => 'Symfony\Bundle\FrameworkBundle\Translation\Translator',
));
}
public function buildForm(FormBuilderInterface $builder, array $options) {
$t = $options['t'];
$t->trans('string to translate');
....
}
controller:
public function someAction() {
$form = $this->createForm(new TaskType(),
$task,
array('t' => $this->get('translator')));
Symfony Best Practices:
You can also register your form type as a service. This is only needed if your form type requires some dependencies to be injected by the container, otherwise it is unnecessary overhead and therefore not recommended to do this for all form type classes.
# src/AppBundle/Resources/config/services.yml
services:
app.form.type.gender:
class: AppBundle\Form\Type\ SomeType
arguments:
- "@app.table_name_provider"
tags:
- { name: form.type }
$form = $this->createForm(SomeType::class)
Update for Symfony 3.X, you have two options now...
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setRequired('option_key');
}
Then pass it through the controller
$form = $this->createForm(XXXType::class, $entity, array(
'option_key' => $this->get('service_you_want_to_call')
));
This option is cleaner IMO, and you don't have to send the option everywhere you call the form
class XXXType extends AbstractType
{
private $service;
public function __construct(ServiceType $service)
{
$this->service = $service;
}
And then defining the service in the config
services:
app.form.type.XXX:
class: AppBundle\Form\XXXType
arguments: ['@service_you_want_to_call']
tags:
- { name: form.type }
Every time you call the form with
$this->createForm(XXXType::class, $data, $options)
Symfony will be smart enough to know that it has to use that service arguments (it knows it because the form.type tag), so you won't need to pass any data to the constructor anymore.
Symfony docs: How to Access Services or Config from Inside a Form
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With