Symfony 2.8 - ChoiceType需要字符串,但登录需要角色为数组

时间:2018-04-30 08:13:48

标签: php arrays string symfony symfony-2.8

的信息: 我在发布之前进行了搜索,并尝试了建议的解决方案,所有这些都让我回到问题a或b,如下所述。因此虽然这可能看起来像重复,但迄今为止没有其他答案帮我解决了这个问题。

此外,我用MyApp替换了真实的捆绑名称。

问题: 我试图让Symfony应用程序正常运行。我按照Symfony 2.8文档创建了一个数据库和表,登录过程正常。在我添加表单以创建新用户后,我遇到了ChoiceType和我的登录页面的错误。

具体来说,当我在getRoles()中将return array($this->roles);设置为Entity/User.php时,登录正常,但我在创建用户表单中收到以下错误。

GET / admin /具有多个=> false的用户(访问页面)

Notice: Array to string conversion
500 Internal Server Error - ContextErrorException
Stack Trace

    in vendor/symfony/symfony/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php at line 79  -
                if (null === $value && $this->castableToString($choices)) {
                    $value = function ($choice) {
                        return false === $choice ? '0' : (string) $choice;
                    };
                }
    at ErrorHandler ->handleError ('8', 'Array to string conversion', '/home/dev/MyApp/vendor/symfony/symfony/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php', '79', array('choice' => array(null)))
    in vendor/symfony/symfony/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php at line 79  +
    at ArrayChoiceList ->Symfony\Component\Form\ChoiceList\{closure} (array(null))
    at call_user_func (object(Closure), array(null))
    in vendor/symfony/symfony/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php at line 164  +
    at ArrayChoiceList ->getValuesForChoices (array(array(null)))
    in vendor/symfony/symfony/src/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToValueTransformer.php at line 32  +
    at ChoiceToValueTransformer ->transform (array(null))
    in vendor/symfony/symfony/src/Symfony/Component/Form/Form.php at line 1156  +
    at Form ->normToView (array(null))
    in vendor/symfony/symfony/src/Symfony/Component/Form/Form.php at line 351  +
    at Form ->setData (array(null))
    in vendor/symfony/symfony/src/Symfony/Component/Form/Extension/Core/DataMapper/PropertyPathMapper.php at line 49  +
    at PropertyPathMapper ->mapDataToForms (object(User), object(RecursiveIteratorIterator))
    in vendor/symfony/symfony/src/Symfony/Component/Form/Form.php at line 384  +
    at Form ->setData (object(User))
    in vendor/symfony/symfony/src/Symfony/Component/Form/Form.php at line 488  +
    at Form ->initialize ()
    in vendor/symfony/symfony/src/Symfony/Component/Form/FormBuilder.php at line 226  +
    at FormBuilder ->getForm ()
    in vendor/symfony/symfony/src/Symfony/Component/Form/FormFactory.php at line 33  +
    at FormFactory ->create ('MyAppBundle\Form\UserType', object(User), array())
    in vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php at line 282  +
    at Controller ->createForm ('MyAppBundle\Form\UserType', object(User))
    in src/MyAppBundle/Controller/AdminController.php at line 214  +
    at AdminController ->adminUsersAction (object(Request))
    in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php at line 135  +
    at HttpKernel ->handleRaw (object(Request), '1')
    in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php at line 57  +
    at HttpKernel ->handle (object(Request), '1', true)
    in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/DependencyInjection/ContainerAwareHttpKernel.php at line 67  +
    at ContainerAwareHttpKernel ->handle (object(Request), '1', true)
    in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Kernel.php at line 183  +
    at Kernel ->handle (object(Request))
    in web/app_dev.php at line 30  +
    at require ('/home/dev/MyApp/web/app_dev.php')
    in vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Resources/config/router_dev.php at line 40  +

我尝试按照某些答案中的建议设置multiple=>true(即使我不想要多选)。这解决了渲染错误,但表单提交中也出现了相同的错误。

使用/admin/users 发布到multiple=>true(提交用户表单)

