feature #14001 [2.7] [Security] [ACL] Improved MaskBuilder and PermissionMap (AlexDpy)

This PR was merged into the 2.7 branch.

Discussion
----------

[2.7] [Security] [ACL] Improved MaskBuilder and PermissionMap

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets |  #13566
| License       | MIT
| Doc PR        | I'll do it if needed

This PR refers to #13697 . The previous PR introduced a BC break, so i provide this one which is backward compatible.

The MaskBuilderRetrievalInterface::getMaskBuilder methods allows us to retrieve a new instance of the MaskBuilder used in our application, even if it's a custom one.
I also added a MaskBuilderInterface and an AbstractMaskBuilder which can be a great helper.

Commits
-------

3d79d8b added MaskBuilderRetrievalInterface
89a1f2a improved MaskBuilder
This commit is contained in:
Fabien Potencier 2015-03-21 18:50:37 +01:00
commit a3dc823983
6 changed files with 199 additions and 75 deletions

View File

@ -0,0 +1,85 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Permission;
/**
* This abstract class implements nearly all the MaskBuilderInterface methods
*/
abstract class AbstractMaskBuilder implements MaskBuilderInterface
{
/**
* @var int
*/
protected $mask;
/**
* Constructor.
*
* @param int $mask optional; defaults to 0
*/
public function __construct($mask = 0)
{
$this->set($mask);
}
/**
* {@inheritdoc}
*/
public function set($mask)
{
if (!is_int($mask)) {
throw new \InvalidArgumentException('$mask must be an integer.');
}
$this->mask = $mask;
return $this;
}
/**
* {@inheritdoc}
*/
public function get()
{
return $this->mask;
}
/**
* {@inheritdoc}
*/
public function add($mask)
{
$this->mask |= $this->resolveMask($mask);
return $this;
}
/**
* {@inheritdoc}
*/
public function remove($mask)
{
$this->mask &= ~$this->resolveMask($mask);
return $this;
}
/**
* {@inheritdoc}
*/
public function reset()
{
$this->mask = 0;
return $this;
}
}

View File

@ -17,7 +17,7 @@ namespace Symfony\Component\Security\Acl\Permission;
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class BasicPermissionMap implements PermissionMapInterface
class BasicPermissionMap implements PermissionMapInterface, MaskBuilderRetrievalInterface
{
const PERMISSION_VIEW = 'VIEW';
const PERMISSION_EDIT = 'EDIT';
@ -105,4 +105,12 @@ class BasicPermissionMap implements PermissionMapInterface
{
return isset($this->map[$permission]);
}
/**
* {@inheritdoc}
*/
public function getMaskBuilder()
{
return new MaskBuilder();
}
}

View File

@ -42,7 +42,7 @@ namespace Symfony\Component\Security\Acl\Permission;
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class MaskBuilder
class MaskBuilder extends AbstractMaskBuilder
{
const MASK_VIEW = 1; // 1 << 0
const MASK_CREATE = 2; // 1 << 1
@ -67,50 +67,6 @@ class MaskBuilder
const OFF = '.';
const ON = '*';
private $mask;
/**
* Constructor.
*
* @param int $mask optional; defaults to 0
*
* @throws \InvalidArgumentException
*/
public function __construct($mask = 0)
{
if (!is_int($mask)) {
throw new \InvalidArgumentException('$mask must be an integer.');
}
$this->mask = $mask;
}
/**
* Adds a mask to the permission.
*
* @param mixed $mask
*
* @return MaskBuilder
*
* @throws \InvalidArgumentException
*/
public function add($mask)
{
$this->mask |= $this->getMask($mask);
return $this;
}
/**
* Returns the mask of this permission.
*
* @return int
*/
public function get()
{
return $this->mask;
}
/**
* Returns a human-readable representation of the permission.
*
@ -135,34 +91,6 @@ class MaskBuilder
return $pattern;
}
/**
* Removes a mask from the permission.
*
* @param mixed $mask
*
* @return MaskBuilder
*
* @throws \InvalidArgumentException
*/
public function remove($mask)
{
$this->mask &= ~$this->getMask($mask);
return $this;
}
/**
* Resets the PermissionBuilder.
*
* @return MaskBuilder
*/
public function reset()
{
$this->mask = 0;
return $this;
}
/**
* Returns the code for the passed mask.
*
@ -204,7 +132,7 @@ class MaskBuilder
*
* @throws \InvalidArgumentException
*/
private function getMask($code)
public function resolveMask($code)
{
if (is_string($code)) {
if (!defined($name = sprintf('static::MASK_%s', strtoupper($code)))) {

View File

@ -0,0 +1,75 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Permission;
/**
* This is the interface that must be implemented by mask builders.
*/
interface MaskBuilderInterface
{
/**
* Set the mask of this permission
*
* @param int $mask
*
* @return MaskBuilderInterface
* @throws \InvalidArgumentException if $mask is not an integer
*/
public function set($mask);
/**
* Returns the mask of this permission.
*
* @return int
*/
public function get();
/**
* Adds a mask to the permission.
*
* @param mixed $mask
*
* @return MaskBuilderInterface
*
* @throws \InvalidArgumentException
*/
public function add($mask);
/**
* Removes a mask from the permission.
*
* @param mixed $mask
*
* @return MaskBuilderInterface
*
* @throws \InvalidArgumentException
*/
public function remove($mask);
/**
* Resets the PermissionBuilder.
*
* @return MaskBuilderInterface
*/
public function reset();
/**
* Returns the mask for the passed code
*
* @param mixed $code
*
* @return int
*
* @throws \InvalidArgumentException
*/
public function resolveMask($code);
}

View File

@ -0,0 +1,25 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Permission;
/**
* Retrieves the MaskBuilder
*/
interface MaskBuilderRetrievalInterface
{
/**
* Returns a new instance of the MaskBuilder used in the permissionMap
*
* @return MaskBuilderInterface
*/
public function getMaskBuilder();
}

View File

@ -6,6 +6,9 @@ CHANGELOG
* added LogoutUrlGenerator
* added the triggering of the `Symfony\Component\Security\Http\SecurityEvents::INTERACTIVE_LOGIN` in `Symfony\Component\Security\Http\Firewall\SimplePreAuthenticationListener`
* The MaskBuilder logic has been abstracted in the `Symfony\Component\Security\Acl\Permission\AbstractMaskBuilder`
and described in the `Symfony\Component\Security\Acl\Permission\MaskBuilderInterface`
* added interface `Symfony\Component\Security\Acl\Permission\MaskBuilderRetrievalInterface`
2.6.0
-----