MaskBuilder.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Security\Acl\Permission;
  11. /**
  12. * This class allows you to build cumulative permissions easily, or convert
  13. * masks to a human-readable format.
  14. *
  15. * <code>
  16. * $builder = new MaskBuilder();
  17. * $builder
  18. * ->add('view')
  19. * ->add('create')
  20. * ->add('edit')
  21. * ;
  22. * var_dump($builder->get()); // int(7)
  23. * var_dump($builder->getPattern()); // string(32) ".............................ECV"
  24. * </code>
  25. *
  26. * We have defined some commonly used base permissions which you can use:
  27. * - VIEW: the SID is allowed to view the domain object / field
  28. * - CREATE: the SID is allowed to create new instances of the domain object / fields
  29. * - EDIT: the SID is allowed to edit existing instances of the domain object / field
  30. * - DELETE: the SID is allowed to delete domain objects
  31. * - UNDELETE: the SID is allowed to recover domain objects from trash
  32. * - OPERATOR: the SID is allowed to perform any action on the domain object
  33. * except for granting others permissions
  34. * - MASTER: the SID is allowed to perform any action on the domain object,
  35. * and is allowed to grant other SIDs any permission except for
  36. * MASTER and OWNER permissions
  37. * - OWNER: the SID is owning the domain object in question and can perform any
  38. * action on the domain object as well as grant any permission
  39. *
  40. * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  41. */
  42. class MaskBuilder extends AbstractMaskBuilder
  43. {
  44. const MASK_VIEW = 1; // 1 << 0
  45. const MASK_CREATE = 2; // 1 << 1
  46. const MASK_EDIT = 4; // 1 << 2
  47. const MASK_DELETE = 8; // 1 << 3
  48. const MASK_UNDELETE = 16; // 1 << 4
  49. const MASK_OPERATOR = 32; // 1 << 5
  50. const MASK_MASTER = 64; // 1 << 6
  51. const MASK_OWNER = 128; // 1 << 7
  52. const MASK_IDDQD = 1073741823; // 1 << 0 | 1 << 1 | ... | 1 << 30
  53. const CODE_VIEW = 'V';
  54. const CODE_CREATE = 'C';
  55. const CODE_EDIT = 'E';
  56. const CODE_DELETE = 'D';
  57. const CODE_UNDELETE = 'U';
  58. const CODE_OPERATOR = 'O';
  59. const CODE_MASTER = 'M';
  60. const CODE_OWNER = 'N';
  61. const ALL_OFF = '................................';
  62. const OFF = '.';
  63. const ON = '*';
  64. /**
  65. * Returns a human-readable representation of the permission.
  66. *
  67. * @return string
  68. */
  69. public function getPattern()
  70. {
  71. $pattern = self::ALL_OFF;
  72. $length = strlen($pattern);
  73. $bitmask = str_pad(decbin($this->mask), $length, '0', STR_PAD_LEFT);
  74. for ($i = $length - 1; $i >= 0; --$i) {
  75. if ('1' === $bitmask[$i]) {
  76. try {
  77. $pattern[$i] = self::getCode(1 << ($length - $i - 1));
  78. } catch (\Exception $e) {
  79. $pattern[$i] = self::ON;
  80. }
  81. }
  82. }
  83. return $pattern;
  84. }
  85. /**
  86. * Returns the code for the passed mask.
  87. *
  88. * @param int $mask
  89. *
  90. * @throws \InvalidArgumentException
  91. * @throws \RuntimeException
  92. *
  93. * @return string
  94. */
  95. public static function getCode($mask)
  96. {
  97. if (!is_int($mask)) {
  98. throw new \InvalidArgumentException('$mask must be an integer.');
  99. }
  100. $reflection = new \ReflectionClass(get_called_class());
  101. foreach ($reflection->getConstants() as $name => $cMask) {
  102. if (0 !== strpos($name, 'MASK_') || $mask !== $cMask) {
  103. continue;
  104. }
  105. if (!defined($cName = 'static::CODE_'.substr($name, 5))) {
  106. throw new \RuntimeException('There was no code defined for this mask.');
  107. }
  108. return constant($cName);
  109. }
  110. throw new \InvalidArgumentException(sprintf('The mask "%d" is not supported.', $mask));
  111. }
  112. /**
  113. * Returns the mask for the passed code.
  114. *
  115. * @param mixed $code
  116. *
  117. * @return int
  118. *
  119. * @throws \InvalidArgumentException
  120. */
  121. public function resolveMask($code)
  122. {
  123. if (is_string($code)) {
  124. if (!defined($name = sprintf('static::MASK_%s', strtoupper($code)))) {
  125. throw new \InvalidArgumentException(sprintf('The code "%s" is not supported', $code));
  126. }
  127. return constant($name);
  128. }
  129. if (!is_int($code)) {
  130. throw new \InvalidArgumentException('$code must be an integer.');
  131. }
  132. return $code;
  133. }
  134. }