Issue 1:
The ValidatorTypeGuesser does not consider the current form's validation_groups option when guessing type. This could be fixed by passing the options array to the guesser methods. The signature of the FormTypeGuesserInterface methods would look like this:

function guessType($class, $property, array $options = array());

The default argument is provided for BC.

Issue 2:
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

guessing should be made more efficient by generating optimized guessers for model classes

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();
}
}
}