つまり、投票者は好きなだけ再利用できます。たとえば、投票者はインターフェースに対して機能します。
ただし、ほんの数行のコードを節約するためだけに、ボーターを使用してあまりにも多くのことを判断するべきではありません。おそらく、有権者が派生クラスではないオブジェクトのセットを判断できる場合、それらには共通点があります。これは、インターフェイスとトレイトに適した場所です。したがって、有権者はそのインターフェースに対して作業する必要があります。それが、契約を結ぶためのインターフェースです。
将来的にクラスの配列がある場合はsupportsClass
、そのうちの1つで何かを変更します。そのクラスの Voter を壊すかもしれませんが、インターフェイスによってバインドされていないため、静的解析や PHP インタープリターはそれをキャッチしません。そして、それはかなりの問題です。
ご覧Voter
のとおり、3 つのパーツから構築されています。
Voter
特定のクラスのオブジェクトについて決定できるかどうかを Symfony に伝えるsupportsClass 。
Voter
このアクションについて決定できるかどうかを Symfony に伝えるsupportsAttribute 。
- 投票渡されたオブジェクトに基づいて、yes/no/dunno かどうかを決定します
これは正確には機能しません。しかし、有権者が何のためにそこにいるのかを理解できるはずです。
君は:
//You in controller
if (!$this->get('security.context')->isGranted('edit', $object)) {
throw new AuthenticationException('Not a step furher chap!');
}
フレームワーク:
//security.context
//again it is rough idea what it does for real implementation check Symfoy github
public function isGranted($action, $object) {
//There it goes trough all voters from all bundles!
foreach ($this->voters as $voter) {
if (!$voter->supportsClass(get_class($object))) {
//this voter doesn't care about this object
continue;
}
if (!$voter->supportsAttribute($action)) {
//this voter does care about this object but not about this action on it
continue;
}
//This voter is there to handle this object and action, so lest se what it has to say about it
$answer = $voter->vote(..);
...some more logic
}
}
私の頭の上からの奇妙な例:
interface Owneable {
public function getOwnerId();
}
trait Owned {
/**
* @ORM....
*/
protected $ownerId;
public function getOwnerId() {
return $this->ownerId;
}
public function setOwnerId($id) {
$this->ownerId = $id;
}
}
class Post implements Owneable {
use Owned;
}
class Comment implements Owneable {
use Owned;
}
class OwnedVoter implements VoterInterface
{
public function supportsAttribute($attribute)
{
return $attribute === 'edit';
}
public function supportsClass($class)
{
//same as return is_subclass_of($class, 'Owneable');
$interfaces = class_implements($class);
return in_array('Owneable' , $interfaces);
}
public function vote(TokenInterface $token, $ownedObject, array $attributes)
{
if (!$this->supportsClass(get_class($ownedObject))) {
return VoterInterface::ACCESS_ABSTAIN;
}
if (!$this->supportsAttribute($attributes[0])) {
return VoterInterface::ACCESS_ABSTAIN;
}
$user = $token->getUser();
if (!$user instanceof UserInterface) {
return VoterInterface::ACCESS_DENIED;
}
$userOwnsObject = $user->getId() === $ownedObject->getOwnerId();
if ($userOwnsObject) {
return VoterInterface::ACCESS_GRANTED;
}
return VoterInterface::ACCESS_DENIED;
}
}
ヒント: Voter は他のものと同じように単なるクラスです。継承や抽象クラスなどもここで機能します!
ヒント 2: 有権者は、あなたが渡すことができるサービスsecurity.context
またはその他のサービスとして登録されています。そのため、コードをかなりうまく再利用できます