Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 2657ee7

Browse filesBrowse files
committed
feature #3597 Document how to create a custom type guesser (WouterJ)
This PR was merged into the 2.3 branch. Discussion ---------- Document how to create a custom type guesser | Q | A | --- | --- | Doc fix? | no | New docs? | yes | Applies to | all | Fixed tickets | #481 Commits ------- 0d37a3b Applied comments 3b3cd6f Added references f36fdb7 Documented FormTypeGuesserInterface
2 parents 5ad1599 + 0d37a3b commit 2657ee7
Copy full SHA for 2657ee7

File tree

Expand file treeCollapse file tree

5 files changed

+206
-6
lines changed
Filter options
Expand file treeCollapse file tree

5 files changed

+206
-6
lines changed

‎components/form/index.rst

Copy file name to clipboardExpand all lines: components/form/index.rst
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
:maxdepth: 2
66

77
introduction
8+
type_guesser

‎components/form/type_guesser.rst

Copy file name to clipboard
+191Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
.. index::
2+
single: Forms; Custom Type Guesser
3+
4+
Creating a Custom Type Guesser
5+
==============================
6+
7+
The Form component can guess the type and some options of a form field by
8+
using type guessers. The component already includes a type guesser using the
9+
assertions of the Validation component, but you can also add your own custom
10+
type guessers.
11+
12+
.. sidebar:: Form Type Guessers in the Bridges
13+
14+
Symfony also provides some form type guessers in the bridges:
15+
16+
* :class:`Symfony\\Bridge\\Propel1\\Form\\PropelTypeGuesser` provided by
17+
the Propel1 bridge;
18+
* :class:`Symfony\\Bridge\\Doctrine\\Form\\DoctrineOrmTypeGuesser`
19+
provided by the Doctrine bridge.
20+
21+
Create a PHPDoc Type Guesser
22+
----------------------------
23+
24+
In this section, you are going to build a guesser that reads information about
25+
fields from the PHPDoc of the properties. At first, you need to create a class
26+
which implements :class:`Symfony\\Component\\Form\\FormTypeGuesserInterface`.
27+
This interface requires 4 methods:
28+
29+
* :method:`Symfony\\Component\\Form\\FormTypeGuesserInterface::guessType` -
30+
tries to guess the type of a field;
31+
* :method:`Symfony\\Component\\Form\\FormTypeGuesserInterface::guessRequired` -
32+
tries to guess the value of the :ref:`required <reference-form-option-required>`
33+
option;
34+
* :method:`Symfony\\Component\\Form\\FormTypeGuesserInterface::guessMaxLength` -
35+
tries to guess the value of the :ref:`max_length <reference-form-option-max_length>`
36+
option;
37+
* :method:`Symfony\\Component\\Form\\FormTypeGuesserInterface::guessPattern` -
38+
tries to guess the value of the :ref:`pattern <reference-form-option-pattern>`
39+
option.
40+
41+
Start by creating the class and these methods. Next, you'll learn how to fill each on.
42+
43+
.. code-block:: php
44+
45+
namespace Acme\Form;
46+
47+
use Symfony\Component\Form\FormTypeGuesserInterface;
48+
49+
class PhpdocTypeGuesser implements FormTypeGuesserInterface
50+
{
51+
public function guessType($class, $property)
52+
{
53+
}
54+
55+
public function guessRequired($class, $property)
56+
{
57+
}
58+
59+
public function guessMaxLength($class, $property)
60+
{
61+
}
62+
63+
public function guessPattern($class, $property)
64+
{
65+
}
66+
}
67+
68+
Guessing the Type
69+
~~~~~~~~~~~~~~~~~
70+
71+
When guessing a type, the method returns either an instance of
72+
:class:`Symfony\\Component\\Form\\Guess\\TypeGuess` or nothing, to determine
73+
that the type guesser cannot guess the type.
74+
75+
The ``TypeGuess`` constructor requires 3 options:
76+
77+
* The type name (one of the :doc:`form types </reference/forms/types`);
78+
* Additional options (for instance, when the type is ``entity``, you also
79+
want to set the ``class`` option). If no types are guessed, this should be
80+
set to an empty array;
81+
* The confidence that the guessed type is correct. This can be one of the
82+
constants of the :class:`Symfony\\Component\\Form\\Guess\Guess` class:
83+
``LOW_CONFIDENCE``, ``MEDIUM_CONFIDENCE``, ``HIGH_CONFIDENCE``,
84+
``VERY_HIGH_CONFIDENCE``. After all type guessers have been executed, the
85+
type with the highest confidence is used.
86+
87+
With this knowledge, you can easily implement the ``guessType`` method of the
88+
``PHPDocTypeGuesser``::
89+
90+
namespace Acme\Form;
91+
92+
use Symfony\Component\Form\Guess\Guess;
93+
use Symfony\Component\Form\Guess\TypeGuess;
94+
95+
class PhpdocTypeGuesser implements FormTypeGuesserInterface
96+
{
97+
public function guessType($class, $property)
98+
{
99+
$annotations = $this->readPhpDocAnnotations($class, $property);
100+
101+
if (!isset($annotations['var'])) {
102+
return; // guess nothing if the @var annotation is not available
103+
}
104+
105+
// otherwise, base the type on the @var annotation
106+
switch ($annotations['var']) {
107+
case 'string':
108+
// there is a high confidence that the type is a string when
109+
// @var string is used
110+
return new TypeGuess('text', array(), Guess::HIGH_CONFIDENCE);
111+
112+
case 'int':
113+
case 'integer':
114+
// integers can also be the id of an entity or a checkbox (0 or 1)
115+
return new TypeGuess('integer', array(), Guess::MEDIUM_CONFIDENCE);
116+
117+
case 'float':
118+
case 'double':
119+
case 'real':
120+
return new TypeGuess('number', array(), Guess::MEDIUM_CONFIDENCE);
121+
122+
case 'boolean':
123+
case 'bool':
124+
return new TypeGuess('checkbox', array(), Guess::HIGH_CONFIDENCE);
125+
126+
default:
127+
// there is a very low confidence that this one is correct
128+
return new TypeGuess('text', array(), Guess::LOW_CONFIDENCE);
129+
}
130+
}
131+
132+
protected function readPhpDocAnnotations($class, $property)
133+
{
134+
$reflectionProperty = new \ReflectionProperty($class, $property);
135+
$phpdoc = $reflectionProperty->getDocComment();
136+
137+
// parse the $phpdoc into an array like:
138+
// array('type' => 'string', 'since' => '1.0')
139+
$phpdocTags = ...;
140+
141+
return $phpdocTags;
142+
}
143+
}
144+
145+
This type guesser can now guess the field type for a property if it has
146+
PHPdoc!
147+
148+
Guessing Field Options
149+
~~~~~~~~~~~~~~~~~~~~~~
150+
151+
The other 3 methods (``guessMaxLength``, ``guessRequired`` and
152+
``guessPattern``) return a :class:`Symfony\\Component\\Form\\Guess\\ValueGuess`
153+
instance with the value of the option. This constructor has 2 arguments:
154+
155+
* The value of the option;
156+
* The confidence that the guessed value is correct (using the constants of the
157+
``Guess`` class).
158+
159+
``null`` is guessed when you believe the value of the option should not be
160+
set.
161+
162+
.. caution::
163+
164+
You should be very careful using the ``guessPattern`` method. When the
165+
type is a float, you cannot use it to determine a min or max value of the
166+
float (e.g. you want a float to be greater than ``5``, ``4.512313`` is not valid
167+
but ``length(4.512314) > length(5)`` is, so the pattern will succeed). In
168+
this case, the value should be set to ``null`` with a ``MEDIUM_CONFIDENCE``.
169+
170+
Registering a Type Guesser
171+
--------------------------
172+
173+
The last thing you need to do is registering your custom type guesser by using
174+
:method:`Symfony\\Component\\Form\\FormFactoryBuilder::addTypeGuesser` or
175+
:method:`Symfony\\Component\\Form\\FormFactoryBuilder::addTypeGuessers`::
176+
177+
use Symfony\Component\Form\Forms;
178+
use Acme\Form\PHPDocTypeGuesser;
179+
180+
$formFactory = Forms::createFormFactoryBuilder()
181+
// ...
182+
->addTypeGuesser(new PHPDocTypeGuesser())
183+
->getFormFactory();
184+
185+
// ...
186+
187+
.. note::
188+
189+
When you use the Symfony framework, you need to register your type guesser
190+
and tag it with ``form.type_guesser``. For more information see
191+
:ref:`the tag reference <reference-dic-type_guesser>`.

