-
-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Document how to create a custom type guesser #3597
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,3 +5,4 @@ | |
:maxdepth: 2 | ||
|
||
introduction | ||
type_guesser |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
.. index:: | ||
single: Forms; Custom Type Guesser | ||
|
||
Creating a Custom Type Guesser | ||
============================== | ||
|
||
The Form component can guess the type and some options of a form field by | ||
using type guessers. The component already includes a type guesser using the | ||
assertions of the Validation component, but you can also add your own custom | ||
type guessers. | ||
|
||
.. sidebar:: Form Type Guessers in the Bridges | ||
|
||
Symfony also provides some form type guessers in the bridges. These can be | ||
used if you use that library. | ||
|
||
* :class:`Symfony\\Bridge\\Propel1\\Form\\PropelTypeGuesser` provided by | ||
the Propel1 bridge; | ||
* :class:`Symfony\\Bridge\\Doctrine\\Form\\DoctrineOrmTypeGuesser` | ||
provided by the Doctrine bridge. | ||
|
||
A PHPDoc Type Guesser | ||
--------------------- | ||
|
||
In this section, you are going to build a PHPDoc type guesser. At first, you | ||
need to create a class which extends | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wich implements There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 AND, how about we change the header to "Create a PHPDoc Type Guesser" and then remove the first sentence (or replace it with something describing what this means - e.g. "In this section, you are going to build a guesser that reads information about fields from the PHPDoc above the properties"). |
||
:class:`Symfony\\Component\\Form\\FormTypeGuesserInterface`. This interface | ||
requires 4 methods: | ||
|
||
* :method:`Symfony\\Component\\Form\\FormTypeGuesserInterface::guessType` - | ||
tries to guess the type of a field; | ||
* :method:`Symfony\\Component\\Form\\FormTypeGuesserInterface::guessRequired` - | ||
tries to guess the value of the ``required`` option; | ||
* :method:`Symfony\\Component\\Form\\FormTypeGuesserInterface::guessMaxLength` - | ||
tries to guess the value of the ``max_length`` option; | ||
* :method:`Symfony\\Component\\Form\\FormTypeGuesserInterface::guessPattern` - | ||
tries to guess the value of the ``pattern`` option. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we could link the option to their descriptions in the reference docs |
||
|
||
The most basic class looks like:: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like this better as a command so that it's clear that this is step 1:
|
||
|
||
use Symfony\Component\Form\FormTypeGuesserInterface; | ||
|
||
class PHPDocTypeGuesser implements FormTypeGuesserInterface | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I prefer There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. agreed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. well, either actually, since it does appear to be called PHPDoc There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, uppercasing letters is a big CS problem if you ask me :) Doctrine always use things like ORM and not Orm in their classes/namespaces, but the CMF has switched to Orm (Phpcr actually...). So I'll change it to PhpDoc to make you happy :P There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wanted to change, but I will leave it as it is. Since it should be |
||
{ | ||
public function guessType($class, $property) | ||
{ | ||
} | ||
|
||
public function guessRequired($class, $property) | ||
{ | ||
} | ||
|
||
public function guessMaxLength($class, $property) | ||
{ | ||
} | ||
|
||
public function guessPattern($class, $property) | ||
{ | ||
} | ||
} | ||
|
||
Guessing the Type | ||
~~~~~~~~~~~~~~~~~ | ||
|
||
When guessing a type, the method returns either an instance of | ||
:class:`Symfony\\Component\\Form\\Guess\\TypeGuess` or nothing, to determine | ||
that the type guesser cannot guess the type. | ||
|
||
The ``TypeGuess`` constructor requires 3 options: | ||
|
||
* The type name (one of the :doc:`form types </reference/forms/types`); | ||
* Additionally options (for instance, when the type is ``entity``, you also | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Additional |
||
want to set the ``class`` option). If no types are guessed, this should be | ||
set to an empty array; | ||
* The confidence that the guessed type is correct. This can be one of the | ||
constants of the :class:`Symfony\\Component\\Form\\Guess\Guess` class: | ||
``LOW_CONFIDENCE``, ``MEDIUM_CONFIDENCE``, ``HIGH_CONFIDENCE``, | ||
``VERY_HIGH_CONFIDENCE``. After all type guessers are executed, the type | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. have been executed |
||
with the highest confidence is used. | ||
|
||
With this knowledge, you can easily implement the ``guessType`` method of the | ||
``PHPDocTypeGuesser``:: | ||
|
||
use Symfony\Component\Form\Guess\Guess; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it was good to add a namespace declaration There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what do you mean? It's not inside a class and I've just copied the example from the introduction chapter There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reading the article I had the understanding that this is a part of the Maybe it's more clear if you wrap the method inside a class. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I thought you commented on another code example, I'll include the namespace here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. actually, this is part of the PHPDocTypeGuesser class, @xabbuh |
||
use Symfony\Component\Form\Guess\TypeGuess; | ||
|
||
// ... | ||
public function guessType($class, $property) | ||
{ | ||
$annotations = $this->readPhpDocAnnotations($class, $property); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're going to at least need to make a mention that we're leaving the implementation of this function to the user, and maybe a clue on how it might work (because after all, the example you chose for this entry is actually pretty awesome and real-world). |
||
|
||
if (!isset($annotations['var'])) { | ||
return; // guess nothing if the @var annotation is not available | ||
} | ||
|
||
// otherwise, base the type on the @var annotation | ||
switch ($annotations['var']) { | ||
case 'string': | ||
// there is a high confidence that the type is a string when | ||
// @var string is used | ||
return new TypeGuess('text', array(), Guess::HIGH_CONFIDENCE); | ||
|
||
case 'int': | ||
case 'integer': | ||
// integers can also be the id of an entity or a checkbox (0 or 1) | ||
return new TypeGuess('integer', array(), Guess::MEDIUM_CONFIDENCE); | ||
|
||
case 'float': | ||
case 'double': | ||
case 'real': | ||
return new TypeGuess('number', array(), Guess::MEDIUM_CONFIDENCE); | ||
|
||
case 'boolean': | ||
case 'bool': | ||
return new TypeGuess('checkbox', array(), Guess::HIGH_CONFIDENCE); | ||
|
||
default: | ||
// there is a very low confidence that this one is correct | ||
return new TypeGuess('text', array(), Guess::LOW_CONFIDENCE); | ||
} | ||
} | ||
|
||
This type guesser can now guess the field type for a property if it has | ||
PHPdoc! | ||
|
||
Guessing Field Options | ||
~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
The other 3 methods (``guessMaxLength``, ``guessRequired`` and | ||
``guessPattern``) return a :class:`Symfony\\Component\\Form\\Guess\\ValueGuess` | ||
instance with the value of the option. This constructor has 2 arguments: | ||
|
||
* The value of the option; | ||
* The confidence that the guessed value is correct (using the constants of the | ||
``Guess`` class). | ||
|
||
``null`` is guessed when you believe the value of the option should not be | ||
set. | ||
|
||
.. caution:: | ||
|
||
You should be very careful with the ``guessPattern`` method. When the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [...] be careful using the [...] |
||
type is a float, you cannot use it to determine a min or max value of the | ||
float (e.g. you want a float to be greater than ``5``, ``4.512313`` is not valid | ||
but ``length(4.512314) > length(5)`` is, so the pattern will success). In | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [...] so the pattern will succeed. |
||
this case, the value should be set to ``null`` with a ``MEDIUM_CONFIDENCE``. | ||
|
||
Registering a Type Guesser | ||
-------------------------- | ||
|
||
The last thing you need to do is registering your custom type guesser by using | ||
:method:`Symfony\\Component\\Form\\FormFactoryBuilder::addTypeGuesser` or | ||
:method:`Symfony\\Component\\Form\\FormFactoryBuilder::addTypeGuessers`:: | ||
|
||
use Symfony\Component\Form\Forms; | ||
use Acme\Form\PHPDocTypeGuesser; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would move the type guesser into a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The symfony convention is to put them directly into the |
||
|
||
$formFactory = Forms::createFormFactoryBuilder() | ||
// ... | ||
->addTypeGuesser(new PHPDocTypeGuesser()) | ||
->getFormFactory(); | ||
|
||
// ... | ||
|
||
.. note:: | ||
|
||
When you use the full stack framework, you need to register your type | ||
guesser and tag it with ``form.type_guesser``. For more information see | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. guesser as a service There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, maybe we should be saying "If you're using the Symfony Framework" - calling it "Symfony Framework" instead of "full stack framework" |
||
:ref:`the tag reference <reference-dic-type_guesser>`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd remove the second sentence entirely - it doesn't sound right and I don't think it adds anything