Создание пользовательского отгадывателя типа
Дата обновления перевода 2023-09-07
Создание пользовательского отгадывателя типа
Компонент Формы может отгадывать тип и некоторые опции поля формы, используя отгадыватели типа. Компонент уже включает в себя отгадыватель типа, используя утверждения компонента Валидации, но вы также можете добавлять ваши пользовательские отгадыватели типа.
Угадыватели используються только в следующих случаях:
- Используя createForProperty() или createBuilderForProperty();
- Вызывая add() или create() или add() без ясного типа, в контексте, где родительская форма имеет определённый класс данных.
Создайте отгадыватель типаPHPDoc
В этом разделе, вы построите отгадыватель, который читает информацию о полях из PHPDoc свойств. Вначале, вам нужно создать класс, реализующий FormTypeGuesserInterface. Этот интерфейс требует четыре метода:
- guessType()
- Пытается угадать тип поля;
- guessRequired()
- Пытается угадать значение обязательной опции;
- 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_CONFIDENCE
,MEDIUM_CONFIDENCE
,HIGH_CONFIDENCE
,VERY_HIGH_CONFIDENCE
. После того, как будут выполнены все отгадыватели типа, будет использован тип с наибольшим доверием.
Зная это, вы можете с лёгкостью реализовать метод guessType()
в PHPDocTypeGuesser
:
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; // ничего не угадывать, если аннотация @var недоступна
}
// в обратном случае, основывайте тип на аннотации @var
return match($annotations['var']) {
// существует высокая уверенность в том, что тип - текст, когда
// используется строка @var
'string' => new TypeGuess(TextType::class, [], Guess::HIGH_CONFIDENCE),
// целые числа также могут быть id сущности или флаговой кнопкой (0 или 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),
// уверенность в том, что этот тип правильный, очень низкая
default => new TypeGuess(TextType::class, [], Guess::LOW_CONFIDENCE)
};
}
protected function readPhpDocAnnotations(string $class, string $property): array
{
$reflectionProperty = new \ReflectionProperty($class, $property);
$phpdoc = $reflectionProperty->getDocComment();
// разобрать $phpdoc в массив таким образом:
// массив ('type' => 'string', 'since' => '1.0')
$phpdocTags = ...;
return $phpdocTags;
}
// ...
}
Этот отгадыватель типа теперь может угадывать типа поля для свойства, если оно имеет PHPdoc!
Опции поля отгадывания
Три других метода (guessMaxLength()
, guessRequired()
и guessPattern()
)
возвращают экземпляр ValueGuess с значением
опции. Этот конструктор имеет 2 аргумента:
- Значение опции;
- Уверенность в том, что отгаданное значение - верное (используя константы
класса
Guess
).
null
угадывается, когда вы думаете, что значение опции не должно
быть установлено.
Caution
Вы должны быть очень осторожны используя метод guessMaxLength()
. Когда тип
- float, вы не можете определить длину (например, вы хотите, чтобы float был меньше,
чем 5
, 5.512313
- не является валидным, но length(5.512314) > length(5)
-
валидно, так что схема сработает). В этом случае, значение должно быть установлено,
как null
с MEDIUM_CONFIDENCE
.
Регистрация отгадывателя типа
Если вы используете автомонтирование и автоконфигурацию , то вы закончили! Symfony уже знает и использует ваш отгадыватель типа формы..
Если вы не используете автомонтирование и автоконфигурацию, зарегистрируйте ваш
сервис вручную, и тегируйте его с помощью form.type_guesser
:
1 2 3 4 5 6
# config/services.yaml
services:
# ...
App\Form\TypeGuesser\PHPDocTypeGuesser:
tags: [form.type_guesser]
Tip
Выполните следующую команду, чтобы верифицировать, что отгадыватель типа формы был успешно зарегистирован в приложении:
1
$ php bin/console debug:form