diff --git a/components/form/index.rst b/components/form/index.rst index 8283298b120..5ea5add00f6 100644 --- a/components/form/index.rst +++ b/components/form/index.rst @@ -5,3 +5,4 @@ :maxdepth: 2 introduction + type_guesser diff --git a/components/form/type_guesser.rst b/components/form/type_guesser.rst new file mode 100644 index 00000000000..2cdc6c02dac --- /dev/null +++ b/components/form/type_guesser.rst @@ -0,0 +1,191 @@ +.. 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: + + * :class:`Symfony\\Bridge\\Propel1\\Form\\PropelTypeGuesser` provided by + the Propel1 bridge; + * :class:`Symfony\\Bridge\\Doctrine\\Form\\DoctrineOrmTypeGuesser` + provided by the Doctrine bridge. + +Create a PHPDoc Type Guesser +---------------------------- + +In this section, you are going to build a guesser that reads information about +fields from the PHPDoc of the properties. At first, you need to create a class +which implements :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 :ref:`required ` + option; +* :method:`Symfony\\Component\\Form\\FormTypeGuesserInterface::guessMaxLength` - + tries to guess the value of the :ref:`max_length ` + option; +* :method:`Symfony\\Component\\Form\\FormTypeGuesserInterface::guessPattern` - + tries to guess the value of the :ref:`pattern ` + option. + +Start by creating the class and these methods. Next, you'll learn how to fill each on. + +.. code-block:: php + + namespace Acme\Form; + + use Symfony\Component\Form\FormTypeGuesserInterface; + + class PhpdocTypeGuesser implements FormTypeGuesserInterface + { + 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 readPhpDocAnnotations($class, $property); + + 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); + } + } + + protected function readPhpDocAnnotations($class, $property) + { + $reflectionProperty = new \ReflectionProperty($class, $property); + $phpdoc = $reflectionProperty->getDocComment(); + + // parse the $phpdoc into an array like: + // array('type' => 'string', 'since' => '1.0') + $phpdocTags = ...; + + return $phpdocTags; + } + } + +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 using the ``guessPattern`` method. When 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 succeed). In + 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; + + $formFactory = Forms::createFormFactoryBuilder() + // ... + ->addTypeGuesser(new PHPDocTypeGuesser()) + ->getFormFactory(); + + // ... + +.. note:: + + When you use the Symfony framework, you need to register your type guesser + and tag it with ``form.type_guesser``. For more information see + :ref:`the tag reference `. diff --git a/components/map.rst.inc b/components/map.rst.inc index 867f04568ca..fbc1872afb8 100644 --- a/components/map.rst.inc +++ b/components/map.rst.inc @@ -68,6 +68,7 @@ * :doc:`/components/form/index` * :doc:`/components/form/introduction` + * :doc:`/components/form/type_guesser` * :doc:`/components/http_foundation/index` diff --git a/reference/dic_tags.rst b/reference/dic_tags.rst index 94fc8bac3f2..cbb8ca4c6a9 100644 --- a/reference/dic_tags.rst +++ b/reference/dic_tags.rst @@ -332,6 +332,8 @@ The ``alias`` key of the tag is the type of field that this extension should be applied to. For example, to apply the extension to any form/field, use the "form" value. +.. _reference-dic-type_guesser: + form.type_guesser ----------------- @@ -339,14 +341,13 @@ form.type_guesser This tag allows you to add your own logic to the :ref:`Form Guessing ` process. By default, form guessing is done by "guessers" based on the validation -metadata and Doctrine metadata (if you're using Doctrine). +metadata and Doctrine metadata (if you're using Doctrine) or Propel metadata +(if you're using Propel). -To add your own form type guesser, create a class that implements the -:class:`Symfony\\Component\\Form\\FormTypeGuesserInterface` interface. Next, -tag its service definition with ``form.type_guesser`` (it has no options). +.. seelalso:: -To see an example of how this class might look, see the ``ValidatorTypeGuesser`` -class in the Form component. + For information on how to create your own type guesser, see + :doc:`/components/form/type_guesser`. kernel.cache_clearer -------------------- diff --git a/reference/forms/types/form.rst b/reference/forms/types/form.rst index fe795634475..4464f763e05 100644 --- a/reference/forms/types/form.rst +++ b/reference/forms/types/form.rst @@ -17,6 +17,8 @@ on all fields. .. include:: /reference/forms/types/options/empty_data.rst.inc +.. _reference-form-option-required: + .. include:: /reference/forms/types/options/required.rst.inc .. include:: /reference/forms/types/options/label.rst.inc @@ -43,6 +45,8 @@ on all fields. .. include:: /reference/forms/types/options/block_name.rst.inc +.. _reference-form-option-max_length: + .. include:: /reference/forms/types/options/max_length.rst.inc .. include:: /reference/forms/types/options/by_reference.rst.inc @@ -61,6 +65,8 @@ on all fields. .. include:: /reference/forms/types/options/post_max_size_message.rst.inc +.. _reference-form-option-pattern: + .. include:: /reference/forms/types/options/pattern.rst.inc .. include:: /reference/forms/types/options/action.rst.inc