创建自定义的类型猜测器

3.4 版本
维护中的版本

通过使用type guesser(类型猜测器),表单组件可以猜出字段的“类型及部分选项”。本组件自带了一个“使用Validator组件的assertions(断言)”的type guesser,但你也可以添加自定义的type guesser。

Bridge中的表单类型猜测器

Symfony在bridges中也提供了一些表单类型的guesser:

创建一个PHPDoc Type Guesser 

本节,你要建立一个guesser,可以从属性上面的PHPDoc中读取字段信息。首先,你要创建一个类,令其实现FormTypeGuesserInterface接口。该接口有4个方法:

先用这几个方法把类建立起来。然后,你要学习如何填充每个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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)
    {
    }
}

类型猜测 

猜测一个类型时,方法返回的是TypeGuess实例,或什么也不返回以确定guesser不能猜测出这个类型。

TypeGuess类的构造器有三个参数:

  • 类型的名称(需是form types之一);

  • 附加选项(例如,当类型是entity时,你同时希望设置其class选项)。如果没有任何类型被猜中,此处被设置为一个空数组;

  • 猜出来的类型“有多正确”之confidence(自信度)。它可以是Guess类中的常量里的一个:LOW_CONFIDENCEMEDIUM_CONFIDENCEHIGH_CONFIDENCEVERY_HIGH_CONFIDENCE。当所有的guessers都被执行过之后,最高自信度的类型将被采纳。

在这些知识的帮助下,你可以去实现PHPDocTypeGuesserguessType方法了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
namespace Acme\Form;
 
use Symfony\Component\Form\Guess\Guess;
use Symfony\Component\Form\Guess\TypeGuess;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
 
class PHPDocTypeGuesser implements FormTypeGuesserInterface
{
    public function guessType($class, $property)
    {
        $annotations = $this->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 text when
                // @var string is used
                return new TypeGuess(TextType::class, 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(IntegerType::class, array(), Guess::MEDIUM_CONFIDENCE);
 
            case 'float':
            case 'double':
            case 'real':
                return new TypeGuess(NumberType::class, array(), Guess::MEDIUM_CONFIDENCE);
 
            case 'boolean':
            case 'bool':
                return new TypeGuess(CheckboxType::class, array(), Guess::HIGH_CONFIDENCE);
 
            default:
                // there is a very low confidence that this one is correct
                return new TypeGuess(TextType::class, 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;
    }
}

猜测字段选项 

另外3个方法(guessMaxLength()guessRequired()guessPattern())返回的是带有选项值的ValueGuess实例。其构造器有2个参数:

  • 选项的值;

  • 所猜之值有多正确的“自信度”(使用Guess类中的常量)。

若猜为null则表示你认为这个选项不应该被设置。

你应该非常小心地使用guessPattern()方法。当类型是float时,你不能用它来决断这个浮点的min值或max值(比如,你希望一个浮点大于5,那么4.512313是无效的,不过length(4.512314) > length(5)却是有效的,进而匹配成功)。在这个例子中,参数的取值应该分别设为nullMEDIUM_CONFIDENCE

注册一个type gueesser 

你要做的最后一件事,是用addTypeGuesser()方法或addTypeGuessers()方法来注册你的自定义type guesser:

1
2
3
4
5
6
7
8
9
use Symfony\Component\Form\Forms;
use Acme\Form\PHPDocTypeGuesser;
 
$formFactory = Forms::createFormFactoryBuilder()
    // ...
    ->addTypeGuesser(new PHPDocTypeGuesser())
    ->getFormFactory();
 
// ...

使用Symfony框架时,需要注册你的type guesser,并为它打上form.type_guesser标签。更多信息请阅读tag参考

本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。

登录symfonychina 发表评论或留下问题(我们会尽量回复)