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