[英]symfony5 - error 500 page instead form error in twig
我使用表單生成器設置了注冊表。
問題是 Symfony 拋出一個 InvalidArgumentException 頁面,其中包含Expected argument of type "string", "null" given at property path "user_name".
消息“ Expected argument of type "string", "null" given at property path "user_name".
當然,用戶實體中的setUserName
將user_name
類型定義為字符串,但我在表單構建器中添加了約束NotBlank
。 我預計樹枝內部會出現“此字段不能為空”之類的錯誤。
編輯:在評論 somme 屬性后,似乎在我的所有表單字段上都會發生這種行為。
為什么錯誤沒有出現在我的樹枝模板中? 我已經在 Symfony 4 中實現了這個流程,它的工作非常有魅力。
這里是建造者
<?php
namespace App\Form\Type;
use App\Entity\Department;
use App\Entity\Level;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Regex;
class InscriptionType extends AbstractType
{
/**
* EntityManagerInterface
*
* @var EntityManagerInterface
*/
private $em;
/**
* Constructor
*
* @param EntityManagerInterface $em
*/
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
/**
* Build the register form
*
* @param FormBuilderInterface $builder
* @param array $options
* @return void
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('user_name', TextType::class, [
'label' => 'Nom',
'attr' => [
'placeholder' => 'Doe'
],
'constraints' => [
new Length([
'min' => 3,
'minMessage' => 'Doit comporter 2 caractères ou plus',
]),
new Regex([
'pattern' => '/^[\wéèêàäâçïöôîûüù\' \-]+$/',
'message' => 'La chaîne comporte des caractères non autorisés',
]),
new NotBlank()
]
])
->add('user_firstname', TextType::class, [
'label' => 'Prénom',
'attr' => [
'placeholder' => 'John'
],
'constraints' => [
new Length([
'min' => 3,
'minMessage' => 'Doit comporter 2 caractères ou plus',
]),
new Regex([
'pattern' => '/^[\wéèêàäâçïöôîûüù\' \-]+$/',
'message' => 'La chaîne comporte des caractères non autorisés',
]),
new NotBlank()
],
])
->add('user_birthdate', DateType::class, [
'label' => 'Date de naissance',
'placeholder' => [
'year' => 'Année',
'month' => 'Mois',
'day' => 'Jours',
],
'widget' => 'single_text',
'input' => 'array',
'constraints' => [
new NotBlank()
],
])
->add('email', EmailType::class, [
'label' => 'Adresse email',
'attr' => [
'placeholder' => 'john.doe@exemple.com'
],
'constraints' => [
new NotBlank(),
],
])
->add('user_department', ChoiceType::class, [
'label' => 'Département',
'placeholder' => 'Sélectionnez un departement',
'choices' => $this->getDepartmentList(),
'constraints' => [
new NotBlank(),
],
])
->add('user_level', ChoiceType::class, [
'label' => 'Niveau',
'placeholder' => 'Sélectionnez votre niveau',
'choices' => $this->getLevelList(),
'constraints' => [
new NotBlank(),
],
])
->add('user_description', TextareaType::class, [
'label' => 'Description',
'constraints' => [
new Length([
'min' => 3,
'minMessage' => 'Doit comporter 2 caractères ou plus',
]),
new NotBlank(),
],
])
->add('password', PasswordType::class, [
'label' => 'Mot de passe',
'constraints' => [
new Length([
'min' => 3,
'minMessage' => 'Doit comporter 2 caractères ou plus',
]),
new NotBlank(),
],
])
->add('confirm_password', PasswordType::class, [
'mapped' => false,
'label' => 'Confirmation',
'constraints' => [
new Length([
'min' => 3,
'minMessage' => 'Doit comporter 2 caractères ou plus',
]),
new NotBlank(),
],
])
->add('submit', SubmitType::class, [
'label' => 'Valider',
]);
/* TO DO IMPLEMENTER CAPTCHA */
/*
if ($_ENV['GOOGLE_RECAPTCHA_ACTIVE'] === 'true') {
$builder->add('CaptchaDmd', HiddenType::class,[
'label' => 'Captcha',
'mapped' => false, // le captcha n'est pas une propriete existante dans l'entite demandePass, on indique que on ne doit pas la mapper
'error_bubbling' => false,
'constraints' => [
new NotBlank([
'message' => $this->translator->trans('LibBlankCaptcha')
])
]
]);
}
*/
}
/**
* Retrieve department list
*
* @return void
*/
protected function getDepartmentList()
{
$repo = $this->em->getRepository(Department::class);
$departments = [];
$departmentList = $repo->findAll();
foreach ($departmentList as $department) {
# $country est une instance de App\Entity\LangueInternational
$libelle = $department->getDepartmentNom() . ' (' . $department->getDepartementCode() . ')';
$valeur = $department->getId();
$departments[$libelle] = $valeur;
}
return $departments;
}
/**
* Retrieve level list
*
* @return void
*/
protected function getLevelList()
{
$repo = $this->em->getRepository(Level::class);
$levels = [];
$levelList = $repo->findAll();
foreach ($levelList as $level) {
# $country est une instance de App\Entity\LangueInternational
$libelle = ucfirst($level->getLevelName());
$valeur = $level->getId();
$levels[$libelle] = $valeur;
}
return $levels;
}
}
用戶實體
<?php
namespace App\Entity;
use App\Repository\UserRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* @ORM\Entity(repositoryClass=UserRepository::class)
*/
class User implements UserInterface
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=180, unique=true)
*/
private $email;
/**
* @ORM\Column(type="json")
*/
private $roles = [];
/**
* @var string The hashed password
* @ORM\Column(type="string")
*/
private $password;
/**
* @ORM\Column(type="string", length=255)
*/
private $user_name;
/**
* @ORM\Column(type="string", length=255)
*/
private $user_firstname;
/**
* @ORM\Column(type="date")
*/
private $user_birthdate;
/**
* @ORM\Column(type="integer")
*/
private $user_region;
/**
* @ORM\Column(type="integer")
*/
private $user_department;
/**
* @ORM\Column(type="text")
*/
private $user_description;
/**
* @ORM\Column(type="integer")
*/
private $user_level;
public function getId(): ?int
{
return $this->id;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
/**
* A visual identifier that represents this user.
*
* @see UserInterface
*/
public function getUsername(): string
{
return (string) $this->email;
}
/**
* @see UserInterface
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
/**
* @see UserInterface
*/
public function getPassword(): string
{
return (string) $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
/**
* @see UserInterface
*/
public function getSalt()
{
// not needed when using the "bcrypt" algorithm in security.yaml
}
/**
* @see UserInterface
*/
public function eraseCredentials()
{
// If you store any temporary, sensitive data on the user, clear it here
// $this->plainPassword = null;
}
public function setUserName(string $user_name): self
{
$this->user_name = $user_name;
return $this;
}
public function getUserFirstname(): ?string
{
return $this->user_firstname;
}
public function setUserFirstname(string $user_firstname): self
{
$this->user_firstname = $user_firstname;
return $this;
}
public function getUserBirthdate(): ?\DateTimeInterface
{
return $this->user_birthdate;
}
public function setUserBirthdate(\DateTimeInterface $user_birthdate): self
{
$this->user_birthdate = $user_birthdate;
return $this;
}
public function getUserRegion(): ?int
{
return $this->user_region;
}
public function setUserRegion(int $user_region): self
{
$this->user_region = $user_region;
return $this;
}
public function getUserDepartment(): ?int
{
return $this->user_department;
}
public function setUserDepartment(int $user_department): self
{
$this->user_department = $user_department;
return $this;
}
public function getUserDescription(): ?string
{
return $this->user_description;
}
public function setUserDescription(string $user_description): self
{
$this->user_description = $user_description;
return $this;
}
public function getUserLevel(): ?int
{
return $this->user_level;
}
public function setUserLevel(int $user_level): self
{
$this->user_level = $user_level;
return $this;
}
}
模板
{{ form_start(inscriptionForm, {'attr': {'novalidate' : 'novalidate'}}) }}
{{ form_errors(inscriptionForm) }}
<div class="form-row">
<div class="form-group col-md-6">
{{ form_label(inscriptionForm.user_name) }}
{{ form_widget(inscriptionForm.user_name) }}
{{ form_errors(inscriptionForm.user_name) }}
</div>
<div class="form-group col-md-6">
{{ form_label(inscriptionForm.user_firstname) }}
{{ form_widget(inscriptionForm.user_firstname) }}
{{ form_errors(inscriptionForm.user_firstname) }}
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
{{ form_label(inscriptionForm.email) }}
{{ form_widget(inscriptionForm.email) }}
{{ form_errors(inscriptionForm.email) }}
</div>
<div class="form-group col-md-6">
{{ form_label(inscriptionForm.user_birthdate) }}
{{ form_widget(inscriptionForm.user_birthdate) }}
{{ form_errors(inscriptionForm.user_birthdate) }}
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
{{ form_label(inscriptionForm.password) }}
{{ form_widget(inscriptionForm.password) }}
{{ form_errors(inscriptionForm.password) }}
</div>
<div class="form-group col-md-6">
{{ form_label(inscriptionForm.confirm_password) }}
{{ form_widget(inscriptionForm.confirm_password) }}
{{ form_errors(inscriptionForm.confirm_password) }}
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
{{ form_label(inscriptionForm.user_level) }}
{{ form_widget(inscriptionForm.user_level) }}
{{ form_errors(inscriptionForm.user_level) }}
</div>
<div class="form-group col-md-6">
{{ form_label(inscriptionForm.user_description) }}
{{ form_widget(inscriptionForm.user_description) }}
{{ form_errors(inscriptionForm.user_description) }}
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
{{ form_label(inscriptionForm.user_department) }}
{{ form_widget(inscriptionForm.user_department) }}
{{ form_errors(inscriptionForm.user_department) }}
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
{{ form_widget(inscriptionForm.submit) }}
</div>
</div>
{{ form_end(inscriptionForm) }}
和處理表單提交的控制器
<?php
namespace App\Controller;
use App\Entity\User;
use App\Form\Type\InscriptionType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
class InscriptionController extends AbstractController
{
/**
* @Route("/inscription", name="inscription")
*/
public function inscriptionAction(Request $request)
{
$user = new User();
// Creation du formulaire d'inscription
$inscriptionForm = $this->createForm(InscriptionType::class, $user);
// Si requete en POST et formulaire soumit
if ($request->isMethod('POST')) {
error_log('Formulaire inscription soumis');
// On indique au formulaire de prendre en charge le contenu de la requete
// Il va mapper les different champs soumis avec le contenu de l entite $user
$inscriptionForm->handleRequest($request);
if ($inscriptionForm->isSubmitted() && $inscriptionForm->isValid()) {
error_log("Formulaire inscription ok, sauvegarde de l'inscription");
}
}
// Affichage
return $this->render('inscription.html.twig', array(
'inscriptionForm' => $inscriptionForm->createView(),
'errors' => (isset($errors) ? $errors : ''),
));
}
}
也許您不應該使用 getUsername 返回您的電子郵件
public function getUsername(): string
{
return (string) $this->email;
}
而你 setUserName 的 setter 設置了 $this->user_name,和 email 不一樣。
public function setUserName(string $user_name): self
{
$this->user_name = $user_name;
return $this;
}
函數 getUsername 在 UserInterface 中設置。
當RequestHandler
處理請求時,它會將空值轉換為null
並且由於您的字段不可為 null,因此綁定失敗。 您可以將empty_data
設置為空字符串 ( 'empty_data' => '',
) 來解決這個問題。
至於生日,你可以設置今天的日期,但這會導致數據造假。 老實說,我寧願將該字段設為可選。
查看實體,您的任何 setter 都不接受空值。 這是解決問題的另一種方法,將它們全部設置為接受null
。 例如,將birthday
設置器更改為:
public function setUserBirthdate(?\DateTimeInterface $user_birthdate): self
然后表單將觸發驗證約束。 請注意,不使用表單的其他上下文可能會使您的實體處於無效狀態,您可能需要考慮收緊架構以避免不一致的數據,將約束移動到實體以便您可以觸發實體驗證或使用 DTO。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.