11

我正在使用 Symfony 2.0.16

我的 UserProvider 中有 getRoles 方法

public function getRoles()
{
    /**
     * @var \Doctrine\Common\Collections\ArrayCollection $rol
     */
    return $this->rol->toArray();
}

我的角色实体有角色界面

class Rol implements \Symfony\Component\Security\Core\Role\RoleInterface
//...
public function getRole()
{
    return $this->getName();
}

但是当我尝试登录时出现以下错误

致命错误:在第 57 行调用 C:\Users\julian\Code\parqueadero\vendor\symfony\src\Symfony\Bundle\SecurityBundle\DataCollector\SecurityDataCollector.php 中非对象的成员函数 getRole()

读取类SecurityDataCollector,错误是由一个闭包引发的

array_map(function ($role){ return $role->getRole();}, $token->getRoles()

现在我把它改成

array_map(function ($role){ var_dump($role); return $role->getRole();}, $token->getRoles()

令我惊讶的是,$role是一个对象 Rol 但我不明白为什么会出现错误。

4

3 回答 3

14

我发现解决方案问题是PHP 5.4(我正在使用的php)序列化方法中的一个错误github用户yoannch提出了这个解决方案serialize/unserialize,是使用方法覆盖json_encode/json_decode方法

class User implements \Serializable

//...

/**
 * Serializes the content of the current User object
 * @return string
 */
public function serialize()
{
    return \json_encode(
            array($this->username, $this->password, $this->salt,
                    $this->rol, $this->id));
}

/**
 * Unserializes the given string in the current User object
 * @param serialized
 */
public function unserialize($serialized)
{
    list($this->username, $this->password, $this->salt,
                    $this->rol, $this->id) = \json_decode(
            $serialized);
}

只需要更改正确的名称属性

于 2012-09-03T17:56:18.637 回答
11

我有同样的问题(Windows,PHP 5.4.5),更新到 5.4.7,但它仍然没有工作。尽管如此,我想出了一个需要较少维护的解决方法(当覆盖您提到的文章中描述的序列化函数时,您必须在添加/删除字段时使它们保持最新)。到目前为止它对我有用,我希望我可能忘记的解决方法不会导致其他问题。只需像这样更改用户的getRoles()功能:

/**
 * @inheritDoc
 */
public function getRoles()
{
    $roles = array();
    foreach ($this->userRoles as $role) {
        $roles[] = $role->getRole();
    }

    return $roles;
}

请注意,$role->getRole()将角色名称作为字符串返回(例如ROLE_ADMIN)。

于 2012-09-26T15:54:14.660 回答
6

这个问题的解决方法很简单。User与您和Role对象的循环引用相关的所有问题。所以你不必序列化User::$rolesRole::$users字段。

Symfony\Component\Security\Core\Authentication\Token\AbstractToken::__construct()Symfony\Component\Security\Core\Authentication\Token\AbstractToken::serialize()

你怎么看,Symfony 通过UserInterface::getRoles()在序列化之前调用来扮演你用户的角色。User并分别序列化Roles

您必须在和实体中实现\Serializable接口。UserRole

例子:

/**
 * Acme\Bundle\UserBundle\Entity\User
 * 
 * @ORM\Table(name="`user`")
 * @ORM\Entity(repositoryClass="Acme\Bundle\UserBundle\Entity\UserRepository")
 */
class User implements AdvancedUserInterface, EquatableInterface, \Serializable
{
    /**
     * @var integer $id
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

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

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

    /**
     * @var string $salt
     *
     * @ORM\Column(type="string", length=40)
     */
    private $salt;

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

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

    /**
     * User's roles. (Owning Side)
     * 
     * @var ArrayCollection
     * 
     * @ORM\ManyToMany(targetEntity="Role", inversedBy="users")
     */
    private $roles;

    // .....

    /**
     * @see \Serializable::serialize()
     */
    public function serialize()
    {
        /*
         * ! Don't serialize $roles field !
         */
        return \serialize(array(
            $this->id,
            $this->username,
            $this->email,
            $this->salt,
            $this->password,
            $this->isActive
        ));
    }

    /**
     * @see \Serializable::unserialize()
     */
    public function unserialize($serialized)
    {
        list (
            $this->id,
            $this->username,
            $this->email,
            $this->salt,
            $this->password,
            $this->isActive
        ) = \unserialize($serialized);
    }

}
/**
 * Acme\Bundle\UserBundle\Entity\Role
 *
 * @ORM\Table(name="role")
 * @ORM\Entity
 * 
 */
class Role implements RoleInterface, \Serializable
{
    /**
     * @var integer $id
     *
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string $role
     *
     * @ORM\Column(name="role", type="string", length=20, unique=true)
     */
    private $role;

    /**
     * Users in group (Inverse Side)
     * 
     * @var ArrayCollection
     * 
     * @ORM\ManyToMany(targetEntity="User", mappedBy="roles")
     */
    private $users;

    // .....    

    /**
     * @see \Serializable::serialize()
     */
    public function serialize()
    {
        /*
         * ! Don't serialize $users field !
         */
        return \serialize(array(
            $this->id,
            $this->role
        ));
    }

    /**
     * @see \Serializable::unserialize()
     */
    public function unserialize($serialized)
    {
        list(
            $this->id,
            $this->role
        ) = \unserialize($serialized);
    }
}

并且所有内容都将正确序列化/反序列化。

请参阅https://github.com/symfony/symfony/issues/3691上的铁饼

另见: http ://docs.doctrine-project.org/projects/doctrine-orm/en/latest/cookbook/entities-in-session.html#serializing-entity-into-the-session

于 2012-11-06T17:01:05.050 回答