Notice: Array to string conversion
500 Internal Server Error - ContextErrorException
Stack Trace

    in vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php at line 67  -
            public function bindValue($param, $value, $type = \PDO::PARAM_STR)
            {
                try {
                    return parent::bindValue($param, $value, $type);
                } catch (\PDOException $exception) {
                    throw new PDOException($exception);
                }
    at ErrorHandler ->handleError ('8', 'Array to string conversion', '/home/dev/MyApp/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php', '67', array('param' => '5', 'value' => array('ROLE_USER'), 'type' => '2'))
    at PDOStatement ->bindValue ('5', array('ROLE_USER'), '2')
    in vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php at line 67  +
    at PDOStatement ->bindValue ('5', array('ROLE_USER'), '2')
    in vendor/doctrine/dbal/lib/Doctrine/DBAL/Statement.php at line 120  +
    at Statement ->bindValue ('5', array('ROLE_USER'), object(StringType))
    in vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php at line 277  +
    at BasicEntityPersister ->executeInserts ()
    in vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php at line 1014  +
    at UnitOfWork ->executeInserts (object(ClassMetadata))
    in vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php at line 378  +
    at UnitOfWork ->commit (null)
    in vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php at line 356  +
    at EntityManager ->flush ()
    in src/MyAppBundle/Controller/AdminController.php at line 228  +
    at AdminController ->adminUsersAction (object(Request))
    in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php at line 135  +
    at HttpKernel ->handleRaw (object(Request), '1')
    in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php at line 57  +
    at HttpKernel ->handle (object(Request), '1', true)
    in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/DependencyInjection/ContainerAwareHttpKernel.php at line 67  +
    at ContainerAwareHttpKernel ->handle (object(Request), '1', true)
    in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Kernel.php at line 183  +
    at Kernel ->handle (object(Request))
    in web/app_dev.php at line 30  +
    at require ('/home/dev/MyApp/web/app_dev.php')
    in vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Resources/config/router_dev.php at line 40  +

getRoles()更改为return $this->roles;确实解决了呈现和发布问题,但导致登录功能出现相反的问题。

登录请求/login

Type error: Argument 4 passed to Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken::__construct() must be of the type array, string given, called in /home/dev/MyApp/vendor/symfony/security/Core/Authentication/Provider/UserAuthenticationProvider.php on line 96
500 Internal Server Error - FatalThrowableError
Stack Trace

    in vendor/symfony/security/Core/Authentication/Token/UsernamePasswordToken.php at line 36  -
            *
            * @throws \InvalidArgumentException
            */
            public function __construct($user, $credentials, $providerKey, array $roles = array())
            {
                parent::__construct($roles);
    at UsernamePasswordToken ->__construct (object(User), 'test', 'main', 'ROLE_USER')
    in vendor/symfony/security/Core/Authentication/Provider/UserAuthenticationProvider.php at line 96  +
    at UserAuthenticationProvider ->authenticate (object(UsernamePasswordToken))
    in app/cache/dev/classes.php at line 2749  +
    at AuthenticationProviderManager ->authenticate (object(UsernamePasswordToken))
    in vendor/symfony/security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php at line 93  +
    at UsernamePasswordFormAuthenticationListener ->attemptAuthentication (object(Request))
    in vendor/symfony/security/Http/Firewall/AbstractAuthenticationListener.php at line 146  +
    at AbstractAuthenticationListener ->handle (object(GetResponseEvent))
    in app/cache/dev/classes.php at line 2664  +
    at Firewall ->onKernelRequest (object(GetResponseEvent), 'kernel.request', object(TraceableEventDispatcher))
    at call_user_func (array(object(Firewall), 'onKernelRequest'), object(GetResponseEvent), 'kernel.request', object(TraceableEventDispatcher))
    in vendor/symfony/symfony/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php at line 61  +
    at WrappedListener ->__invoke (object(GetResponseEvent), 'kernel.request', object(ContainerAwareEventDispatcher))
    at call_user_func (object(WrappedListener), object(GetResponseEvent), 'kernel.request', object(ContainerAwareEventDispatcher))
    in app/cache/dev/classes.php at line 1888  +
    at EventDispatcher ->doDispatch (array(object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener)), 'kernel.request', object(GetResponseEvent))
    in app/cache/dev/classes.php at line 1803  +
    at EventDispatcher ->dispatch ('kernel.request', object(GetResponseEvent))
    in vendor/symfony/symfony/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php at line 133  +
    at TraceableEventDispatcher ->dispatch ('kernel.request', object(GetResponseEvent))
    in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php at line 116  +
    at HttpKernel ->handleRaw (object(Request), '1')
    in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php at line 57  +
    at HttpKernel ->handle (object(Request), '1', true)
    in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/DependencyInjection/ContainerAwareHttpKernel.php at line 67  +
    at ContainerAwareHttpKernel ->handle (object(Request), '1', true)
    in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Kernel.php at line 183  +
    at Kernel ->handle (object(Request))
    in web/app_dev.php at line 30  +
    at require ('/home/dev/MyApp/web/app_dev.php')
    in vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Resources/config/router_dev.php at line 40  +

如何处理用户表单和登录中的一系列角色,以便两者都满足$roles的格式?

源代码供参考。

窗体/ UserType.php

[...]
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('email', EmailType::class)
        ->add('username', TextType::class)
        ->add('roles', ChoiceType::class, array(
            'multiple' => true,
            'expanded' => false,
            'choices'  => array(
                'User' => 'ROLE_USER',
                'Admin' => 'ROLE_ADMIN'),
            'choices_as_values' => true,
        ))
        ->add('plainPassword', RepeatedType::class, array(
            'type' => PasswordType::class,
            'first_options'  => array('label' => 'Password'),
            'second_options' => array('label' => 'Repeat Password'),
        )
    );
}

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => 'MyAppBundle\Entity\User',
    ));
}
[...]

