RoleInterface выдает ошибку "вызвать не-объект"
Я работаю над Symfony 2.0.16
В моем UserProvider есть метод getRoles
public function getRoles()
{
/**
* @var \Doctrine\Common\Collections\ArrayCollection $rol
*/
return $this->rol->toArray();
}
и мой объект Rol имеет интерфейс ролей
class Rol implements \Symfony\Component\Security\Core\Role\RoleInterface
//...
public function getRole()
{
return $this->getName();
}
но когда я пытаюсь войти в систему, я получаю следующую ошибку:
Неустранимая ошибка: вызов функции-члена getRole() для не-объекта в C:\Users\julian\Code\parqueadero\vendor\symfony\src\Symfony\Bundle\SecurityBundle\DataCollector\SecurityDataCollector.php on line 57
Чтение класса SecurityDataCollector, ошибка вызывается закрытием
array_map(function ($role){ return $role->getRole();}, $token->getRoles()
Теперь я изменяю это на
array_map(function ($role){ var_dump($role); return $role->getRole();}, $token->getRoles()
К моему удивлению, $role
- это объект Rol, но Я не могу понять, почему я получаю ошибку.
Ответы
Ответ 1
Я нашел решение, проблема - ошибка в 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);
}
требуется изменить правильные свойства имени
Ответ 2
У меня была та же проблема (Windows, PHP 5.4.5), обновленная до 5.4.7, и она по-прежнему не работает. Тем не менее, я придумал обходное решение, которое требует меньшего обслуживания (при перезаписывании функций сериализации, как описано в упомянутой статье, вам нужно будет обновлять их при добавлении/удалении полей). Пока это работает для меня, я надеюсь, что нет никаких других проблем, связанных с обходным решением, которое я, возможно, забыл. Просто измените функцию User getRoles()
следующим образом:
/**
* @inheritDoc
*/
public function getRoles()
{
$roles = array();
foreach ($this->userRoles as $role) {
$roles[] = $role->getRole();
}
return $roles;
}
Обратите внимание, что $role->getRole()
возвращает имя роли в виде строки (например, ROLE_ADMIN
).
Ответ 3
решение этой задачи очень просто.
Все проблемы, связанные с циклическими ссылками на ваши объекты User
и Role
.
Таким образом, вы не должны сериализовать поля User::$roles
и Role::$users
.
Посмотрите Symfony\Component\Security\Core\Authentication\Token\AbstractToken::__construct()
и Symfony\Component\Security\Core\Authentication\Token\AbstractToken::serialize()
.
Как вы можете видеть, Symfony выполняет роли пользователя, вызывая UserInterface::getRoles()
перед сериализацией. И сериализуйте User
и Roles
отдельно.
Вам нужно реализовать интерфейс \Serializable
в объектах User
и Role
.
Пример:
/**
* 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 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);
}
}
И все будет правильно сериализовано/несертифицировано.
Смотрите discus на 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