Створення користувацького вгадувача типу

Дата оновлення перекладу 2023-09-07

Створення користувацького вгадувача типу

Компонент Form може вгадувати тип та деякі опції поля форми, використовуючи вгадувачі типу. Компонент вже містить у собі відгадувач типу, використовуючи ствердження компонента Validation, але ви також можете додавати ваші користувацькі вгадувачі типу.

Symfony також надає деякі вгадувачі типу у мостах:

Вгадувачі використовуються лише в наступних випадках:

Створіть вгадувач типу 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 у масив таким чином:
        // ['var' => 'string', 'since' => '1.0']
        $phpdocTags = ...;

        return $phpdocTags;
    }

    // ...
}

Цей вгадувач типу тепер може вгадувати тип поля для властивості, якщо вона має PHPdoc!

Опції поля вгадування

Три інших методи (guessMaxLength(), guessRequired() і guessPattern()) повертають екземпляр ValueGuess зі значенням опції. Цей конструктор має 2 аргументи:

  • Значенея опції;
  • Впевненість у тому, що вгадане значення - вірне (використовуючи константи класу Guess).

null вгадується, коли ви думаєте, що значення опції не має бути встановленим.

Caution

Ви маєте бути дуже обережні, використовуючи метод guessMaxLength(). Коли тип - float,
ви не можете визначити довжину (наприклад, ви хочете, щоб float був менше, ніж 5, 54.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]

Якщо ви використовуєте компонент Form ізольовано у вашому PHP-проекті, використайте addTypeGuesser() або addTypeGuessers() в FormFactoryBuilder, щоб зареєструвати нові вгадувачі типу:

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

// ...

Tip

Виконайте наступну команду, щоб верифікувати, що вгадувач типу форми був успішно зареєстрований у додатку:

1
$ php bin/console debug:form