vendor/symfony/src/Symfony/Component/Security/Acl/Permission/MaskBuilder.php
changeset 0 7f95f8617b0b
equal deleted inserted replaced
-1:000000000000 0:7f95f8617b0b
       
     1 <?php
       
     2 
       
     3 /*
       
     4  * This file is part of the Symfony package.
       
     5  *
       
     6  * (c) Fabien Potencier <fabien@symfony.com>
       
     7  *
       
     8  * For the full copyright and license information, please view the LICENSE
       
     9  * file that was distributed with this source code.
       
    10  */
       
    11 
       
    12 namespace Symfony\Component\Security\Acl\Permission;
       
    13 
       
    14 /**
       
    15  * This class allows you to build cumulative permissions easily, or convert
       
    16  * masks to a human-readable format.
       
    17  *
       
    18  * <code>
       
    19  *       $builder = new MaskBuilder();
       
    20  *       $builder
       
    21  *           ->add('view')
       
    22  *           ->add('create')
       
    23  *           ->add('edit')
       
    24  *       ;
       
    25  *       var_dump($builder->get());        // int(7)
       
    26  *       var_dump($builder->getPattern()); // string(32) ".............................ECV"
       
    27  * </code>
       
    28  *
       
    29  * We have defined some commonly used base permissions which you can use:
       
    30  * - VIEW: the SID is allowed to view the domain object / field
       
    31  * - CREATE: the SID is allowed to create new instances of the domain object / fields
       
    32  * - EDIT: the SID is allowed to edit existing instances of the domain object / field
       
    33  * - DELETE: the SID is allowed to delete domain objects
       
    34  * - UNDELETE: the SID is allowed to recover domain objects from trash
       
    35  * - OPERATOR: the SID is allowed to perform any action on the domain object
       
    36  *             except for granting others permissions
       
    37  * - MASTER: the SID is allowed to perform any action on the domain object,
       
    38  *           and is allowed to grant other SIDs any permission except for
       
    39  *           MASTER and OWNER permissions
       
    40  * - OWNER: the SID is owning the domain object in question and can perform any
       
    41  *          action on the domain object as well as grant any permission
       
    42  *
       
    43  * @author Johannes M. Schmitt <schmittjoh@gmail.com>
       
    44  */
       
    45 class MaskBuilder
       
    46 {
       
    47     const MASK_VIEW         = 1;          // 1 << 0
       
    48     const MASK_CREATE       = 2;          // 1 << 1
       
    49     const MASK_EDIT         = 4;          // 1 << 2
       
    50     const MASK_DELETE       = 8;          // 1 << 3
       
    51     const MASK_UNDELETE     = 16;         // 1 << 4
       
    52     const MASK_OPERATOR     = 32;         // 1 << 5
       
    53     const MASK_MASTER       = 64;         // 1 << 6
       
    54     const MASK_OWNER        = 128;        // 1 << 7
       
    55     const MASK_IDDQD        = 1073741823; // 1 << 0 | 1 << 1 | ... | 1 << 30
       
    56 
       
    57     const CODE_VIEW         = 'V';
       
    58     const CODE_CREATE       = 'C';
       
    59     const CODE_EDIT         = 'E';
       
    60     const CODE_DELETE       = 'D';
       
    61     const CODE_UNDELETE     = 'U';
       
    62     const CODE_OPERATOR     = 'O';
       
    63     const CODE_MASTER       = 'M';
       
    64     const CODE_OWNER        = 'N';
       
    65 
       
    66     const ALL_OFF           = '................................';
       
    67     const OFF               = '.';
       
    68     const ON                = '*';
       
    69 
       
    70     private $mask;
       
    71 
       
    72     /**
       
    73      * Constructor
       
    74      *
       
    75      * @param integer $mask optional; defaults to 0
       
    76      * @return void
       
    77      */
       
    78     public function __construct($mask = 0)
       
    79     {
       
    80         if (!is_int($mask)) {
       
    81             throw new \InvalidArgumentException('$mask must be an integer.');
       
    82         }
       
    83 
       
    84         $this->mask = $mask;
       
    85     }
       
    86 
       
    87     /**
       
    88      * Adds a mask to the permission
       
    89      *
       
    90      * @param mixed $mask
       
    91      * @return PermissionBuilder
       
    92      */
       
    93     public function add($mask)
       
    94     {
       
    95         if (is_string($mask) && defined($name = 'static::MASK_'.strtoupper($mask))) {
       
    96             $mask = constant($name);
       
    97         } else if (!is_int($mask)) {
       
    98             throw new \InvalidArgumentException('$mask must be an integer.');
       
    99         }
       
   100 
       
   101         $this->mask |= $mask;
       
   102 
       
   103         return $this;
       
   104     }
       
   105 
       
   106     /**
       
   107      * Returns the mask of this permission
       
   108      *
       
   109      * @return integer
       
   110      */
       
   111     public function get()
       
   112     {
       
   113         return $this->mask;
       
   114     }
       
   115 
       
   116     /**
       
   117      * Returns a human-readable representation of the permission
       
   118      *
       
   119      * @return string
       
   120      */
       
   121     public function getPattern()
       
   122     {
       
   123         $pattern = self::ALL_OFF;
       
   124         $length = strlen($pattern);
       
   125         $bitmask = str_pad(decbin($this->mask), $length, '0', STR_PAD_LEFT);
       
   126 
       
   127         for ($i=$length-1; $i>=0; $i--) {
       
   128             if ('1' === $bitmask[$i]) {
       
   129                 try {
       
   130                     $pattern[$i] = self::getCode(1 << ($length - $i - 1));
       
   131                 } catch (\Exception $notPredefined) {
       
   132                     $pattern[$i] = self::ON;
       
   133                 }
       
   134             }
       
   135         }
       
   136 
       
   137         return $pattern;
       
   138     }
       
   139 
       
   140     /**
       
   141      * Removes a mask from the permission
       
   142      *
       
   143      * @param mixed $mask
       
   144      * @return PermissionBuilder
       
   145      */
       
   146     public function remove($mask)
       
   147     {
       
   148         if (is_string($mask) && defined($name = 'static::MASK_'.strtoupper($mask))) {
       
   149             $mask = constant($name);
       
   150         } else if (!is_int($mask)) {
       
   151             throw new \InvalidArgumentException('$mask must be an integer.');
       
   152         }
       
   153 
       
   154         $this->mask &= ~$mask;
       
   155 
       
   156         return $this;
       
   157     }
       
   158 
       
   159     /**
       
   160      * Resets the PermissionBuilder
       
   161      *
       
   162      * @return PermissionBuilder
       
   163      */
       
   164     public function reset()
       
   165     {
       
   166         $this->mask = 0;
       
   167 
       
   168         return $this;
       
   169     }
       
   170 
       
   171     /**
       
   172      * Returns the code for the passed mask
       
   173      *
       
   174      * @param integer $mask
       
   175      * @throws \InvalidArgumentException
       
   176      * @throws \RuntimeException
       
   177      * @return string
       
   178      */
       
   179     static public function getCode($mask)
       
   180     {
       
   181         if (!is_int($mask)) {
       
   182             throw new \InvalidArgumentException('$mask must be an integer.');
       
   183         }
       
   184 
       
   185         $reflection = new \ReflectionClass(get_called_class());
       
   186         foreach ($reflection->getConstants() as $name => $cMask) {
       
   187             if (0 !== strpos($name, 'MASK_')) {
       
   188                 continue;
       
   189             }
       
   190 
       
   191             if ($mask === $cMask) {
       
   192                 if (!defined($cName = 'static::CODE_'.substr($name, 5))) {
       
   193                     throw new \RuntimeException('There was no code defined for this mask.');
       
   194                 }
       
   195 
       
   196                 return constant($cName);
       
   197             }
       
   198         }
       
   199 
       
   200         throw new \InvalidArgumentException(sprintf('The mask "%d" is not supported.', $mask));
       
   201     }
       
   202 }