I want to return to an old and very painful topic#5906. I wanted to revisit this topic before the release 4.0 and 5.0, but didn't find the time for this. Now, when everyone already has PHP 7 or 8, and thestrict_types=1
is the defect standard, it is probably time to abandon the hook when the text may not be astring
.
We've been using hooks for many years, even before#18357. We want string values to always be strings. Under strict typing conditions, i consider usingNULL
as a value valid only in cases where the expected value is not a scalar type and cannot be correctly transformed from the submitted data. In such cases, we use custom transformers.
Expected implementation
A very crude example.
useSymfony\Component\Validator\ConstraintsasAssert;finalclass RenameAuthor{/** * @Assert\NotBlank * @Assert\Length(max=128) */publicstring$firstname ='';/** * @Assert\Length(max=128) */publicstring$lastname ='';/** * @Assert\Length(max=128) */publicstring$patronymic ='';}
useSymfony\Component\Form\AbstractType;useSymfony\Component\Form\Extension\Core\Type\TextType;useSymfony\Component\Form\FormBuilderInterface;useSymfony\Component\OptionsResolver\OptionsResolver;finalclass RenameAuthorFormTypeextends AbstractType{publicfunctionbuildForm(FormBuilderInterface$builder,array$options):void {$builder ->add('firstname', TextType::class) ->add('lastname', TextType::class, ['required' =>false, ]) ->add('patronymic', TextType::class, ['required' =>false, ]) ; }publicfunctionconfigureOptions(OptionsResolver$resolver):void {$resolver->setDefault('data_class', RenameAuthor::class); }}
class Questionnaire{// ...publicfunctionrenameAuthor(string$new_firstname,string$new_lastname,string$new_patronymic):void {$this->author_name =newAuthorName($new_firstname,$new_lastname,$new_patronymic); }
$command =newRenameAuthor();$form =$this->createForm(RenameAuthorFormType::class,$command)->handleRequest($request);if ($form->isSubmitted() &&$form->isValid()) {$questionnaire->renameAuthor($command->firstname,$command->lastname,$command->patronymic);// ...}
Actual implementation
Without hooks and specifying optionempty_data
.
use Symfony\Component\Validator\Constraints as Assert;final class RenameAuthor{ /** * @Assert\NotBlank * @Assert\Length(max=128) */- public string $firstname = '';+ private string $firstname = ''; /** * @Assert\Length(max=128) */- public string $lastname = '';+ private string $lastname = ''; /** * @Assert\Length(max=128) */- public string $patronymic = '';+ private string $patronymic = '';++ public function getFirstname(): string+ {+ return $this->firstname;+ }++ public function setFirstname(?string $firstname): void+ {+ $this->firstname = $firstname ?? '';+ }++ public function getLastname(): string+ {+ return $this->lastname;+ }++ public function setLastname(?string $lastname): void+ {+ $this->lastname = $lastname ?? '';+ }++ public function getPatronymic(): string+ {+ return $this->patronymic;+ }++ public function setPatronymic(?string $patronymic): void+ {+ $this->patronymic = $patronymic ?? '';+ }}
$command = new RenameAuthor();$form = $this->createForm(RenameAuthorFormType::class, $command)->handleRequest($request);if ($form->isSubmitted() && $form->isValid()) {- $questionnaire->renameAuthor($command->firstname, $command->lastname, $command->patronymic);+ $questionnaire->renameAuthor($command->getFirstname(), $command->getLastname(), $command->getPatronymic()); // ...}
Implementation with empty_data option
It seems that specifying one option is not a problem. But you should always remember that the text may not be astring
, and to typecast to astring
, you need to specify optionempty_data
in each field, each form. There may be hundreds and thousands of such places per project, and the probability of errors increases with the growth of the project.
use Symfony\Component\Form\AbstractType;use Symfony\Component\Form\Extension\Core\Type\TextType;use Symfony\Component\Form\FormBuilderInterface;use Symfony\Component\OptionsResolver\OptionsResolver;final class RenameAuthorFormType extends AbstractType{ public function buildForm(FormBuilderInterface $builder, array $options): void { $builder- ->add('firstname', TextType::class)+ ->add('firstname', TextType::class, [+ 'empty_data' => '',+ ]) ->add('lastname', TextType::class, [+ 'empty_data' => '', 'required' => false, ]) ->add('patronymic', TextType::class, [+ 'empty_data' => '', 'required' => false, ]) ; } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefault('data_class', RenameAuthor::class); }}
Uh oh!
There was an error while loading.Please reload this page.
I want to return to an old and very painful topic#5906. I wanted to revisit this topic before the release 4.0 and 5.0, but didn't find the time for this. Now, when everyone already has PHP 7 or 8, and the
strict_types=1
is the defect standard, it is probably time to abandon the hook when the text may not be astring
.We've been using hooks for many years, even before#18357. We want string values to always be strings. Under strict typing conditions, i consider using
NULL
as a value valid only in cases where the expected value is not a scalar type and cannot be correctly transformed from the submitted data. In such cases, we use custom transformers.Expected implementation
A very crude example.
Actual implementation
Without hooks and specifying option
empty_data
.Implementation with empty_data option
It seems that specifying one option is not a problem. But you should always remember that the text may not be a
string
, and to typecast to astring
, you need to specify optionempty_data
in each field, each form. There may be hundreds and thousands of such places per project, and the probability of errors increases with the growth of the project.