10000 [Form] Improve guessing mechanism · Issue #7868 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content
[Form] Improve guessing mechanism #7868
Closed
@webmozart

Description

@webmozart

Currently, the guessing mechanism is not very efficient, because it needs to do type and metadata introspection which naturally is slow. It is also limited, because options cannot be guessed when the type is fixed in the builder.

For example, assume that a property "firstName" does not have a NotNull constraint. When you do

$builder->add('firstName', 'text');

the field will still be required, because guessing is only activated when the type parameter is omitted. To improve this status quo

  1. guessing should be made more efficient by generating optimized guessers for model classes
  2. option guessing should be activated even when the "type" parameter is given

(1) is a requirement for (2), because activating guessing for every field consequently needs a very efficient guessing mechanism.

Implementation Suggestion

To realize the above, I suggest to add two interfaces, FormGuesserInterface and FormGuesserStrategyInterface (which replaces the current FormTypeGuesserInterface). Both are very similar, but while FormGuesserStrategyInterface returns Guess instances with confidence values about the correctness of the guessed value, FormGuesserInterface returns plain PHP values.

Each form extension can optionally provide a guesser strategy, for example ValidatorGuesserStrategy and DoctrineGuesserStrategy. The form core will use a StrategyBasedGuesser that is initialized with a list of these strategies and then resolves the guesses to plain PHP values.

Additionally, the form core should implement a GeneratorBasedGuesser that generates optimized PHP classes for each model class and then uses these classes for guessing. For an example see below.

FormGuesserInterface
interface FormGuesserInterface
{
    /**
     * @param string $class The class name to guess for.
     * @param string $property The property name to guess for.
     * @return string The form type to use.
     */
    public function guessType($class, $property);

    /**
     * @param string $type The used form type.
     * @param string $class The class name to guess for.
     * @param string $property The property name to guess for.
     * @return array The options to use.
     */
    public function guessOptions($type, $class, $property);
}
FormGuesserStrategyInterface
interface FormGuesserStrategyInterface
{
    /**
     * @param string $class The class name to guess for.
     * @param string $property The property name to guess for.
     * @return TypeGuess The form type to use together with a confidence level.
     */
    public function guessType($class, $property);

    /**
     * @param string $type The used form type.
     * @param string $class The class name to guess for.
     * @param string $property The property name to guess for.
     * @return OptionGuess[] The options to use together with confidence levels
     * and applicable form types.
     */
    public function guessOptions($type, $class, $property);
}
TypeGuess
use Symfony\Component\Form\Guess\Guess;

class TypeGuess extends Guess
{
     /**
      * @return string The guessed type.
      */
     public function getType();
}
OptionGuess
use Symfony\Component\Form\Guess\Guess;

class OptionGuess extends Guess
{
     /**
      * @return string The option name.
      */
     public function getOption();

     /**
      * @return string The guessed option value.
      */
     public function getValue();

     /**
      * @return string[] The applicable form types.
      */
     public function getApplicableTypes();
}
Generated Guesser Example
// Generated guesser for the "Person" model class
class PersonGuesser implements ClassSpecificFormGuesserInterface
{
    public function guessType($property)
    {
        switch ($property) {
            case 'gender':
                return 'choice';
            default:
                return 'text';
        }
    }

    public function guessOptions($type, $property)
    {
        switch ($property) {
            case 'gender':
                return array(
                    'required' => true,
                    'choices' => array('male', 'female'),
                );
            case 'firstName':
                return array(
                    'required' => false,
                );
            default:
                return array();
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0