PageRenderTime 53ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/models/behaviors/inmate.php

https://github.com/m3nt0r/cakephp-jailson
PHP | 415 lines | 188 code | 55 blank | 172 comment | 44 complexity | 12f35f4b3e44438909dc9a7d4595613d MD5 | raw file
Possible License(s): MIT
  1. <?php
  2. /**
  3. * Jailson for CakePHP
  4. * Access Control Plugin
  5. *
  6. * @category CakePHP
  7. * @author Kjell Bublitz <m3nt0r.de@gmail.com>
  8. * @package plugins.jailson
  9. * @subpackage plugins.jailson.behaviors
  10. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  11. * @link http://github.com/m3nt0r/cakephp-jailson Repository/Docs
  12. * @copyright (c) 2010, Kjell Bublitz (http://cakealot.com)
  13. */
  14. App::import('Lib', 'Jailson.Storage');
  15. /**
  16. * Jailson - Inmate Behavior
  17. *
  18. * @category CakePHP
  19. * @author Kjell Bublitz <m3nt0r.de@gmail.com>
  20. * @package plugins.jailson
  21. * @subpackage plugins.jailson.behaviors
  22. */
  23. class InmateBehavior extends ModelBehavior {
  24. /**
  25. * Storage Model
  26. * @var Inmate
  27. */
  28. public $Inmate;
  29. /**
  30. * Init Storage Model
  31. */
  32. function setup($model, $config = array()) {
  33. // options
  34. $_defaultConfig = array(
  35. 'cacheConfig' => 'default',
  36. 'inmateModel' => 'Jailson.Inmate',
  37. 'disableCache' => false
  38. );
  39. $this->settings[$model->alias] = array_merge($_defaultConfig, $config);
  40. // load storage model
  41. if (!is_object($this->Inmate)) {
  42. $this->Inmate = ClassRegistry::init($this->settings[$model->alias]['inmateModel']);
  43. }
  44. }
  45. /**
  46. * Before delete store the id of the object to Inmate
  47. *
  48. * @see InmateBehavior::afterDelete
  49. * @param object $model
  50. */
  51. function beforeDelete($model) {
  52. $this->_id = $model->id;
  53. }
  54. /**
  55. * After delete remove all data for this object, using stored model id
  56. * Clean up after.
  57. *
  58. * @see InmateBehavior::beforeDelete
  59. * @param object $model
  60. */
  61. function afterDelete($model) {
  62. $model->id = $this->_id;
  63. $this->free($model);
  64. unset($this->_id);
  65. }
  66. /**
  67. * Check if current object has given role
  68. *
  69. * @param object $model
  70. * @param mixed $role string/array
  71. * @param mixed $sentence
  72. *
  73. * @return boolean
  74. */
  75. function has($model, $role, $sentence = null) {
  76. if (!is_array($role)) $role = array($role);
  77. $checked = $keys = array();
  78. $cached = $this->cachedRoles($model);
  79. if ($cached === false || $this->settings[$model->alias]['disableCache']) {
  80. foreach ($role as $part) {
  81. $keys[]= Storage::pack($model, $part, $sentence);
  82. }
  83. $found = $this->Inmate->retrieve($keys);
  84. if (count($found)) {
  85. $this->_cache('write', $model, $found);
  86. $checked = array_fill(0, count($found), true);
  87. }
  88. } else {
  89. foreach ($role as $part) {
  90. $key = Storage::pack($model, $part, $sentence);
  91. if (!in_array($key, $cached)) {
  92. $exists = $this->Inmate->retrieve($key);
  93. if (!empty($exists)) {
  94. $this->_cache('merge', $model, $exists, $cached);
  95. $checked[]= true;
  96. }
  97. } else {
  98. $checked[]= in_array($key, $cached);
  99. }
  100. }
  101. }
  102. return (array_sum($checked) == count($role));
  103. }
  104. /**
  105. * Assigns given role to the current object
  106. *
  107. * @param object $model
  108. * @param mixed $role string/array
  109. * @param mixed $sentence
  110. *
  111. * @return array
  112. */
  113. function lockAs($model, $role, $sentence = null) {
  114. if (!is_array($role)) $role = array($role);
  115. $cached = (array) $this->cachedRoles($model);
  116. $keys = array();
  117. foreach ($role as $part) {
  118. $key = Storage::pack($model, $part, $sentence);
  119. if (!in_array($key, $cached)) // dont store cached
  120. $keys[]= $key;
  121. }
  122. if (!empty($keys))
  123. $stored = $this->Inmate->store($keys);
  124. if (!empty($stored)) {
  125. $this->_cache('merge', $model, $stored, $cached);
  126. return array_map(array('Storage', 'unpack'), $stored);
  127. }
  128. return false; // nothing to do
  129. }
  130. /**
  131. * Removes given role from current object
  132. *
  133. * @param object $model
  134. * @param mixed $role
  135. * @param mixed $sentence
  136. *
  137. * @return mixed unpacked roles, or false if nothing to do
  138. */
  139. function release($model, $role, $sentence = null) {
  140. $keys = $deleted = array();
  141. if (!is_array($role))
  142. $role = array($role);
  143. $cached = (array) $this->cachedRoles($model);
  144. if ($this->settings[$model->alias]['disableCache']) {
  145. foreach ($role as $part) {
  146. $keys[]= Storage::pack($model, $part, $sentence);
  147. }
  148. } else {
  149. foreach ($role as $part) {
  150. $key = Storage::pack($model, $part, $sentence);
  151. if (in_array($key, $cached)) // only try cached
  152. $keys[]= $key;
  153. }
  154. }
  155. if (!empty($keys))
  156. $deleted = $this->Inmate->remove($keys);
  157. if (!empty($deleted)) {
  158. $this->_cache('diff', $model, $deleted, $cached);
  159. return array_map(array('Storage', 'unpack'), $deleted);
  160. }
  161. return false; // nothing to do
  162. }
  163. /**
  164. * Deletes all entries for object
  165. *
  166. * @param object $model
  167. * @param mixed $role (optional)
  168. * @param mixed $sentence (optional)
  169. *
  170. * @return mixed roles data, or false if nothing to do
  171. */
  172. function free($model, $role = null, $sentence = null) {
  173. $key = Storage::pack($model, $role, $sentence);
  174. $cached = (array) $this->cachedRoles($model);
  175. if (!in_array($key, $cached) && !$this->settings[$model->alias]['disableCache'])
  176. return false; // empty cache is 'free' enough
  177. $deleted = $this->Inmate->removeTree($key);
  178. if (empty($role)) {
  179. $this->_cache('reset', $model);
  180. }
  181. if (!empty($deleted)) {
  182. $this->_cache('diff', $model, $deleted, $cached);
  183. return array_map(array('Storage', 'unpack'), $deleted);
  184. }
  185. return false;
  186. }
  187. /**
  188. * Returns a list of roles assigned to the current object
  189. *
  190. * @param object $model
  191. * @param mixed $justRoles If true, only current role names are returned
  192. *
  193. * @return mixed roles data
  194. */
  195. function roles($model, $justRoles = false) {
  196. $keys = (array) $this->Inmate->drilldown(Storage::inmateId($model));
  197. $result = array();
  198. foreach ($keys as $key) {
  199. $data = Storage::unpack($key);
  200. $result[ $data['role'] ][] = $data;
  201. }
  202. if ($justRoles)
  203. return array_keys($result);
  204. return $result;
  205. }
  206. /**
  207. * Just for semantics: Alias to "is"
  208. *
  209. * @param object $model
  210. * @param string $role member_of, created_by, seen_at, image_for, based_on
  211. * @param mixed $sentence model object or any string
  212. * @param boolean $create (optional) if true: make this semantic become real
  213. *
  214. * @return array
  215. */
  216. function did($model) {
  217. return call_user_method_array('is', $this, func_get_args());
  218. }
  219. /**
  220. * Just for semantics: Alias to "is"
  221. *
  222. * @param object $model
  223. * @param string $role member_of, created_by, seen_at, image_for, based_on
  224. * @param mixed $sentence model object or any string
  225. * @param boolean $create (optional) if true: make this semantic become real
  226. *
  227. * @return array
  228. */
  229. function was($model) {
  230. return call_user_method_array('is', $this, func_get_args());
  231. }
  232. /**
  233. * Just for semantics: Alias to "is"
  234. *
  235. * @param object $model
  236. * @param string $role member_of, created_by, seen_at, image_for, based_on
  237. * @param mixed $sentence model object or any string
  238. * @param boolean $create (optional) if true: make this semantic become real
  239. *
  240. * @return array
  241. */
  242. function can($model) {
  243. return call_user_method_array('is', $this, func_get_args());
  244. }
  245. /**
  246. * Just for semantics: Alias to "is"
  247. *
  248. * @param object $model
  249. * @param string $role member_of, created_by, seen_at, image_for, based_on
  250. * @param mixed $sentence model object or any string
  251. * @param boolean $create (optional) if true: make this semantic become real
  252. *
  253. * @return array
  254. */
  255. function isIn($model) {
  256. return call_user_method_array('is', $this, func_get_args());
  257. }
  258. /**
  259. * Just for semantics
  260. *
  261. * @param object $model
  262. * @param string $role member_of, created_by, seen_at, image_for, based_on
  263. * @param mixed $sentence model object or any string
  264. * @param boolean $create (optional) if true: make this semantic become real
  265. *
  266. * @return array
  267. */
  268. function is($model) {
  269. $args = func_get_args();
  270. list($role, $sentence, $create) = $this->__parseArgs($args);
  271. if ($create) {
  272. return $this->lockAs($model, $role, $sentence);
  273. }
  274. return $this->has($model, $role, $sentence);
  275. }
  276. /**
  277. * Just for semantics, reversed is()
  278. *
  279. * @param object $model
  280. * @param string $role member_of, created_by, seen_at, image_for, based_on
  281. * @param mixed $sentence model object or any string
  282. * @param boolean $remove (optional) if true, make this semantic become real
  283. *
  284. * @return array
  285. */
  286. function isNot($model) {
  287. $args = func_get_args();
  288. list($role, $sentence, $remove) = $this->__parseArgs($args);
  289. if ($remove) {
  290. return $this->release($model, $role, $sentence);
  291. }
  292. return !$this->has($model, $role, $sentence);
  293. }
  294. /**
  295. * Wrapper for Cache::read
  296. * get currently cached roles for this object
  297. *
  298. * @param object $model
  299. * @return mixed
  300. */
  301. function cachedRoles($model) {
  302. if ($this->settings[$model->alias]['disableCache'])
  303. return array();
  304. $config = $this->settings[$model->alias]['cacheConfig'];
  305. $cache = Cache::read(Storage::cacheId($model), $config);
  306. return $cache;
  307. }
  308. /**
  309. * Wrapper for Cache::write
  310. * store data to the cache of the current object
  311. *
  312. * @param string $task Modify data task
  313. * @param object $model To build the cache key
  314. * @param array $data (optional) List of keys, or empty
  315. * @param array $cached (optional) Current cache
  316. *
  317. * @return array Data that was written
  318. */
  319. protected function _cache($task, $model, $data = array(), $cached = null) {
  320. if (!$cached)
  321. $cached = $this->cachedRoles($model);
  322. if ($task == 'merge')
  323. $data = array_merge($cached, $data);
  324. if ($task == 'diff')
  325. $data = array_diff($cached, $data);
  326. if ($task == 'reset')
  327. $data = array();
  328. if ($this->settings[$model->alias]['disableCache'])
  329. return $data;
  330. Cache::write(Storage::cacheId($model), Set::filter($data), $this->settings[$model->alias]['cacheConfig']);
  331. return $data;
  332. }
  333. /**
  334. * Parse method arguments
  335. *
  336. * @param array $args func_get_args
  337. * @return array (sRole, mSentence, bSwitch)
  338. */
  339. private function __parseArgs($args) {
  340. $model = $args[0];
  341. $role = Storage::role($args[1]);
  342. $sentence = null;
  343. if (count($args) >= 3) {
  344. if (is_bool($args[2]) && count($args) == 3) {
  345. // allow bool as second param
  346. $switch = $args[2];
  347. } else {
  348. $sentence = $args[2];
  349. }
  350. }
  351. // optional third param (if there's a sentence)
  352. if (count($args) >= 4) {
  353. $switch = $args[3];
  354. } else {
  355. if (!isset($switch))
  356. $switch = false;
  357. }
  358. return array($role, $sentence, $switch);
  359. }
  360. }