HookManagement.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. /**
  4. * @TODO: Improve description
  5. * @package chamilo.hookmanagement
  6. */
  7. class HookManagement implements HookManagementInterface
  8. {
  9. /**
  10. * Constructor
  11. */
  12. protected function __construct()
  13. {
  14. $this->tables[TABLE_HOOK_OBSERVER] = Database::get_main_table(TABLE_HOOK_OBSERVER);
  15. $this->tables[TABLE_HOOK_EVENT] = Database::get_main_table(TABLE_HOOK_EVENT);
  16. $this->tables[TABLE_HOOK_CALL] = Database::get_main_table(TABLE_HOOK_CALL);
  17. $this->hookCalls = $this->listAllHookCalls();
  18. $this->hookEvents = $this->listAllHookEvents();
  19. $this->hookObservers = $this->listAllHookObservers();
  20. }
  21. /**
  22. * Instance the hook manager
  23. * @staticvar null $result
  24. * @return HookManagement
  25. */
  26. public static function create()
  27. {
  28. static $result = null;
  29. return $result ? $result : $result = new self();
  30. }
  31. /**
  32. * Insert hook into Database. Return insert id
  33. * @param string $eventName
  34. * @param string $observerClassName
  35. * @param int $type
  36. *
  37. * @return int
  38. */
  39. public function insertHook($eventName, $observerClassName, $type)
  40. {
  41. if ($type === HOOK_EVENT_TYPE_ALL) {
  42. $this->insertHook($eventName, $observerClassName, HOOK_EVENT_TYPE_PRE);
  43. $this->insertHook($eventName, $observerClassName, HOOK_EVENT_TYPE_POST);
  44. } else {
  45. $this->insertHookIfNotExist($eventName, $observerClassName);
  46. // Check if exists hook call
  47. $row = Database::select('id, enabled',
  48. $this->tables[TABLE_HOOK_CALL],
  49. array(
  50. 'where' => array(
  51. 'hook_event_id = ? ' => $this->hookEvents[$eventName],
  52. 'AND hook_observer_id = ? ' => $this->hookObservers[$observerClassName],
  53. 'AND type = ? ' => $type,
  54. ),
  55. ),
  56. 'ASSOC');
  57. if (!empty($row) && is_array($row)) {
  58. // Check if is hook call is active
  59. if ((int) $row['enabled'] === 0) {
  60. Database::update(
  61. $this->tables[TABLE_HOOK_CALL],
  62. array(
  63. 'enabled' => 1,
  64. ),
  65. array(
  66. 'id = ?' => $row['id'],
  67. )
  68. );
  69. }
  70. }
  71. }
  72. }
  73. /**
  74. * Delete hook from Database. Return deleted rows number
  75. * @param string $eventName
  76. * @param string $observerClassName
  77. * @param int $type
  78. *
  79. * @return int
  80. */
  81. public function deleteHook($eventName, $observerClassName, $type)
  82. {
  83. if ($type === HOOK_EVENT_TYPE_ALL) {
  84. $this->deleteHook($eventName, $observerClassName, HOOK_EVENT_TYPE_PRE);
  85. $this->deleteHook($eventName, $observerClassName, HOOK_EVENT_TYPE_POST);
  86. } else {
  87. $this->insertHookIfNotExist($eventName, $observerClassName);
  88. Database::update(
  89. $this->tables[TABLE_HOOK_CALL],
  90. array(
  91. 'enabled' => 0,
  92. ),
  93. array(
  94. 'id = ? ' => $this->hookCalls[$eventName][$observerClassName][$type],
  95. )
  96. );
  97. }
  98. }
  99. /**
  100. * Update hook observer order by hook event
  101. * @param $eventName
  102. * @param $type
  103. * @param $hookOrders
  104. *
  105. * @return int
  106. */
  107. public function orderHook($eventName, $type, $hookOrders)
  108. {
  109. foreach ($this->hookCalls[$eventName] as $observerClassName => $types) {
  110. foreach ($hookOrders as $oldOrder => $newOrder)
  111. {
  112. $res = Database::update(
  113. $this->tables[TABLE_HOOK_CALL],
  114. array(
  115. 'hook_order ' => $newOrder,
  116. ),
  117. array(
  118. 'id = ? ' => $types[$type],
  119. 'AND hook_order = ? ' => $oldOrder,
  120. )
  121. );
  122. if ($res) {
  123. break;
  124. }
  125. }
  126. }
  127. }
  128. /**
  129. * Return a list an associative array where keys are the active hook observer class name
  130. * @param string $eventName
  131. *
  132. * @return array
  133. */
  134. public function listHookObservers($eventName)
  135. {
  136. $array = array();
  137. $joinTable = $this->tables[TABLE_HOOK_CALL].' hc'.
  138. ' INNER JOIN '.$this->tables[TABLE_HOOK_EVENT].' he'.
  139. ' ON hc.hook_event_id = he.id '.
  140. ' INNER JOIN '.$this->tables[TABLE_HOOK_OBSERVER].' ho '.
  141. ' ON hc.hook_observer_id = ho.id ';
  142. $columns = 'ho.class_name, ho.path, ho.plugin_name, hc.enabled';
  143. $where = array('where' => array('he.class_name = ? ' => $eventName, 'AND hc.enabled = ? ' => 1));
  144. $rows = Database::select($columns, $joinTable, $where);
  145. foreach ($rows as $row) {
  146. $array[$row['class_name']] = $row;
  147. }
  148. return $array;
  149. }
  150. /**
  151. * Return a list an associative array where keys are the active hook observer class name
  152. * @return array
  153. */
  154. public function listAllHookObservers()
  155. {
  156. $array = array();
  157. $columns = 'id, class_name';
  158. $rows = Database::select($columns, $this->tables[TABLE_HOOK_OBSERVER]);
  159. foreach ($rows as $row) {
  160. $array[$row['class_name']] = $row['id'];
  161. }
  162. return $array;
  163. }
  164. /**
  165. * Return a list an associative array where keys are the active hook observer class name
  166. * @return array
  167. */
  168. public function listAllHookEvents()
  169. {
  170. $array = array();
  171. $columns = 'id, class_name';
  172. $rows = Database::select($columns, $this->tables[TABLE_HOOK_EVENT]);
  173. foreach ($rows as $row) {
  174. $array[$row['class_name']] = $row['id'];
  175. }
  176. return $array;
  177. }
  178. /**
  179. * Return a list an associative array where keys are the active hook observer class name
  180. * @return array
  181. */
  182. public function listAllHookCalls()
  183. {
  184. $array = array();
  185. $joinTable = $this->tables[TABLE_HOOK_CALL].' hc'.
  186. ' INNER JOIN '.$this->tables[TABLE_HOOK_EVENT].' he'.
  187. ' ON hc.hook_event_id = he.id '.
  188. ' INNER JOIN '.$this->tables[TABLE_HOOK_OBSERVER].' ho '.
  189. ' ON hc.hook_observer_id = ho.id ';
  190. $columns = 'he.class_name AS event_class_name, ho.class_name AS observer_class_name, hc.id AS id, hc.type AS type';
  191. $rows = Database::select($columns, $joinTable);
  192. foreach ($rows as $row) {
  193. $array[$row['event_class_name']][$row['observer_class_name']][$row['type']] = $row['id'];
  194. }
  195. return $array;
  196. }
  197. /**
  198. * Check if hooks (event, observer, call) exist in Database, if not,
  199. * Will insert them into their respective table
  200. * @param string $eventName
  201. * @param string $observerClassName
  202. *
  203. * @return int
  204. */
  205. public function insertHookIfNotExist($eventName = null, $observerClassName = null)
  206. {
  207. // Check if exists hook event
  208. if (isset($eventName) && !isset($this->hookEvents[$eventName])) {
  209. $attributes = array(
  210. 'class_name' => $eventName,
  211. 'description' => get_lang('HookDescription'.$eventName),
  212. );
  213. $id = Database::insert($this->tables[TABLE_HOOK_EVENT], $attributes);
  214. $this->hookEvents[$eventName] = $id;
  215. }
  216. // Check if exists hook observer
  217. if (isset($observerClassName) &&
  218. !isset($this->hookObservers[$observerClassName])
  219. ) {
  220. $object = $observerClassName::create();
  221. $attributes = array(
  222. 'class_name' => $observerClassName,
  223. 'path' => $object->getPath(),
  224. 'plugin_name' => $object->getPluginName(),
  225. );
  226. $id = Database::insert($this->tables[TABLE_HOOK_OBSERVER], $attributes);
  227. $this->hookObservers[$observerClassName] = $id;
  228. }
  229. if (
  230. isset($eventName) &&
  231. isset($observerClassName) &&
  232. !isset($this->hookCalls[$eventName][$observerClassName])
  233. ) {
  234. // HOOK TYPE PRE
  235. $row = Database::select(
  236. 'MAX(hook_order) as hook_order',
  237. $this->tables[TABLE_HOOK_CALL],
  238. array(
  239. 'where' => array(
  240. 'hook_event_id = ? ' =>$this->hookEvents[$eventName],
  241. 'AND type = ? ' => HOOK_EVENT_TYPE_PRE,
  242. ),
  243. ),
  244. 'ASSOC'
  245. );
  246. // Check if exists hook call
  247. $id = Database::insert(
  248. $this->tables[TABLE_HOOK_CALL],
  249. array(
  250. 'hook_event_id' => $this->hookEvents[$eventName],
  251. 'hook_observer_id' => $this->hookObservers[$observerClassName],
  252. 'type' => HOOK_EVENT_TYPE_PRE,
  253. 'enabled' => 0,
  254. 'hook_order' => $row['hook_order'] + 1,
  255. )
  256. );
  257. $this->hookCalls[$eventName][$observerClassName][HOOK_EVENT_TYPE_PRE] = $id;
  258. // HOOK TYPE POST
  259. $row = Database::select(
  260. 'MAX(hook_order) as hook_order',
  261. $this->tables[TABLE_HOOK_CALL],
  262. array(
  263. 'where' => array(
  264. 'hook_event_id = ? ' =>$this->hookEvents[$eventName],
  265. 'AND type = ? ' => HOOK_EVENT_TYPE_POST,
  266. ),
  267. ),
  268. 'ASSOC'
  269. );
  270. // Check if exists hook call
  271. $id = Database::insert(
  272. $this->tables[TABLE_HOOK_CALL],
  273. array(
  274. 'hook_event_id' => $this->hookEvents[$eventName],
  275. 'hook_observer_id' => $this->hookObservers[$observerClassName],
  276. 'type' => HOOK_EVENT_TYPE_POST,
  277. 'enabled' => 0,
  278. 'hook_order' => $row['hook_order'] + 1,
  279. )
  280. );
  281. $this->hookCalls[$eventName][$observerClassName][HOOK_EVENT_TYPE_POST] = $id;
  282. } elseif (isset($eventName) && !isset($observerClassName)) {
  283. foreach ($this->hookObservers as $observer => $id) {
  284. $this->insertHookIfNotExist($eventName, $observer);
  285. }
  286. } elseif (!isset($eventName) && isset($observerClassName)) {
  287. foreach ($this->hookEvents as $event => $id) {
  288. $this->insertHookIfNotExist($event, $observerClassName);
  289. }
  290. }
  291. return 1;
  292. }
  293. /**
  294. * Return the hook call id identified by hook event, hook observer and type
  295. * @param string $eventName
  296. * @param string $observerClassName
  297. * @param int $type
  298. *
  299. * @return mixed
  300. */
  301. public function getHookCallId($eventName, $observerClassName, $type)
  302. {
  303. $eventName = Database::escape_string($eventName);
  304. $observerClassName($observerClassName);
  305. $type = Database::escape_string($type);
  306. $joinTable = $this->tables[TABLE_HOOK_CALL].' hc'.
  307. ' INNER JOIN '.$this->tables[TABLE_HOOK_EVENT].' he'.
  308. ' ON hc.hook_event_id = he.id '.
  309. ' INNER JOIN '.$this->tables[TABLE_HOOK_OBSERVER].' ho '.
  310. ' ON hc.hook_observer_id = ho.id ';
  311. $row = Database::select(
  312. 'id',
  313. $joinTable,
  314. array(
  315. 'where' => array(
  316. 'he.class_name = ? ' => $eventName,
  317. 'AND ho.class_name = ? ' => $observerClassName,
  318. 'AND hc.type = ? ' => $type,
  319. ),
  320. ),
  321. 'ASSOC'
  322. );
  323. return $row['id'];
  324. }
  325. }