HookManagement.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  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(
  48. 'id, enabled',
  49. $this->tables[TABLE_HOOK_CALL],
  50. array(
  51. 'where' => array(
  52. 'hook_event_id = ? ' => $this->hookEvents[$eventName],
  53. 'AND hook_observer_id = ? ' => $this->hookObservers[$observerClassName],
  54. 'AND type = ? ' => $type,
  55. ),
  56. ),
  57. 'ASSOC'
  58. );
  59. if (!empty($row) && is_array($row)) {
  60. // Check if is hook call is active
  61. if ((int) $row['enabled'] === 0) {
  62. Database::update(
  63. $this->tables[TABLE_HOOK_CALL],
  64. array(
  65. 'enabled' => 1,
  66. ),
  67. array(
  68. 'id = ?' => $row['id'],
  69. )
  70. );
  71. }
  72. }
  73. }
  74. }
  75. /**
  76. * Delete hook from Database. Return deleted rows number
  77. * @param string $eventName
  78. * @param string $observerClassName
  79. * @param int $type
  80. *
  81. * @return int
  82. */
  83. public function deleteHook($eventName, $observerClassName, $type)
  84. {
  85. if ($type === HOOK_EVENT_TYPE_ALL) {
  86. $this->deleteHook($eventName, $observerClassName, HOOK_EVENT_TYPE_PRE);
  87. $this->deleteHook($eventName, $observerClassName, HOOK_EVENT_TYPE_POST);
  88. } else {
  89. $this->insertHookIfNotExist($eventName, $observerClassName);
  90. Database::update(
  91. $this->tables[TABLE_HOOK_CALL],
  92. array(
  93. 'enabled' => 0,
  94. ),
  95. array(
  96. 'id = ? ' => $this->hookCalls[$eventName][$observerClassName][$type],
  97. )
  98. );
  99. }
  100. }
  101. /**
  102. * Update hook observer order by hook event
  103. * @param $eventName
  104. * @param $type
  105. * @param $hookOrders
  106. *
  107. * @return int
  108. */
  109. public function orderHook($eventName, $type, $hookOrders)
  110. {
  111. foreach ($this->hookCalls[$eventName] as $observerClassName => $types) {
  112. foreach ($hookOrders as $oldOrder => $newOrder) {
  113. $res = Database::update(
  114. $this->tables[TABLE_HOOK_CALL],
  115. array(
  116. 'hook_order ' => $newOrder,
  117. ),
  118. array(
  119. 'id = ? ' => $types[$type],
  120. 'AND hook_order = ? ' => $oldOrder,
  121. )
  122. );
  123. if ($res) {
  124. break;
  125. }
  126. }
  127. }
  128. }
  129. /**
  130. * Return a list an associative array where keys are the active hook observer class name
  131. * @param string $eventName
  132. *
  133. * @return array
  134. */
  135. public function listHookObservers($eventName)
  136. {
  137. $array = array();
  138. $joinTable = $this->tables[TABLE_HOOK_CALL].' hc'.
  139. ' INNER JOIN '.$this->tables[TABLE_HOOK_EVENT].' he'.
  140. ' ON hc.hook_event_id = he.id '.
  141. ' INNER JOIN '.$this->tables[TABLE_HOOK_OBSERVER].' ho '.
  142. ' ON hc.hook_observer_id = ho.id ';
  143. $columns = 'ho.class_name, ho.path, ho.plugin_name, hc.enabled';
  144. $where = array('where' => array('he.class_name = ? ' => $eventName, 'AND hc.enabled = ? ' => 1));
  145. $rows = Database::select($columns, $joinTable, $where);
  146. foreach ($rows as $row) {
  147. $array[$row['class_name']] = $row;
  148. }
  149. return $array;
  150. }
  151. /**
  152. * Return a list an associative array where keys are the active hook observer class name
  153. * @return array
  154. */
  155. public function listAllHookObservers()
  156. {
  157. $array = array();
  158. $columns = 'id, class_name';
  159. $rows = Database::select($columns, $this->tables[TABLE_HOOK_OBSERVER]);
  160. foreach ($rows as $row) {
  161. $array[$row['class_name']] = $row['id'];
  162. }
  163. return $array;
  164. }
  165. /**
  166. * Return a list an associative array where keys are the active hook observer class name
  167. * @return array
  168. */
  169. public function listAllHookEvents()
  170. {
  171. $array = array();
  172. $columns = 'id, class_name';
  173. $rows = Database::select($columns, $this->tables[TABLE_HOOK_EVENT]);
  174. foreach ($rows as $row) {
  175. $array[$row['class_name']] = $row['id'];
  176. }
  177. return $array;
  178. }
  179. /**
  180. * Return a list an associative array where keys are the active hook observer class name
  181. * @return array
  182. */
  183. public function listAllHookCalls()
  184. {
  185. $array = array();
  186. $joinTable = $this->tables[TABLE_HOOK_CALL].' hc'.
  187. ' INNER JOIN '.$this->tables[TABLE_HOOK_EVENT].' he'.
  188. ' ON hc.hook_event_id = he.id '.
  189. ' INNER JOIN '.$this->tables[TABLE_HOOK_OBSERVER].' ho '.
  190. ' ON hc.hook_observer_id = ho.id ';
  191. $columns = 'he.class_name AS event_class_name, ho.class_name AS observer_class_name, hc.id AS id, hc.type AS type';
  192. $rows = Database::select($columns, $joinTable);
  193. foreach ($rows as $row) {
  194. $array[$row['event_class_name']][$row['observer_class_name']][$row['type']] = $row['id'];
  195. }
  196. return $array;
  197. }
  198. /**
  199. * Check if hooks (event, observer, call) exist in Database, if not,
  200. * Will insert them into their respective table
  201. * @param string $eventName
  202. * @param string $observerClassName
  203. *
  204. * @return int
  205. */
  206. public function insertHookIfNotExist($eventName = null, $observerClassName = null)
  207. {
  208. // Check if exists hook event
  209. if (isset($eventName) && !isset($this->hookEvents[$eventName])) {
  210. $attributes = array(
  211. 'class_name' => $eventName,
  212. 'description' => get_lang('HookDescription'.$eventName),
  213. );
  214. $id = Database::insert($this->tables[TABLE_HOOK_EVENT], $attributes);
  215. $this->hookEvents[$eventName] = $id;
  216. }
  217. // Check if exists hook observer
  218. if (isset($observerClassName) &&
  219. !isset($this->hookObservers[$observerClassName])
  220. ) {
  221. $object = $observerClassName::create();
  222. $attributes = array(
  223. 'class_name' => $observerClassName,
  224. 'path' => $object->getPath(),
  225. 'plugin_name' => $object->getPluginName(),
  226. );
  227. $id = Database::insert($this->tables[TABLE_HOOK_OBSERVER], $attributes);
  228. $this->hookObservers[$observerClassName] = $id;
  229. }
  230. if (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. }