@@ -28,13 +28,13 @@ Creating the Transformer
2828First, create an ``IssueToNumberTransformer `` class - this class will be responsible
2929for converting to and from the issue number and the ``Issue `` object::
3030
31- // src/Acme/TaskBundle /Form/DataTransformer/IssueToNumberTransformer.php
32- namespace Acme\TaskBundle \Form\DataTransformer;
31+ // src/AppBundle /Form/DataTransformer/IssueToNumberTransformer.php
32+ namespace AppBundle \Form\DataTransformer;
3333
34+ use AppBundle\Entity\Issue;
35+ use Doctrine\Common\Persistence\ObjectManager;
3436 use Symfony\Component\Form\DataTransformerInterface;
3537 use Symfony\Component\Form\Exception\TransformationFailedException;
36- use Doctrine\Common\Persistence\ObjectManager;
37- use Acme\TaskBundle\Entity\Issue;
3838
3939 class IssueToNumberTransformer implements DataTransformerInterface
4040 {
@@ -60,7 +60,7 @@ for converting to and from the issue number and the ``Issue`` object::
6060 public function transform($issue)
6161 {
6262 if (null === $issue) {
63- return "" ;
63+ return '' ;
6464 }
6565
6666 return $issue->getNumber();
@@ -70,9 +70,7 @@ for converting to and from the issue number and the ``Issue`` object::
7070 * Transforms a string (number) to an object (issue).
7171 *
7272 * @param string $number
73- *
7473 * @return Issue|null
75- *
7674 * @throws TransformationFailedException if object (issue) is not found.
7775 */
7876 public function reverseTransform($number)
@@ -82,7 +80,7 @@ for converting to and from the issue number and the ``Issue`` object::
8280 }
8381
8482 $issue = $this->om
85- ->getRepository('AcmeTaskBundle :Issue')
83+ ->getRepository('AppBundle :Issue')
8684 ->findOneBy(array('number' => $number))
8785 ;
8886
@@ -111,29 +109,116 @@ for converting to and from the issue number and the ``Issue`` object::
111109Using the Transformer
112110---------------------
113111
114- Now that you have the transformer built, you just need to add it to your
115- issue field in some form.
112+ As seen above our transformer requires an instance of an object manager. While for most
113+ use-cases it is sufficient to use the default entity manager, you will sometimes need
114+ to explicitly choose the one to use. To achieve this, you can use a factory::
115+
116+ // src/AppBundle/Form/DataTransformer/IssueToNumberTransformerFactory.php
117+ namespace AppBundle\Form\DataTransformer;
118+
119+ use Doctrine\Common\Persistence\ManagerRegistry;
120+
121+ class IssueToNumberTransformerFactory
122+ {
123+ /**
124+ * @var ManagerRegistry
125+ */
126+ private $registry;
127+
128+ public function __construct(ManagerRegistry $registry)
129+ {
130+ $this->registry = $registry;
131+ }
132+
133+ public function create($om)
134+ {
135+ return new IssueToNumberTransformer($this->registry->getManager($om));
136+ }
137+ }
138+
139+ .. configuration-block ::
140+
141+ .. code-block :: yaml
142+
143+ services :
144+ app.issue_transformer_factory :
145+ class : AppBundle\Form\DataTransformer\IssueToNumberTransformerFactory
146+ arguments : ["@doctrine"]
147+ public : false
148+
149+ app.type.task :
150+ class : AppBundle\Form\TaskType
151+ arguments : ["@app.issue_transformer_factory"]
152+ tag :
153+ - { name: form.type, alias: app_task }
154+
155+ .. code-block :: xml
156+
157+ <service id =" app.issue_transformer_factory"
158+ class =" AppBundle\Form\DataTransformer\IssueToNumberTransformerFactory" public =" false" >
159+ <argument type =" service" id =" doctrine" />
160+ </service >
161+
162+ <service id =" app.type.task"
163+ class =" AppBundle\Form\TaskType" >
164+ <argument type =" service" id =" app.issue_transformer_factory" />
165+ <tag name =" form.type" alias =" app_task" />
166+ </service >
167+
168+ .. code-block :: php
169+
170+ use Symfony\Component\DependencyInjection\Definition;
171+ use Symfony\Component\DependencyInjection\Reference;
172+ // ...
173+
174+ $container
175+ ->setDefinition('app.issue_transformer_factory', new Definition(
176+ 'AppBundle\Form\DataTransformer\IssueToNumberTransformerFactory'
177+ ), array(
178+ new Reference('doctrine'),
179+ ))
180+ ->setPublic(false)
181+ ;
182+
183+ $container
184+ ->setDefinition('app.type.task', new Definition(
185+ 'AppBundle\Form\TaskType'
186+ ), array(
187+ new Reference('app.issue_transformer_factory'),
188+ ))
189+ ->addTag('form.type', array('alias' => 'app_task'))
190+ ;
191+
192+ Now that you have the capability to build the transformer with the desired object manager, you
193+ just need to create it from your issue field in some form.
116194
117195You can also use transformers without creating a new custom form type
118196by calling ``addModelTransformer `` (or ``addViewTransformer `` - see
119197`Model and View Transformers `_) on any field builder::
120198
199+ // src/AppBundle/Form/TaskType.php
200+ namespace AppBundle\Form;
201+
202+ use AppBundle\Form\DataTransformer\IssueToNumberTransformerFactory;
121203 use Symfony\Component\Form\FormBuilderInterface;
122- use Acme\TaskBundle\Form\DataTransformer\IssueToNumberTransformer ;
204+ use Symfony\Component\OptionsResolver\OptionsResolverInterface ;
123205
124206 class TaskType extends AbstractType
125207 {
126- public function buildForm(FormBuilderInterface $builder, array $options)
208+ /**
209+ * @var IssueToNumberTransformerFactory
210+ */
211+ private $factory;
212+
213+ public function __construct(IssueToNumberTransformerFactory $factory)
127214 {
128- // ...
215+ $this->factory = $factory;
216+ }
129217
130- // the "em" is an option that you pass when creating your form. Check out
131- // the 3rd argument to createForm in the next code block to see how this
132- // is passed to the form (also see setDefaultOptions).
133- $entityManager = $options['em'];
134- $transformer = new IssueToNumberTransformer($entityManager);
218+ public function buildForm(FormBuilderInterface $builder, array $options)
219+ {
220+ $transformer = $this->factory->create($options['om']);
135221
136- // add a normal text field, but add your transformer to it
137222 $builder->add(
138223 $builder->create('issue', 'text')
139224 ->addModelTransformer($transformer)
@@ -144,27 +229,19 @@ by calling ``addModelTransformer`` (or ``addViewTransformer`` - see
144229 {
145230 $resolver
146231 ->setDefaults(array(
147- 'data_class' => 'Acme\TaskBundle\Entity\Task',
148- ))
149- ->setRequired(array(
150- 'em',
232+ 'data_class' => 'AppBundle\Entity\Task',
151233 ))
152- ->setAllowedTypes(array(
153- 'em' => 'Doctrine\Common\Persistence\ObjectManager',
154- ));
155-
156- // ...
234+ ->setRequired(array('om'))
235+ ;
157236 }
158-
159- // ...
160237 }
161238
162239This example requires that you pass in the entity manager as an option
163240when creating your form. Later, you'll learn how you could create a custom
164241``issue `` field type to avoid needing to do this in your controller::
165242
166- $taskForm = $this->createForm(new TaskType() , $task, array(
167- 'em ' => $this->getDoctrine()->getManager() ,
243+ $taskForm = $this->createForm('app_task' , $task, array(
244+ 'om ' => 'default' ,
168245 ));
169246
170247Cool, you're done! Your user will be able to enter an issue number into the
@@ -254,40 +331,34 @@ a form that uses the transformer.
254331Because of these, you may choose to :doc: `create a custom field type </cookbook/form/create_custom_field_type >`.
255332First, create the custom field type class::
256333
257- // src/Acme/TaskBundle/ Form/Type /IssueSelectorType.php
258- namespace Acme\TaskBundle\ Form\Type ;
334+ // src/AppBundle/ Form/IssueSelectorType.php
335+ namespace AppBundle\ Form;
259336
337+ use AppBundle\Form\DataTransformer\IssueToNumberTransformerFactory;
260338 use Symfony\Component\Form\AbstractType;
261339 use Symfony\Component\Form\FormBuilderInterface;
262- use Acme\TaskBundle\Form\DataTransformer\IssueToNumberTransformer;
263- use Doctrine\Common\Persistence\ObjectManager;
264340 use Symfony\Component\OptionsResolver\OptionsResolverInterface;
265341
266342 class IssueSelectorType extends AbstractType
267343 {
268- /**
269- * @var ObjectManager
270- */
271- private $om;
272-
273- /**
274- * @param ObjectManager $om
275- */
276- public function __construct(ObjectManager $om)
344+ private $factory;
345+
346+ public function __construct(IssueToNumberTransformerFactory $factory)
277347 {
278- $this->om = $om ;
348+ $this->factory = $factory ;
279349 }
280350
281351 public function buildForm(FormBuilderInterface $builder, array $options)
282352 {
283- $transformer = new IssueToNumberTransformer( $this->om );
353+ $transformer = $this->factory->create($options['om'] );
284354 $builder->addModelTransformer($transformer);
285355 }
286356
287357 public function setDefaultOptions(OptionsResolverInterface $resolver)
288358 {
289359 $resolver->setDefaults(array(
290360 'invalid_message' => 'The selected issue does not exist',
361+ 'om' => 'default'
291362 ));
292363 }
293364
@@ -310,24 +381,49 @@ it's recognized as a custom field type:
310381 .. code-block :: yaml
311382
312383 services :
313- acme_demo.type.issue_selector :
314- class : Acme\TaskBundle\Form\Type\IssueSelectorType
315- arguments : ["@doctrine.orm.entity_manager"]
384+ app.issue_transformer_factory :
385+ class : AppBundle\Form\DataTransformer\IssueToNumberTransformerFactory
386+ arguments : ["@doctrine"]
387+ public : false
388+ app.type.issue_selector :
389+ class : AppBundle\Form\IssueSelectorType
390+ arguments : ["@app.issue_transformer_factory"]
316391 tags :
317392 - { name: form.type, alias: issue_selector }
318393
319394 .. code-block :: xml
320395
321- <service id =" acme_demo.type.issue_selector" class =" Acme\TaskBundle\Form\Type\IssueSelectorType" >
322- <argument type =" service" id =" doctrine.orm.entity_manager" />
396+ <service id =" app.issue_transformer_factory"
397+ class =" AppBundle\Form\DataTransformer\IssueToNumberTransformerFactory" public =" false" >
398+ <argument type =" service" id =" doctrine" />
399+ </service >
400+
401+ <service id =" app.type.issue_selector"
402+ class =" AppBundle\Form\IssueSelectorType" >
403+ <argument type =" service" id =" app.issue_transformer_factory" />
323404 <tag name =" form.type" alias =" issue_selector" />
324405 </service >
325406
326407 .. code-block :: php
327408
409+ use Symfony\Component\DependencyInjection\Definition;
410+ use Symfony\Component\DependencyInjection\Reference;
411+ // ...
412+
413+ $container
414+ ->setDefinition('app.issue_transformer_factory', new Definition(
415+ 'AppBundle\Form\DataTransformer\IssueToNumberTransformerFactory'
416+ ), array(
417+ new Reference('doctrine'),
418+ ))
419+ ->setPublic(false)
420+ ;
421+
328422 $container
329- ->setDefinition('acme_demo.type.issue_selector', array(
330- new Reference('doctrine.orm.entity_manager'),
423+ ->setDefinition('app.type.issue_selector', new Definition(
424+ 'AppBundle\Form\IssueSelectorType'
425+ ), array(
426+ new Reference('app.issue_transformer_factory'),
331427 ))
332428 ->addTag('form.type', array(
333429 'alias' => 'issue_selector',
@@ -337,8 +433,8 @@ it's recognized as a custom field type:
337433 Now, whenever you need to use your special ``issue_selector `` field type,
338434it's quite easy::
339435
340- // src/Acme/TaskBundle/ Form/Type /TaskType.php
341- namespace Acme\TaskBundle\ Form\Type ;
436+ // src/AppBundle/ Form/TaskType.php
437+ namespace AppBundle\ Form;
342438
343439 use Symfony\Component\Form\AbstractType;
344440 use Symfony\Component\Form\FormBuilderInterface;
0 commit comments