对许多实体使用一类选民 [英] Using one class Voter for many entities

查看:82
本文介绍了对许多实体使用一类选民的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是类Voter中的功能 supportsClass

This is the function supportsClass in class Voter

http://symfony.com/doc/2.5/cookbook/security/选民_data_permission.html

 public function supportsClass($class)
{
    $supportedClass = 'AppBundle\Entity\Post';

    return $supportedClass === $class || is_subclass_of($class, $supportedClass);
}

我想知道是否可以对同一捆绑中的许多实体使用一个类投票器,或者我必须为每个实体创建一个选民吗?

I'd like to know if it is possible to use one class voter for many entities in the same bundle or I have to create a Voter for each entity ?

编辑 我找到了这个解决方案:

EDIT I have found this solution:

 public function supportsClass($class)
{
    $classes = array(
        'Project\AgenceBundle\Entity\Agence',
        'Project\AgenceBundle\Entity\SubAgence',
        'Project\AgenceBundle\Entity\Subscription'
    );
    $ok = false;
    foreach($classes as $supportedClass)
    $ok = $ok || $supportedClass === $class || is_subclass_of($class, $supportedClass);

    return $ok;
}

推荐答案

总之,您可以根据需要重复使用Voter.例如,您的选民可以针对界面进行操作.

In short yes, you can reuse your Voter as much as you want. For example your voter can work against interface.

但是,您不应该使用选民来判断太多事情,而只是节省几行代码.选民是否可以判断不是派生类的某些对象集,但是它们有一些共同点.这反过来又是实现界面和特性​​的好地方.因此,选民应针对该接口进行工作. 多数民众赞成在什么接口,给你合同.

However you shouldn't use voter to judge too many things just to save few lines of code. Probably if voter can judge some set of objects that are not derivate class but they have something in common. Which in turn is good place for interface and trait. And so voter should work against that interface. Thats what interfaces are there for, to give you contract.

如果您在supportsClass中有多个类数组,那么将来您可以在其中之一中更改某些内容.您可能会破坏该类的Voter,但是由于它不受接口的限制,因此没有静态分析或PHP解释器都可以捕获它.那是一个很大的问题.

If you have array of classes in supportsClass and than in future you change something in one of them. You might break Voter for that class, but since it is not bound by interface, no static analysis or PHP interpretr will catch it. And that is quite a problem.

如您所见,Voter由三部分组成.

As you can see Voter is build from 3 parts.

  • supportsClass ,它告诉Symfony此Voter是否可以决定某个类的对象.
  • supportsAttribute ,它告诉Symfony此Voter是否可以决定此操作.
  • 投票基于传递的对象,它决定是/否/不知道
  • supportsClass which tells Symfony whether this Voter can decide about objects of certain class.
  • supportsAttribute which tells Symfony whether this Voter can decide about this action.
  • vote Based on passed object it decides if it yes/no/dunno

这是不完全的工作方式.但这应该使您知道选民的用途.

This is not exactly how it works. But it should give you idea what it is voter is there for.

您:

//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和其他任何类一样都是类,继承和抽象类之类的东西也可以在这里工作!

TIP: Voter is just class as any other, things like inheritance and abstract class work here too!

提示2:选民已注册为服务,您可以将security.context或任何其他服务传递给它.这样您就可以很好地重用您的代码

TIP2: Voter is registered as service you can pass security.context or any other service to it. So you can reuse your code pretty well

这篇关于对许多实体使用一类选民的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