Overview

Namespaces

  • PHP
  • ProgrammingAreHard
    • Arbiter
      • Domain
      • Model
  • Symfony
    • Component
      • Security
        • Acl
          • Exception
          • Model
          • Permission
        • Core
          • User

Classes

  • BasicPermissionMap
  • MaskBuilder

Interfaces

  • PermissionMapInterface
  • Overview
  • Namespace
  • Class
  • Tree
  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 int     $mask optional; defaults to 0
 76:      *
 77:      * @throws \InvalidArgumentException
 78:      */
 79:     public function __construct($mask = 0)
 80:     {
 81:         if (!is_int($mask)) {
 82:             throw new \InvalidArgumentException('$mask must be an integer.');
 83:         }
 84: 
 85:         $this->mask = $mask;
 86:     }
 87: 
 88:     /**
 89:      * Adds a mask to the permission
 90:      *
 91:      * @param mixed $mask
 92:      *
 93:      * @return MaskBuilder
 94:      *
 95:      * @throws \InvalidArgumentException
 96:      */
 97:     public function add($mask)
 98:     {
 99:         if (is_string($mask) && defined($name = 'static::MASK_'.strtoupper($mask))) {
100:             $mask = constant($name);
101:         } elseif (!is_int($mask)) {
102:             throw new \InvalidArgumentException('$mask must be an integer.');
103:         }
104: 
105:         $this->mask |= $mask;
106: 
107:         return $this;
108:     }
109: 
110:     /**
111:      * Returns the mask of this permission
112:      *
113:      * @return int
114:      */
115:     public function get()
116:     {
117:         return $this->mask;
118:     }
119: 
120:     /**
121:      * Returns a human-readable representation of the permission
122:      *
123:      * @return string
124:      */
125:     public function getPattern()
126:     {
127:         $pattern = self::ALL_OFF;
128:         $length = strlen($pattern);
129:         $bitmask = str_pad(decbin($this->mask), $length, '0', STR_PAD_LEFT);
130: 
131:         for ($i=$length-1; $i>=0; $i--) {
132:             if ('1' === $bitmask[$i]) {
133:                 try {
134:                     $pattern[$i] = self::getCode(1 << ($length - $i - 1));
135:                 } catch (\Exception $notPredefined) {
136:                     $pattern[$i] = self::ON;
137:                 }
138:             }
139:         }
140: 
141:         return $pattern;
142:     }
143: 
144:     /**
145:      * Removes a mask from the permission
146:      *
147:      * @param mixed $mask
148:      *
149:      * @return MaskBuilder
150:      *
151:      * @throws \InvalidArgumentException
152:      */
153:     public function remove($mask)
154:     {
155:         if (is_string($mask) && defined($name = 'static::MASK_'.strtoupper($mask))) {
156:             $mask = constant($name);
157:         } elseif (!is_int($mask)) {
158:             throw new \InvalidArgumentException('$mask must be an integer.');
159:         }
160: 
161:         $this->mask &= ~$mask;
162: 
163:         return $this;
164:     }
165: 
166:     /**
167:      * Resets the PermissionBuilder
168:      *
169:      * @return MaskBuilder
170:      */
171:     public function reset()
172:     {
173:         $this->mask = 0;
174: 
175:         return $this;
176:     }
177: 
178:     /**
179:      * Returns the code for the passed mask
180:      *
181:      * @param int     $mask
182:      * @throws \InvalidArgumentException
183:      * @throws \RuntimeException
184:      * @return string
185:      */
186:     public static function getCode($mask)
187:     {
188:         if (!is_int($mask)) {
189:             throw new \InvalidArgumentException('$mask must be an integer.');
190:         }
191: 
192:         $reflection = new \ReflectionClass(get_called_class());
193:         foreach ($reflection->getConstants() as $name => $cMask) {
194:             if (0 !== strpos($name, 'MASK_')) {
195:                 continue;
196:             }
197: 
198:             if ($mask === $cMask) {
199:                 if (!defined($cName = 'static::CODE_'.substr($name, 5))) {
200:                     throw new \RuntimeException('There was no code defined for this mask.');
201:                 }
202: 
203:                 return constant($cName);
204:             }
205:         }
206: 
207:         throw new \InvalidArgumentException(sprintf('The mask "%d" is not supported.', $mask));
208:     }
209: }
210: 
Arbiter API documentation generated by ApiGen 2.8.0