AccountController のcreateAction
メソッドでは、実際にRole
ユーザーに a を割り当てることはありません。認証プロセスの一部として使用する前に、最初にそれを設定する必要があります。このようなものはRole
、上記のモデルを保持する必要があります。
if ($registrationForm->isValid()) {
...
$role = new Role();
$role->setName('User');
$role->setRole('ROLE_USER');
$roles = new \Doctrine\Common\Collections\ArrayCollection;
$roles->add($role);
$user->setRoles($roles);
...
}
また、 UserとRoles@ManyToMany
の間に関係を持つという要件を再考しますが、ここではおそらく十分です。何らかの関連マッピングに固執するかどうかに関係なく、クラスを永続化するときに、関連するロールも永続化されることを確認する必要があるでしょう。そのためには、次のようにクラスに命令を追加する必要がある場合があります。@ManyToOne
User
cascade
User
class User implements AdvancedUserInterface, \Serializable
{
...
/**
* @ORM\ManyToMany(targetEntity="Role", inversedBy="users", cascade={"all"})
*/
private $roles;
...
}
のデフォルトUser
クラスは、そのユーザー オブジェクトのロールのコレクションも使用するため、ロールを永続化すると、既存のUsernameAuthenticationProviderSymfony\Component\Security\Core\User
をそのまま使用できる場合があります。うまくいけば、すべてが機能します。そうでない場合は、認証プロバイダーをカスタマイズする必要がある場合があります。
上記では、メソッドで$roles
プロパティを明示的に割り当てていることに注意してください。setRoles()
これは、 の戻り値の型がではgetRoles()
なくArrayCollection
、プリミティブであるためarray
です。プリミティブ配列を返す Symfony の既存の認証プロバイダーですべてを「正常に動作」させたい場合getRoles()
は、私が知る限り正しいです。
同じ問題の新しい見方 (2013 年 11 月 10 日):
「私はあなたが書いたようにそれを行いましたが、役割タイプを保存する acme_roles テーブルに書き込もうとしています-管理者、ユーザー ....しかし、ユーザーの役割を user_roles テーブルに保存したい-そこにユーザー ID を保存しますおよびロールID "
チャットの拡張コメントであなたが何を望んでいるのかを考えると、私のアプローチは、ユーザーとロールの関係をモデル化するために 3 つのエンティティ/テーブルを使用することです。これは明らかに、問題にアプローチする唯一の方法です。
テーブルは次のようになります: acme_users
(User
エンティティ)、acme_roles
(Role
エンティティ)、およびacme_user_roles
(UserRole
エンティティ)。
- オブジェクト
User
と直接多対多の関係を持つことはできません。代わりに、とクラスの間に1 対多の関係を持つことができます。Role
User
UserRole
- アソシエーション クラス
UserRole
(またはそれを何と呼ぶか) には、主キー ( id
) と 2 つの多対 1 の関係 (1 つは 用、User
もう 1 つは 用) が必要Role
です。
Role
クラスと の間に逆の関係を作成する必要はありません。これはUserRole
、ロールが残りのエンティティから分離されているためです。
Role
新しく作成したものに を割り当てる前にUser
、最初にそれを調べる必要があります。それが見つかったら、あなたへの参照を使用して を作成しUserRole
、それをクラスの一連のロールに追加できます。$user
$role
User
上記は、問題に対処する方法の大まかな概要です。さらに詳細に:
クラスは、アノテーションを介してエンティティUser
との関係をマップする必要があります。たとえば、次のようになります。UserRole
@ORM\OneToMany
/**
* @ORM\OneToMany(targetEntity="UserRole", mappedBy="user", cascade={"all"})
*/
private $userRoles;
で、 に関連付けられた実際のロールを返すようにメソッドをUser
変更します。次のようになります。getRoles()
UserRoles
/**
* @inheritDoc
*/
public function getRoles()
{
$roles = array();
foreach ($this->userRoles as $userRole) {
$roles[] = $userRole->getRole();
}
return $roles;
}
クラスに, (および場合によっては) メソッドUser
を追加し、削除します。getUserRoles()
setUserRoles()
addUserRole()
setRoles()
ではUserRole
、ID ではなくエンティティ参照を保存する必要があるため (Doctrine により、それらは任意の方法で列の ID としてマップされます)、$user_id
と$role_id
をそれぞれ に変更し、それらのマッピングを変更します (また、複数のロールを割り当て可能にする場合$user
)関連付け$role
を介しUserRole
て、個別の ID/主キーが必要になるため、次のように$id
プロパティを追加します。
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity="User", inversedBy="userRoles", cascade={"all"})
*/
private $user;
/**
* @ORM\ManyToOne(targetEntity="Role", cascade={"all"})
*/
private $role;
クラスから へのすべての参照を削除し$users
ますRole
。
で、割り当てる役割をルックアップし (つまり、ルックアップに適切な対応する役割AccoundController
を割り当てたい場合)、それをに割り当て、次に を に割り当て、最後に を永続化します。例:ROLE_USER
UserRole
UserRole
User
$user
$user = $registration->getUser();
$user->setSalt($this->generateSalt());
$user->setIsActive(1);
$factory = $this->get('security.encoder_factory');
$encoder = $factory->getEncoder($user);
$password = $encoder->encodePassword($user->getPassword(), $user->getSalt());
$user->setPassword($password);
$role = $this->getDoctrine()
->getRepository('AcmeAccountBundle:Role')
->find(2); // Finds "ROLE_USER"
$userRole = new UserRole();
$userRole->setRole($role);
$user->addUserRole($userRole);
$em->persist($user);
$em->flush();
スキーマを必ず再生成してください。これを行う最も簡単な方法は、次を実行することです。
$ php app/console doctrine:database:drop --force
$ php app/console doctrine:database:create
$ php app/console doctrine:schema:drop --force
$ php app/console doctrine:schema:create
$ php app/console doctrine:schema:validate