实体/ user.php的

[...]
/**
* @ORM\Table(name="app_users")
* @ORM\Entity(repositoryClass="MyAppBundle\Entity\UserRepository")
*/
class User implements UserInterface, \Serializable
{
    /**
    * @ORM\Column(type="integer")
    * @ORM\Id
    * @ORM\GeneratedValue(strategy="AUTO")
    */
    private $id;

    /**
    * @ORM\Column(type="string", length=25, unique=true)
    */
    private $username;

    /**
    * @ORM\Column(type="string", length=64)
    */
    private $password;

    /**
    * @ORM\Column(type="string", length=60, unique=true)
    */
    private $email;

    /**
    * @ORM\Column(name="is_active", type="boolean")
    */
    private $isActive;

    /**
    * @ORM\Column(name="roles", type="string")
    */
    private $roles;

    /**
    * @Assert\NotBlank()
    * @Assert\Length(max=4096)
    */
    private $plainPassword;


    public function __construct()
    {
        // default for new users
        $this->isActive = true;
        //$this->roles = "ROLE_USER";
    }
    [...]
    public function getRoles()
    {
        //return $this->roles;
        return array($this->roles);
    }

    /** @see \Serializable::serialize() */
    public function serialize()
    {
        return serialize(array(
            $this->id,
            $this->username,
            $this->password,
        ));
    }

    /** @see \Serializable::unserialize() */
    public function unserialize($serialized)
    {
        list (
            $this->id,
            $this->username,
            $this->password,
        ) = unserialize($serialized);
    }
    [...]
    /**
    * Set Roles
    *
    * @param string $roles
    *
    * @return User
    */
    public function setRoles($roles)
    {
        $this->roles = $roles;
        return $this;
    }
    [...]

控制器/ AdminController.php

/**
* @Route("/admin/users")
*/
public function adminUsersAction(Request $request)
{
    // 
    $repository = $this->getDoctrine()
        ->getRepository('MyAppBundle:User');

    $users = $repository->findAll();

    // USER FORM
    // 1) build the form
    $user = new User();
    $form = $this->createForm(UserType::class, $user);

    // 2) handle the submit (will only happen on POST)
    $form->handleRequest($request);
    if ($form->isSubmitted() && $form->isValid()) {

        // 3) Encode the password (you could also do this via Doctrine listener)
        $password = $this->get('security.password_encoder')
            ->encodePassword($user, $user->getPlainPassword());
        $user->setPassword($password);

        // 4) save the User!
        $em = $this->getDoctrine()->getManager();
        $em->persist($user);
        $em->flush();

        return $this->redirectToRoute('dashboard');
    }

    return $this->render(
        'MyAppBundle:Admin:users.html.twig',
        array(
            "form"=>$form->createView(),
            "users"=>$users
            )
    );
}

资源/视图/管理/ users.html.twig

<h2>Add Users</h2>
{{ form_start(form) }}
    {{ form_row(form.username) }}
    {{ form_row(form.email) }}
    {{ form_row(form.roles) }}
    {{ form_row(form.plainPassword.first) }}
    {{ form_row(form.plainPassword.second) }}
    <button type="submit">Add User</button>
{{ form_end(form) }}

1 个答案:

答案 0 :(得分:2)

看起来您的角色正在保存为字符串:

/**
* @ORM\Column(name="roles", type="string")
*/
private $roles;

这将存储文字字符串ROLE_USER而不是序列化数组a:1:{i:0;s:9:"ROLE_USER";}。尝试:

/**
* @ORM\Column(name="roles", type="array")
*/
private $roles;

setter应该从具有多个选择支持的ChoiceType中获取数组:

/**
* @param array $roles
* @return User
*/
public function setRoles($roles)
{
    $this->roles = $roles;
    return $this;
}

getter应该将属性作为数组返回,而不必手动将其转换为数组:

public function getRoles()
{
    return $this->roles;
}