Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/267.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 对多个实体使用一个类投票者_Php_Symfony_Symfony Security - Fatal编程技术网

Php 对多个实体使用一个类投票者

Php 对多个实体使用一个类投票者,php,symfony,symfony-security,Php,Symfony,Symfony Security,这是类中的函数supportsClass 我想知道是否可以对同一捆绑包中的多个实体使用一个类投票者,或者我必须为每个实体创建一个投票者 编辑 我找到了这个解决方案: public function supportsClass($class) { $classes = array( 'Project\AgenceBundle\Entity\Agence', 'Project\AgenceBundle\Entity\SubAgence',

这是类中的函数supportsClass

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

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

 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来判断太多的事情。也许选民可以判断一些不是派生类但有共同点的对象集。这反过来又是界面和特质的好地方。所以选民应该反对这种接口。 这就是接口的作用,给你合同

如果您在
supportsClass
中有一个类数组,并且以后您可以更改其中一个类中的某些内容。您可能会破坏该类的投票者,但因为它不受接口的约束,所以静态分析或PHP解释器都不会捕获它。这是一个相当大的问题

如您所见,
Voter
由3个部分组成

  • supportsClass告诉Symfony这个
    投票者是否可以决定特定类的对象
  • supportsAttribute告诉Symfony此
    投票者是否可以决定此操作
  • 投票根据通过的对象,决定是否为是/否/不确定
这不完全是它的工作原理。但它应该会让你知道它是为了什么

你:

框架:

//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;
    }
}
提示:投票者和其他任何东西一样都是类,继承和抽象类在这里也起作用


提示2:投票者已注册为服务,您可以向其传递
security.context
或任何其他服务。因此,您可以很好地重用代码

是的,正如您在@Jindra answer中看到的那样,但只对具有共同点并通过接口表达这一点的类执行此操作。不要为一堆不同的实体创建一个投票者类,并处理大量的ifs和开关。嗨,删除此函数中的所有对齐,然后用
return true替换它怎么样。这几乎使整个投票系统毫无用处。投票者允许您为特定对象编写可重用逻辑。您应该拥有应用程序逻辑所需的投票者数量。也许你可以告诉我们你想做什么。可能有更好的东西适合您的用例。像ACL.Hi,@Jindra:我有一些实体与实体用户相关,我只想保护它们,用户只能删除和编辑自己的实体。我已经编辑了我的问题,你发现的想法和我写的答案差不多。我已经编辑了我的答案以提供更多信息。您好,删除此函数中的所有对齐方式并将其替换为
return true
//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;
    }
}