跳到内容

创建自定义类型猜测器

编辑此页

表单组件可以通过使用类型猜测器来猜测表单字段的类型和一些选项。该组件已经包含一个使用验证组件断言的类型猜测器,但您也可以添加自己的自定义类型猜测器。

Symfony 还在桥接器中提供了一些表单类型猜测器

猜测器仅在以下情况下使用

创建 PHPDoc 类型猜测器

在本节中,您将构建一个猜测器,该猜测器从属性的 PHPDoc 中读取有关字段的信息。首先,您需要创建一个实现 FormTypeGuesserInterface 的类。此接口需要四个方法

guessType()
尝试猜测字段的类型;
guessRequired()
尝试猜测 required 选项的值;
guessMaxLength()
尝试猜测 maxlength 输入属性的值;
guessPattern()
尝试猜测 pattern 输入属性的值。

首先创建类和这些方法。接下来,您将学习如何填充每个方法

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
// src/Form/TypeGuesser/PhpDocTypeGuesser.php
namespace App\Form\TypeGuesser;

use Symfony\Component\Form\FormTypeGuesserInterface;
use Symfony\Component\Form\Guess\TypeGuess;
use Symfony\Component\Form\Guess\ValueGuess;

class PhpDocTypeGuesser implements FormTypeGuesserInterface
{
    public function guessType(string $class, string $property): ?TypeGuess
    {
    }

    public function guessRequired(string $class, string $property): ?ValueGuess
    {
    }

    public function guessMaxLength(string $class, string $property): ?ValueGuess
    {
    }

    public function guessPattern(string $class, string $property): ?ValueGuess
    {
    }
}

猜测类型

当猜测类型时,该方法返回 TypeGuess 的实例,或者什么也不返回,以确定类型猜测器无法猜测类型。

TypeGuess 构造函数需要三个选项

  • 类型名称(表单类型之一);
  • 其他选项(例如,当类型为 entity 时,您还需要设置 class 选项)。如果未猜测到任何选项,则应将其设置为空数组;
  • 猜测类型正确的置信度。这可以是 Guess 类的常量之一:LOW_CONFIDENCEMEDIUM_CONFIDENCEHIGH_CONFIDENCEVERY_HIGH_CONFIDENCE。在执行完所有类型猜测器后,将使用置信度最高的类型。

有了这些知识,您就可以实现 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
// src/Form/TypeGuesser/PhpDocTypeGuesser.php
namespace App\Form\TypeGuesser;

use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Guess\Guess;
use Symfony\Component\Form\Guess\TypeGuess;

class PhpDocTypeGuesser implements FormTypeGuesserInterface
{
    public function guessType(string $class, string $property): ?TypeGuess
    {
        $annotations = $this->readPhpDocAnnotations($class, $property);

        if (!isset($annotations['var'])) {
            return null; // guess nothing if the @var annotation is not available
        }

        // otherwise, base the type on the @var annotation
        return match($annotations['var']) {
            // there is a high confidence that the type is text when
            // @var string is used
            'string' => new TypeGuess(TextType::class, [], Guess::HIGH_CONFIDENCE),

            // integers can also be the id of an entity or a checkbox (0 or 1)
            'int', 'integer' => new TypeGuess(IntegerType::class, [], Guess::MEDIUM_CONFIDENCE),

            'float', 'double', 'real' => new TypeGuess(NumberType::class, [], Guess::MEDIUM_CONFIDENCE),

            'boolean', 'bool' => new TypeGuess(CheckboxType::class, [], Guess::HIGH_CONFIDENCE),

            // there is a very low confidence that this one is correct
            default => new TypeGuess(TextType::class, [], Guess::LOW_CONFIDENCE)
        };
    }

    protected function readPhpDocAnnotations(string $class, string $property): array
    {
        $reflectionProperty = new \ReflectionProperty($class, $property);
        $phpdoc = $reflectionProperty->getDocComment();

        // parse the $phpdoc into an array like:
        // ['var' => 'string', 'since' => '1.0']
        $phpdocTags = ...;

        return $phpdocTags;
    }

    // ...
}

如果属性具有 PHPDoc,则此类型猜测器现在可以猜测该属性的字段类型!

猜测字段选项

其他三个方法(guessMaxLength()guessRequired()guessPattern())返回一个 ValueGuess 实例,其中包含选项的值。此构造函数有 2 个参数

  • 选项的值;
  • 猜测值正确的置信度(使用 Guess 类的常量)。

当您认为不应设置选项的值时,将猜测为 null

警告

您应该非常小心地使用 guessMaxLength() 方法。当类型为浮点数时,您无法确定长度(例如,您希望浮点数小于 55.512313 无效,但 length(5.512314) > length(5) 有效,因此模式将成功)。在这种情况下,值应设置为 null,置信度为 MEDIUM_CONFIDENCE

注册类型猜测器

如果您正在使用 autowireautoconfigure,那么您就完成了!Symfony 已经知道并正在使用您的表单类型猜测器。

如果您没有使用 autowire 和 autoconfigure,请手动注册您的服务并使用 form.type_guesser 标记它

1
2
3
4
5
6
# config/services.yaml
services:
    # ...

    App\Form\TypeGuesser\PhpDocTypeGuesser:
        tags: [form.type_guesser]

如果您在 PHP 项目中独立使用表单组件,请使用 FormFactoryBuilderaddTypeGuesser()addTypeGuessers() 来注册新的类型猜测器

1
2
3
4
5
6
7
8
9
use App\Form\TypeGuesser\PhpDocTypeGuesser;
use Symfony\Component\Form\Forms;

$formFactory = Forms::createFormFactoryBuilder()
    // ...
    ->addTypeGuesser(new PhpDocTypeGuesser())
    ->getFormFactory();

// ...

提示

运行以下命令以验证表单类型猜测器是否已成功注册到应用程序中

1
$ php bin/console debug:form
这项工作,包括代码示例,根据 Creative Commons BY-SA 3.0 许可获得许可。
目录
    版本