‎components/map.rst.inc

Copy file name to clipboardExpand all lines: components/map.rst.inc
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
* :doc:`/components/form/index`
6969

7070
* :doc:`/components/form/introduction`
71+
* :doc:`/components/form/type_guesser`
7172

7273
* :doc:`/components/http_foundation/index`
7374

‎reference/dic_tags.rst

Copy file name to clipboardExpand all lines: reference/dic_tags.rst
+7-6Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -332,21 +332,22 @@ The ``alias`` key of the tag is the type of field that this extension should
332332
be applied to. For example, to apply the extension to any form/field, use the
333333
"form" value.
334334
335+
.. _reference-dic-type_guesser:
336+
335337
form.type_guesser
336338
-----------------
337339
338340
**Purpose**: Add your own logic for "form type guessing"
339341
340342
This tag allows you to add your own logic to the :ref:`Form Guessing <book-forms-field-guessing>`
341343
process. By default, form guessing is done by "guessers" based on the validation
342-
metadata and Doctrine metadata (if you're using Doctrine).
344+
metadata and Doctrine metadata (if you're using Doctrine) or Propel metadata
345+
(if you're using Propel).
343346
344-
To add your own form type guesser, create a class that implements the
345-
:class:`Symfony\\Component\\Form\\FormTypeGuesserInterface` interface. Next,
346-
tag its service definition with ``form.type_guesser`` (it has no options).
347+
.. seelalso::
347348
348-
To see an example of how this class might look, see the ``ValidatorTypeGuesser``
349-
class in the Form component.
349+
For information on how to create your own type guesser, see
350+
:doc:`/components/form/type_guesser`.
350351
351352
kernel.cache_clearer
352353
--------------------

‎reference/forms/types/form.rst

Copy file name to clipboardExpand all lines: reference/forms/types/form.rst
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ on all fields.
1717

1818
.. include:: /reference/forms/types/options/empty_data.rst.inc
1919

20+
.. _reference-form-option-required:
21+
2022
.. include:: /reference/forms/types/options/required.rst.inc
2123

2224
.. include:: /reference/forms/types/options/label.rst.inc
@@ -43,6 +45,8 @@ on all fields.
4345

4446
.. include:: /reference/forms/types/options/block_name.rst.inc
4547

48+
.. _reference-form-option-max_length:
49+
4650
.. include:: /reference/forms/types/options/max_length.rst.inc
4751

4852
.. include:: /reference/forms/types/options/by_reference.rst.inc
@@ -61,6 +65,8 @@ on all fields.
6165

6266
.. include:: /reference/forms/types/options/post_max_size_message.rst.inc
6367

68+
.. _reference-form-option-pattern:
69+
6470
.. include:: /reference/forms/types/options/pattern.rst.inc
6571

6672
.. include:: /reference/forms/types/options/action.rst.inc

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.