You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Symfony头像上传报错:password参数应为string却传入null

问题解决方案

核心问题分析

你遇到两个关键问题:

  1. 密码字段提交时抛出Expected argument of type "string", "null" given错误
  2. 头像文件未存储到服务器,文件名也未写入数据库

问题1:密码字段错误原因

  • UserType中重复定义了两次password字段,第二次的RepeatedType设置了required=true
  • 头像上传页面隐藏了密码输入框,提交时密码字段返回null,但hashPassword方法要求传入字符串类型参数
  • 编辑场景下密码不应强制必填,仅注册时需要

问题2:文件上传失败原因

  • 表单未设置enctype="multipart/form-data",导致文件数据无法正确传递到后端
  • 密码错误导致表单验证不通过,文件上传逻辑未被执行

分步修复方案

1. 清理并优化表单密码字段

修改UserType.php,移除重复的密码字段,添加动态控制必填性的选项:

<?php

namespace App\Form;

use App\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\CountryType;
use Symfony\Component\Form\Extension\Core\Type\BirthdayType;
use Symfony\Component\Form\Extension\Core\Type\LanguageType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;

class UserType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('gender', ChoiceType::class, [
                'choices' => [
                    'Je suis ...' => '',
                    'un homme' => 'male',
                    'une femme' =>'female',
                    'non-binaire' => 'non-binary'
                ]
            ])
            ->add('lastname')
            ->add('firstname')
            ->add('birthdate', BirthdayType::class, [
                'placeholder' => [
                    'year' => 'Année', 'month' => 'Mois', 'day' => 'Jour',
                ],
                'choice_translation_domain' => true
            ])
            ->add('occupation')
            ->add('nationality', CountryType::class, [
                'placeholder' => 'Je choisis un pays',
            ])
            ->add('nativelanguage', LanguageType::class, [
                'placeholder' => 'Je choisis ta langue maternelle',
            ])
            ->add('email')
            // 移除重复的PasswordType字段,保留RepeatedType
            ->add('password', RepeatedType::class, [
                'type' => PasswordType::class,
                'invalid_message' => 'Les deux mots de passe doivent être identiques.',
                'options' => ['attr' => ['class' => 'password-field']],
                // 根据动态选项控制是否必填
                'required' => $options['require_password'],
                'first_options'  => ['label' => 'Password'],
                'second_options' => ['label' => 'Repeat Password'],
                'empty_data' => ''
            ])
            ->add('photo', FileType::class, [
                'mapped' => false,
                'required' => false, // 头像上传非必填
            ])
            ->add('save', SubmitType::class, [
                'attr' => ['class' => 'save'],
            ]);
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => User::class,
            'translation_domain' => 'forms',
            // 默认注册场景必填密码
            'require_password' => true
        ]);
        $resolver->setAllowedTypes('require_password', 'bool');
    }
}

2. 修改头像上传控制器

在UserController.php的addPhoto方法中,创建表单时设置密码非必填:

#[Route('/profile', name: 'profile')]
public function addPhoto(
    Request $request,
    UserRepository $userRepository,
    SluggerInterface $sluggerInterface,
    EntityManagerInterface $entityManagerInterface
){
    $connected = $this->getUser();
    $useremail = $connected->getUserIdentifier();
    $user = $userRepository->findOneBy(['email' => $useremail]);

    // 设置密码非必填
    $userform = $this->createForm(UserType::class, $user, [
        'require_password' => false
    ]);
    $userform->handleRequest($request);

    if ($userform->isSubmitted() && $userform->isValid()) {
        $imagefile = $userform->get('photo')->getData();

        if ($imagefile){
            $originalFileName = pathinfo($imagefile->getClientOriginalName(), PATHINFO_FILENAME);
            $safeFileName = $sluggerInterface->slug($originalFileName);
            $newFileName = $safeFileName . '-' . uniqid() . '.' . $imagefile->guessExtension();

            $imagefile->move(
                $this->getParameter('images_directory'),
                $newFileName
            );

            $user->setPhoto($newFileName);
        }

        $entityManagerInterface->persist($user);
        $entityManagerInterface->flush();
        return $this->redirectToRoute('login');
    }

    return $this->renderForm('security/login.html.twig', [
        'user' => $user,
        'form' => $userform,
    ]);
}

3. 优化用户编辑控制器

修改updateUser方法,仅当密码字段不为空时才更新密码:

#[Route('/update', name: 'update')]
public function updateUser(
    Request $request,
    UserRepository $userRepository,
    EntityManagerInterface $entityManagerInterface,
    UserPasswordHasherInterface $userPasswordHasherInterface
){
    $connected = $this->getUser();
    $useremail = $connected->getUserIdentifier();
    $user = $userRepository->findOneBy(['email' => $useremail]);

    // 设置密码非必填
    $userform = $this->createForm(UserType::class, $user, [
        'require_password' => false
    ]);
    $userform->handleRequest($request);

    if ($userform->isSubmitted() && $userform->isValid()) {

        $plainPassword = $userform->get('password')->getData();
        // 仅当输入密码时才更新
        if (!empty($plainPassword)) {
            $hashedPassword = $userPasswordHasherInterface->hashPassword($user, $plainPassword);
            $user->setPassword($hashedPassword);
        }

        $entityManagerInterface->persist($user);
        $entityManagerInterface->flush();
        return $this->redirectToRoute('home');
    }

    return $this->renderForm('front/edituser.html.twig', [
        'user' => $user,
        'form' => $userform,
    ]);
}

4. 修复表单文件上传编码

修改login.html.twig,添加multipart/form-data编码类型:

{% block body %}

{% if app.user %}

{{ form_start(form, {
    'attr' : {'class' : 'position-absolute top-50 start-50 translate-middle'},
    'enctype': 'multipart/form-data'
} )  }}
    {{ form_widget(form.photo, {'attr' : {'onChange' : 'this.form.submit();'}} ) }}
    {{ form_widget(form.gender, {'attr' : {'class' : 'd-none'}}) }}
    {{ form_widget(form.lastname, {'attr' : {'class' : 'd-none'}}) }}
    {{ form_widget(form.firstname, {'attr' : {'class' : 'd-none'}}) }}
    {{ form_widget(form.birthdate, {'attr' : {'class' : 'd-none'}}) }}
    {{ form_widget(form.occupation, {'attr' : {'class' : 'd-none'}}) }}
    {{ form_widget(form.nationality, {'attr' : {'class' : 'd-none'}}) }}
    {{ form_widget(form.nativelanguage, {'attr' : {'class' : 'd-none'}}) }}
    {{ form_widget(form.email, {'attr' : {'class' : 'd-none'}}) }}
    {{ form_widget(form.password.first, {'attr' : {'class' : 'd-none'}}) }}
    {{ form_widget(form.password.second, {'attr' : {'class' : 'd-none'}}) }}
    {{ form_widget(form.save, {'attr' : {'class' : 'd-none'}}) }}
{{ form_end(form) }}

{% endif %}

{% endblock %}

内容的提问来源于stack exchange,提问作者Emilie Tossan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 20:10:45