DoctrineAclCache.php 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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\Domain;
  11. use Doctrine\Common\Cache\Cache;
  12. use Doctrine\Common\Cache\CacheProvider;
  13. use Symfony\Component\Security\Acl\Model\AclCacheInterface;
  14. use Symfony\Component\Security\Acl\Model\AclInterface;
  15. use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
  16. use Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface;
  17. /**
  18. * This class is a wrapper around the actual cache implementation.
  19. *
  20. * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  21. */
  22. class DoctrineAclCache implements AclCacheInterface
  23. {
  24. const PREFIX = 'sf2_acl_';
  25. private $cache;
  26. private $prefix;
  27. private $permissionGrantingStrategy;
  28. /**
  29. * Constructor.
  30. *
  31. * @param Cache $cache
  32. * @param PermissionGrantingStrategyInterface $permissionGrantingStrategy
  33. * @param string $prefix
  34. *
  35. * @throws \InvalidArgumentException
  36. */
  37. public function __construct(Cache $cache, PermissionGrantingStrategyInterface $permissionGrantingStrategy, $prefix = self::PREFIX)
  38. {
  39. if (0 === strlen($prefix)) {
  40. throw new \InvalidArgumentException('$prefix cannot be empty.');
  41. }
  42. $this->cache = $cache;
  43. $this->permissionGrantingStrategy = $permissionGrantingStrategy;
  44. $this->prefix = $prefix;
  45. }
  46. /**
  47. * {@inheritdoc}
  48. */
  49. public function clearCache()
  50. {
  51. if ($this->cache instanceof CacheProvider) {
  52. $this->cache->deleteAll();
  53. }
  54. }
  55. /**
  56. * {@inheritdoc}
  57. */
  58. public function evictFromCacheById($aclId)
  59. {
  60. $lookupKey = $this->getAliasKeyForIdentity($aclId);
  61. if (!$this->cache->contains($lookupKey)) {
  62. return;
  63. }
  64. $key = $this->cache->fetch($lookupKey);
  65. if ($this->cache->contains($key)) {
  66. $this->cache->delete($key);
  67. }
  68. $this->cache->delete($lookupKey);
  69. }
  70. /**
  71. * {@inheritdoc}
  72. */
  73. public function evictFromCacheByIdentity(ObjectIdentityInterface $oid)
  74. {
  75. $key = $this->getDataKeyByIdentity($oid);
  76. if (!$this->cache->contains($key)) {
  77. return;
  78. }
  79. $this->cache->delete($key);
  80. }
  81. /**
  82. * {@inheritdoc}
  83. */
  84. public function getFromCacheById($aclId)
  85. {
  86. $lookupKey = $this->getAliasKeyForIdentity($aclId);
  87. if (!$this->cache->contains($lookupKey)) {
  88. return;
  89. }
  90. $key = $this->cache->fetch($lookupKey);
  91. if (!$this->cache->contains($key)) {
  92. $this->cache->delete($lookupKey);
  93. return;
  94. }
  95. return $this->unserializeAcl($this->cache->fetch($key));
  96. }
  97. /**
  98. * {@inheritdoc}
  99. */
  100. public function getFromCacheByIdentity(ObjectIdentityInterface $oid)
  101. {
  102. $key = $this->getDataKeyByIdentity($oid);
  103. if (!$this->cache->contains($key)) {
  104. return;
  105. }
  106. return $this->unserializeAcl($this->cache->fetch($key));
  107. }
  108. /**
  109. * {@inheritdoc}
  110. */
  111. public function putInCache(AclInterface $acl)
  112. {
  113. if (null === $acl->getId()) {
  114. throw new \InvalidArgumentException('Transient ACLs cannot be cached.');
  115. }
  116. if (null !== $parentAcl = $acl->getParentAcl()) {
  117. $this->putInCache($parentAcl);
  118. }
  119. $key = $this->getDataKeyByIdentity($acl->getObjectIdentity());
  120. $this->cache->save($key, serialize($acl));
  121. $this->cache->save($this->getAliasKeyForIdentity($acl->getId()), $key);
  122. }
  123. /**
  124. * Unserializes the ACL.
  125. *
  126. * @param string $serialized
  127. *
  128. * @return AclInterface
  129. */
  130. private function unserializeAcl($serialized)
  131. {
  132. $acl = unserialize($serialized);
  133. if (null !== $parentId = $acl->getParentAcl()) {
  134. $parentAcl = $this->getFromCacheById($parentId);
  135. if (null === $parentAcl) {
  136. return;
  137. }
  138. $acl->setParentAcl($parentAcl);
  139. }
  140. $reflectionProperty = new \ReflectionProperty($acl, 'permissionGrantingStrategy');
  141. $reflectionProperty->setAccessible(true);
  142. $reflectionProperty->setValue($acl, $this->permissionGrantingStrategy);
  143. $reflectionProperty->setAccessible(false);
  144. $aceAclProperty = new \ReflectionProperty('Symfony\Component\Security\Acl\Domain\Entry', 'acl');
  145. $aceAclProperty->setAccessible(true);
  146. foreach ($acl->getObjectAces() as $ace) {
  147. $aceAclProperty->setValue($ace, $acl);
  148. }
  149. foreach ($acl->getClassAces() as $ace) {
  150. $aceAclProperty->setValue($ace, $acl);
  151. }
  152. $aceClassFieldProperty = new \ReflectionProperty($acl, 'classFieldAces');
  153. $aceClassFieldProperty->setAccessible(true);
  154. foreach ($aceClassFieldProperty->getValue($acl) as $aces) {
  155. foreach ($aces as $ace) {
  156. $aceAclProperty->setValue($ace, $acl);
  157. }
  158. }
  159. $aceClassFieldProperty->setAccessible(false);
  160. $aceObjectFieldProperty = new \ReflectionProperty($acl, 'objectFieldAces');
  161. $aceObjectFieldProperty->setAccessible(true);
  162. foreach ($aceObjectFieldProperty->getValue($acl) as $aces) {
  163. foreach ($aces as $ace) {
  164. $aceAclProperty->setValue($ace, $acl);
  165. }
  166. }
  167. $aceObjectFieldProperty->setAccessible(false);
  168. $aceAclProperty->setAccessible(false);
  169. return $acl;
  170. }
  171. /**
  172. * Returns the key for the object identity.
  173. *
  174. * @param ObjectIdentityInterface $oid
  175. *
  176. * @return string
  177. */
  178. private function getDataKeyByIdentity(ObjectIdentityInterface $oid)
  179. {
  180. return $this->prefix.md5($oid->getType()).sha1($oid->getType())
  181. .'_'.md5($oid->getIdentifier()).sha1($oid->getIdentifier());
  182. }
  183. /**
  184. * Returns the alias key for the object identity key.
  185. *
  186. * @param string $aclId
  187. *
  188. * @return string
  189. */
  190. private function getAliasKeyForIdentity($aclId)
  191. {
  192. return $this->prefix.$aclId;
  193. }
  194. }