From 19324e838ff43d471b387a0cf84948d3b0acb01e Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sat, 23 May 2015 23:34:02 +0200 Subject: [PATCH 1/4] Update data_transformers.rst #2471 --- cookbook/form/data_transformers.rst | 126 ++++++++++++++++++++-------- 1 file changed, 90 insertions(+), 36 deletions(-) diff --git a/cookbook/form/data_transformers.rst b/cookbook/form/data_transformers.rst index 8bbcea505c1..1dafc3b1ffb 100644 --- a/cookbook/form/data_transformers.rst +++ b/cookbook/form/data_transformers.rst @@ -111,29 +111,96 @@ for converting to and from the issue number and the ``Issue`` object:: Using the Transformer --------------------- -Now that you have the transformer built, you just need to add it to your -issue field in some form. +As seen above our transformer requires an instance of an object manager. While for most +use-cases using the default manager is fine we will let you pick the manager by it's name. +In order to achieve this we will add a factory: + + // src/Acme/TaskBundle/Form/DataTransformer/IssueToNumberTransformerFactory.php + namespace Acme\TaskBundle\Form\DataTransformer; + + use Symfony\Bridge\Doctrine\ManagerRegistry; + + class IssueToNumberTransformerFactory + { + /** @var ManagerRegistry */ + private $registry; + + public function __construct(ManagerRegistry $registry) + { + $this->registry = $registry; + } + + public function create($om) + { + return new IssueToNumberTransformer($this->registry->getManager($om)); + } + } + +.. configuration-block:: + + .. code-block:: yaml + + services: + acme_demo.factory.issue_transformer: + class: Acme\TaskBundle\Form\DataTransformer\IssueToNumberTransformerFactory + arguments: ["@doctrine"] + + acme_demo.type.task: + class: Acme\TaskBundle\Form\TaskType + arguments: ["@acme_demo.factory.issue_transformer"] + + .. code-block:: xml + + + + + + + + + + .. code-block:: php + + $container + ->setDefinition('acme_demo.factory.issue_transformer', array( + new Reference('doctrine'), + )) + ; + + $container + ->setDefinition('acme_demo.type.task', array( + new Reference('acme_demo.factory.issue_transformer'), + )) + ; + +Now that you have capability to build the transformer with the desired object manager, you +just need to create it from your issue field in some form. You can also use transformers without creating a new custom form type by calling ``addModelTransformer`` (or ``addViewTransformer`` - see `Model and View Transformers`_) on any field builder:: + // src/Acme/TaskBundle/Form/TaskType.php + namespace Acme\TaskBundle\Form; + + use Acme\TaskBundle\Form\DataTransformer\IssueToNumberTransformerFactory; use Symfony\Component\Form\FormBuilderInterface; - use Acme\TaskBundle\Form\DataTransformer\IssueToNumberTransformer; + use Symfony\Component\OptionsResolver\OptionsResolverInterface; class TaskType extends AbstractType { - public function buildForm(FormBuilderInterface $builder, array $options) + /** @var IssueToNumberTransformerFactory */ + private $factory; + + public function __construct(IssueToNumberTransformerFactory $factory) { - // ... + $this->factory = $factory; + } - // the "em" is an option that you pass when creating your form. Check out - // the 3rd argument to createForm in the next code block to see how this - // is passed to the form (also see setDefaultOptions). - $entityManager = $options['em']; - $transformer = new IssueToNumberTransformer($entityManager); + public function buildForm(FormBuilderInterface $builder, array $options) + { + $transformer = $this->factory->create($options['om']); - // add a normal text field, but add your transformer to it $builder->add( $builder->create('issue', 'text') ->addModelTransformer($transformer) @@ -146,25 +213,18 @@ by calling ``addModelTransformer`` (or ``addViewTransformer`` - see ->setDefaults(array( 'data_class' => 'Acme\TaskBundle\Entity\Task', )) - ->setRequired(array( - 'em', - )) - ->setAllowedTypes(array( - 'em' => 'Doctrine\Common\Persistence\ObjectManager', - )); - - // ... + ->setRequired(array('om')) + ; } - - // ... } This example requires that you pass in the entity manager as an option when creating your form. Later, you'll learn how you could create a custom ``issue`` field type to avoid needing to do this in your controller:: - $taskForm = $this->createForm(new TaskType(), $task, array( - 'em' => $this->getDoctrine()->getManager(), + $taskType = $this->get('acme_demo.type.task'); + $taskForm = $this->createForm($taskType, $task, array( + 'om' => 'default', )); Cool, you're done! Your user will be able to enter an issue number into the @@ -257,30 +317,23 @@ First, create the custom field type class:: // src/Acme/TaskBundle/Form/Type/IssueSelectorType.php namespace Acme\TaskBundle\Form\Type; + use Acme\TaskBundle\Form\DataTransformer\IssueToNumberTransformerFactory; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; - use Acme\TaskBundle\Form\DataTransformer\IssueToNumberTransformer; - use Doctrine\Common\Persistence\ObjectManager; use Symfony\Component\OptionsResolver\OptionsResolverInterface; class IssueSelectorType extends AbstractType { - /** - * @var ObjectManager - */ - private $om; - - /** - * @param ObjectManager $om - */ - public function __construct(ObjectManager $om) + private $factory; + + public function __construct(IssueToNumberTransformerFactory $factory) { - $this->om = $om; + $this->factory = $factory; } public function buildForm(FormBuilderInterface $builder, array $options) { - $transformer = new IssueToNumberTransformer($this->om); + $transformer = $this->factory->create($options['om']); $builder->addModelTransformer($transformer); } @@ -288,6 +341,7 @@ First, create the custom field type class:: { $resolver->setDefaults(array( 'invalid_message' => 'The selected issue does not exist', + 'om' => 'default' )); } From 7929ed58f3540a5306988783c207e40e32ce5ed9 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sat, 23 May 2015 23:44:58 +0200 Subject: [PATCH 2/4] Update data_transformers.rst Minor change. --- cookbook/form/data_transformers.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cookbook/form/data_transformers.rst b/cookbook/form/data_transformers.rst index 1dafc3b1ffb..9ffa5c3282c 100644 --- a/cookbook/form/data_transformers.rst +++ b/cookbook/form/data_transformers.rst @@ -122,7 +122,9 @@ In order to achieve this we will add a factory: class IssueToNumberTransformerFactory { - /** @var ManagerRegistry */ + /** + * @var ManagerRegistry + */ private $registry; public function __construct(ManagerRegistry $registry) @@ -189,7 +191,9 @@ by calling ``addModelTransformer`` (or ``addViewTransformer`` - see class TaskType extends AbstractType { - /** @var IssueToNumberTransformerFactory */ + /** + * @var IssueToNumberTransformerFactory + */ private $factory; public function __construct(IssueToNumberTransformerFactory $factory) From 4b09b3fed4328126ca31be7bc1572173bd1df0eb Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sat, 23 May 2015 23:47:03 +0200 Subject: [PATCH 3/4] Update data_transformers.rst Minor change. --- cookbook/form/data_transformers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cookbook/form/data_transformers.rst b/cookbook/form/data_transformers.rst index 9ffa5c3282c..b41d359dd64 100644 --- a/cookbook/form/data_transformers.rst +++ b/cookbook/form/data_transformers.rst @@ -113,7 +113,7 @@ Using the Transformer As seen above our transformer requires an instance of an object manager. While for most use-cases using the default manager is fine we will let you pick the manager by it's name. -In order to achieve this we will add a factory: +In order to achieve this we will add a factory:: // src/Acme/TaskBundle/Form/DataTransformer/IssueToNumberTransformerFactory.php namespace Acme\TaskBundle\Form\DataTransformer; From 939cfc585c968e86af3139d660772e347194e477 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 25 May 2015 14:07:47 +0200 Subject: [PATCH 4/4] Update data_transformers.rst Couple of changes. --- cookbook/form/data_transformers.rst | 124 ++++++++++++++++++---------- 1 file changed, 81 insertions(+), 43 deletions(-) diff --git a/cookbook/form/data_transformers.rst b/cookbook/form/data_transformers.rst index b41d359dd64..c2ce3ae0486 100644 --- a/cookbook/form/data_transformers.rst +++ b/cookbook/form/data_transformers.rst @@ -28,13 +28,13 @@ Creating the Transformer First, create an ``IssueToNumberTransformer`` class - this class will be responsible for converting to and from the issue number and the ``Issue`` object:: - // src/Acme/TaskBundle/Form/DataTransformer/IssueToNumberTransformer.php - namespace Acme\TaskBundle\Form\DataTransformer; + // src/AppBundle/Form/DataTransformer/IssueToNumberTransformer.php + namespace AppBundle\Form\DataTransformer; + use AppBundle\Entity\Issue; + use Doctrine\Common\Persistence\ObjectManager; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; - use Doctrine\Common\Persistence\ObjectManager; - use Acme\TaskBundle\Entity\Issue; class IssueToNumberTransformer implements DataTransformerInterface { @@ -60,7 +60,7 @@ for converting to and from the issue number and the ``Issue`` object:: public function transform($issue) { if (null === $issue) { - return ""; + return ''; } return $issue->getNumber(); @@ -70,9 +70,7 @@ for converting to and from the issue number and the ``Issue`` object:: * Transforms a string (number) to an object (issue). * * @param string $number - * * @return Issue|null - * * @throws TransformationFailedException if object (issue) is not found. */ public function reverseTransform($number) @@ -82,7 +80,7 @@ for converting to and from the issue number and the ``Issue`` object:: } $issue = $this->om - ->getRepository('AcmeTaskBundle:Issue') + ->getRepository('AppBundle:Issue') ->findOneBy(array('number' => $number)) ; @@ -112,13 +110,13 @@ Using the Transformer --------------------- As seen above our transformer requires an instance of an object manager. While for most -use-cases using the default manager is fine we will let you pick the manager by it's name. -In order to achieve this we will add a factory:: +use-cases it is sufficient to use the default entity manager, you will sometimes need +to explicitly choose the one to use. To achieve this, you can use a factory:: - // src/Acme/TaskBundle/Form/DataTransformer/IssueToNumberTransformerFactory.php - namespace Acme\TaskBundle\Form\DataTransformer; + // src/AppBundle/Form/DataTransformer/IssueToNumberTransformerFactory.php + namespace AppBundle\Form\DataTransformer; - use Symfony\Bridge\Doctrine\ManagerRegistry; + use Doctrine\Common\Persistence\ManagerRegistry; class IssueToNumberTransformerFactory { @@ -143,49 +141,65 @@ In order to achieve this we will add a factory:: .. code-block:: yaml services: - acme_demo.factory.issue_transformer: - class: Acme\TaskBundle\Form\DataTransformer\IssueToNumberTransformerFactory + app.issue_transformer_factory: + class: AppBundle\Form\DataTransformer\IssueToNumberTransformerFactory arguments: ["@doctrine"] + public: false - acme_demo.type.task: - class: Acme\TaskBundle\Form\TaskType - arguments: ["@acme_demo.factory.issue_transformer"] + app.type.task: + class: AppBundle\Form\TaskType + arguments: ["@app.issue_transformer_factory"] + tag: + - { name: form.type, alias: app_task } .. code-block:: xml - + - - + + + .. code-block:: php + use Symfony\Component\DependencyInjection\Definition; + use Symfony\Component\DependencyInjection\Reference; + // ... + $container - ->setDefinition('acme_demo.factory.issue_transformer', array( + ->setDefinition('app.issue_transformer_factory', new Definition( + 'AppBundle\Form\DataTransformer\IssueToNumberTransformerFactory' + ), array( new Reference('doctrine'), )) + ->setPublic(false) ; $container - ->setDefinition('acme_demo.type.task', array( - new Reference('acme_demo.factory.issue_transformer'), + ->setDefinition('app.type.task', new Definition( + 'AppBundle\Form\TaskType' + ), array( + new Reference('app.issue_transformer_factory'), )) + ->addTag('form.type', array('alias' => 'app_task')) ; -Now that you have capability to build the transformer with the desired object manager, you +Now that you have the capability to build the transformer with the desired object manager, you just need to create it from your issue field in some form. You can also use transformers without creating a new custom form type by calling ``addModelTransformer`` (or ``addViewTransformer`` - see `Model and View Transformers`_) on any field builder:: - // src/Acme/TaskBundle/Form/TaskType.php - namespace Acme\TaskBundle\Form; + // src/AppBundle/Form/TaskType.php + namespace AppBundle\Form; - use Acme\TaskBundle\Form\DataTransformer\IssueToNumberTransformerFactory; + use AppBundle\Form\DataTransformer\IssueToNumberTransformerFactory; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolverInterface; @@ -215,7 +229,7 @@ by calling ``addModelTransformer`` (or ``addViewTransformer`` - see { $resolver ->setDefaults(array( - 'data_class' => 'Acme\TaskBundle\Entity\Task', + 'data_class' => 'AppBundle\Entity\Task', )) ->setRequired(array('om')) ; @@ -226,8 +240,7 @@ This example requires that you pass in the entity manager as an option when creating your form. Later, you'll learn how you could create a custom ``issue`` field type to avoid needing to do this in your controller:: - $taskType = $this->get('acme_demo.type.task'); - $taskForm = $this->createForm($taskType, $task, array( + $taskForm = $this->createForm('app_task', $task, array( 'om' => 'default', )); @@ -318,10 +331,10 @@ a form that uses the transformer. Because of these, you may choose to :doc:`create a custom field type `. First, create the custom field type class:: - // src/Acme/TaskBundle/Form/Type/IssueSelectorType.php - namespace Acme\TaskBundle\Form\Type; + // src/AppBundle/Form/IssueSelectorType.php + namespace AppBundle\Form; - use Acme\TaskBundle\Form\DataTransformer\IssueToNumberTransformerFactory; + use AppBundle\Form\DataTransformer\IssueToNumberTransformerFactory; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolverInterface; @@ -368,24 +381,49 @@ it's recognized as a custom field type: .. code-block:: yaml services: - acme_demo.type.issue_selector: - class: Acme\TaskBundle\Form\Type\IssueSelectorType - arguments: ["@doctrine.orm.entity_manager"] + app.issue_transformer_factory: + class: AppBundle\Form\DataTransformer\IssueToNumberTransformerFactory + arguments: ["@doctrine"] + public: false + app.type.issue_selector: + class: AppBundle\Form\IssueSelectorType + arguments: ["@app.issue_transformer_factory"] tags: - { name: form.type, alias: issue_selector } .. code-block:: xml - - + + + + + + .. code-block:: php + use Symfony\Component\DependencyInjection\Definition; + use Symfony\Component\DependencyInjection\Reference; + // ... + + $container + ->setDefinition('app.issue_transformer_factory', new Definition( + 'AppBundle\Form\DataTransformer\IssueToNumberTransformerFactory' + ), array( + new Reference('doctrine'), + )) + ->setPublic(false) + ; + $container - ->setDefinition('acme_demo.type.issue_selector', array( - new Reference('doctrine.orm.entity_manager'), + ->setDefinition('app.type.issue_selector', new Definition( + 'AppBundle\Form\IssueSelectorType' + ), array( + new Reference('app.issue_transformer_factory'), )) ->addTag('form.type', array( 'alias' => 'issue_selector', @@ -395,8 +433,8 @@ it's recognized as a custom field type: Now, whenever you need to use your special ``issue_selector`` field type, it's quite easy:: - // src/Acme/TaskBundle/Form/Type/TaskType.php - namespace Acme\TaskBundle\Form\Type; + // src/AppBundle/Form/TaskType.php + namespace AppBundle\Form; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface;