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の間に関係を持つという要件を再考しますが、ここではおそらく十分です。何らかの関連マッピングに固執するかどうかに関係なく、クラスを永続化するときに、関連するロールも永続化されることを確認する必要があるでしょう。そのためには、次のようにクラスに命令を追加する必要がある場合があります。@ManyToOneUsercascadeUser
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 対多の関係を持つことができます。RoleUserUserRole
- アソシエーション クラス
UserRole(またはそれを何と呼ぶか) には、主キー ( id) と 2 つの多対 1 の関係 (1 つは 用、Userもう 1 つは 用) が必要Roleです。
Roleクラスと の間に逆の関係を作成する必要はありません。これはUserRole、ロールが残りのエンティティから分離されているためです。
Role新しく作成したものに を割り当てる前にUser、最初にそれを調べる必要があります。それが見つかったら、あなたへの参照を使用して を作成しUserRole、それをクラスの一連のロールに追加できます。$user$roleUser
上記は、問題に対処する方法の大まかな概要です。さらに詳細に:
クラスは、アノテーションを介してエンティティ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_USERUserRoleUserRoleUser$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