PageRenderTime 27ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/src/Sifo/Debug/DataBaseHandler.php

http://github.com/alombarte/SIFO
PHP | 300 lines | 201 code | 43 blank | 56 comment | 6 complexity | 5d8dafb287ceaf2f6da228d8f9bf28a2 MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.1, GPL-2.0, BSD-3-Clause
  1. <?php
  2. namespace Sifo;
  3. use DateTime;
  4. use PDO;
  5. use PDOException;
  6. use function var_export;
  7. class DebugDataBaseHandler
  8. {
  9. /**
  10. * @var string Path to store the Sifo database (set in the class constructor in order to build it based on the ROOT_PATH).
  11. */
  12. private $db_path;
  13. /**
  14. * @var string Sifo database name
  15. */
  16. private $db_name = 'sifo.sqlite3';
  17. /**
  18. * @var string table to store execution debugs name
  19. */
  20. private $table_name = 'execution_debugs';
  21. /**
  22. * @var int We'll keep the executions of the last $days_to_keep_debugs days in the database
  23. */
  24. private $days_to_keep_debugs = 1;
  25. /**
  26. * Connects to the Sifo database and initializes the debug table if it doesn't exists
  27. */
  28. function __construct()
  29. {
  30. $this->db_path = ROOT_PATH . '/logs/';
  31. try
  32. {
  33. $this->persistence = new PDO( 'sqlite:' . $this->db_path . $this->db_name );
  34. $this->persistence->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); // Set database errors mode to exceptions
  35. }
  36. catch ( PDOException $e )
  37. {
  38. trigger_error( "[sifo] [debug] Could not connect to the debug database using the following DSN: 'sqlite:" . $this->db_path . $this->db_name . "'.\n
  39. Error message: " . $e->getMessage() );
  40. }
  41. $this->createSifoDebugDbTable();
  42. }
  43. /**
  44. * Initializes the Sifo debug database table
  45. */
  46. private function createSifoDebugDbTable()
  47. {
  48. try
  49. {
  50. $this->persistence->exec( "CREATE TABLE IF NOT EXISTS $this->table_name (
  51. execution_key TEXT PRIMARY KEY,
  52. url TEXT,
  53. debug_content TEXT,
  54. is_json INTEGER,
  55. is_pinned INTEGER,
  56. timestamp INTEGER,
  57. parent_execution_key TEXT)" );
  58. $this->persistence->exec( "CREATE INDEX IF NOT EXISTS timestamp_index ON $this->table_name( timestamp, is_pinned )" );
  59. }
  60. catch ( PDOException $e )
  61. {
  62. trigger_error( "[sifo] [debug] Could not create the Sifo debug database.\n
  63. Error message: " . $e->getMessage() . "\n
  64. Error info: " . var_export($this->persistence->errorInfo(), true) );
  65. }
  66. }
  67. /**
  68. * Saves an execution debug on the Sifo debug database.
  69. *
  70. * @param string $execution_key unique identifier of the execution to store.
  71. * @param string $url
  72. * @param array $debug_content containing all the debug data and its debug modules.
  73. * @param bool $is_json indicating if this execution is returned as a JSON or not.
  74. */
  75. public function saveExecutionDebug( $execution_key, $url, $debug_content, $is_json )
  76. {
  77. try
  78. {
  79. $insert = "INSERT OR REPLACE INTO $this->table_name (execution_key, url, debug_content, is_json, is_pinned, timestamp)
  80. VALUES ( :execution_key, :url, :debug_content, :is_json, 0, :timestamp )";
  81. $statement = $this->persistence->prepare( $insert );
  82. $date_time = new DateTime();
  83. $timestamp = $date_time->getTimestamp();
  84. $is_json = (int) $is_json;
  85. $statement->bindParam( ':execution_key', $execution_key, PDO::PARAM_STR );
  86. $statement->bindParam( ':url', $url, PDO::PARAM_STR );
  87. $encoded_debug = json_encode( $debug_content );
  88. $statement->bindParam( ':debug_content', $encoded_debug , PDO::PARAM_STR );
  89. $statement->bindParam( ':is_json', $is_json, PDO::PARAM_INT );
  90. $statement->bindParam( ':timestamp', $timestamp, PDO::PARAM_INT );
  91. $statement->execute();
  92. }
  93. catch ( PDOException $e )
  94. {
  95. trigger_error( "[sifo] [debug] Could not insert the execution debug record in the Sifo debug database.\n
  96. Error message: " . $e->getMessage() . "\n
  97. Error info: " . var_export($this->persistence->errorInfo(), true) );
  98. }
  99. }
  100. /**
  101. * Deletes execution debugs older than $this->days_to_keep_debugs days.
  102. * Do not delete the pinned execution debugs.
  103. */
  104. public function cleanOldExecutionDebugs()
  105. {
  106. try
  107. {
  108. $delete = "DELETE FROM $this->table_name WHERE timestamp <= :timestamp AND is_pinned = 0";
  109. $statement = $this->persistence->prepare( $delete );
  110. $date_time_to_delete = new DateTime();
  111. $date_time_to_delete->sub( new \DateInterval( 'P' . $this->days_to_keep_debugs . 'D' ) );
  112. $timestamp = $date_time_to_delete->getTimestamp();
  113. $statement->bindParam( ':timestamp', $timestamp, PDO::PARAM_INT );
  114. $statement->execute();
  115. }
  116. catch ( PDOException $e )
  117. {
  118. trigger_error( "[sifo] [debug] Could not delete the old execution debugs records from the Sifo debug database.\n
  119. Error message: " . $e->getMessage() . "\n
  120. Error info: " . var_export( $this->persistence->errorInfo(), true));
  121. }
  122. }
  123. /**
  124. * Returns all the execution debug data based on an ID.
  125. *
  126. * @param string $execution_key Execution debug identifier.
  127. *
  128. * @return bool|mixed false if we couldn't execute the prepared statement. All execution debug data in an associative array otherwise.
  129. */
  130. public function getExecutionDebugWithChildrenById( $execution_key )
  131. {
  132. try
  133. {
  134. $query = "SELECT execution_key, url, debug_content, is_json, is_pinned, timestamp, parent_execution_key FROM $this->table_name WHERE execution_key = :execution_key OR parent_execution_key = :execution_key";
  135. $statement = $this->persistence->prepare( $query );
  136. $statement->bindParam( ':execution_key', $execution_key, PDO::PARAM_STR );
  137. if ( $statement->execute() )
  138. {
  139. // Structure in the $all_executions_debug_data the parent execution data and an array of children executions depending
  140. // on if the execution_key is the received one or not.
  141. $all_executions_debug_data = array();
  142. foreach ( $statement->fetchAll( PDO::FETCH_ASSOC ) as $execution_debug_data )
  143. {
  144. if ( $execution_debug_data['execution_key'] == $execution_key )
  145. {
  146. $all_executions_debug_data['parent_execution'] = $this->unmapExecutionDebugData( $execution_debug_data );
  147. }
  148. else
  149. {
  150. $all_executions_debug_data['children_executions'][$execution_debug_data['execution_key']] = $this->unmapExecutionDebugData( $execution_debug_data );
  151. }
  152. }
  153. return $all_executions_debug_data;
  154. }
  155. else
  156. {
  157. return false;
  158. }
  159. }
  160. catch ( PDOException $e )
  161. {
  162. trigger_error( "[sifo] [debug] Could not get the execution debug content from the Sifo debug database for the execution ID: $execution_key.\n
  163. Error message: " . $e->getMessage() . "\n
  164. Error info: " . var_export($this->persistence->errorInfo(), true) );
  165. return false;
  166. }
  167. }
  168. /**
  169. * Unmap the data stored in the database to the format expected by the controller in order to deal with it.
  170. *
  171. * @param array $execution_debug_data with all the execution debug raw data retrieved from the data base as it was stored.
  172. *
  173. * @return array of saved execution debug data formatted properly in order to bring it to the controller.
  174. */
  175. private function unmapExecutionDebugData( $execution_debug_data )
  176. {
  177. $execution_debug_data['debug_content'] = json_decode( $execution_debug_data['debug_content'], true );
  178. $execution_debug_data['date_time'] = new DateTime( '@' . $execution_debug_data['timestamp'] );
  179. $execution_debug_data['date_time'] = $execution_debug_data['date_time']->format( 'Y-m-d H:i:s' );
  180. return $execution_debug_data;
  181. }
  182. /**
  183. * Returns the last execution_key inserted in the sifo debug table without taking into account the children executions.
  184. *
  185. * @param bool $is_json filter by json executions or not:
  186. * false: return only non json executions (default)
  187. * true: return only json executions
  188. * null: return the last execution without taking into account if it's json or not
  189. *
  190. * @return bool|string depending on if we could execute the prepared statement or not.
  191. */
  192. public function getLastParentExecutionKey( $is_json = null )
  193. {
  194. try
  195. {
  196. $query = "SELECT execution_key FROM $this->table_name WHERE parent_execution_key IS NULL";
  197. if ( isset( $is_json ) )
  198. {
  199. $query .= " AND is_json = " . (int)$is_json;
  200. }
  201. $query .= " ORDER BY timestamp DESC LIMIT 1";
  202. $statement = $this->persistence->prepare( $query );
  203. if ( $statement->execute() )
  204. {
  205. $execution_debug_data = $statement->fetch( PDO::FETCH_ASSOC );
  206. return $execution_debug_data['execution_key'];
  207. }
  208. else
  209. {
  210. return false;
  211. }
  212. }
  213. catch ( PDOException $e )
  214. {
  215. trigger_error( "[sifo] [debug] Could not get the last execution key from the Sifo debug database.\n
  216. Error message: " . $e->getMessage() . "\n
  217. Error info: " . var_export($this->persistence->errorInfo(), true) );
  218. return false;
  219. }
  220. }
  221. public function linkChildExecutionToParent( $child_execution_key, $parent_execution_key )
  222. {
  223. try
  224. {
  225. $query = "UPDATE $this->table_name SET parent_execution_key = :parent_execution_key WHERE execution_key = :child_execution_key";
  226. $statement = $this->persistence->prepare( $query );
  227. $statement->bindParam( ':parent_execution_key', $parent_execution_key, PDO::PARAM_STR );
  228. $statement->bindParam( ':child_execution_key', $child_execution_key, PDO::PARAM_STR );
  229. return $statement->execute();
  230. }
  231. catch ( PDOException $e )
  232. {
  233. trigger_error( "[sifo] [debug] Could not link a child execution to its parent. child_execution_key: $child_execution_key, parent_execution_key: $parent_execution_key.\n
  234. Error message: " . $e->getMessage() . "\n
  235. Error info: " . var_export($this->persistence->errorInfo(), true) );
  236. return false;
  237. }
  238. }
  239. public function pinExecution( $execution_key, $is_pinned )
  240. {
  241. try
  242. {
  243. $query = "UPDATE $this->table_name SET is_pinned = :is_pinned WHERE execution_key = :execution_key OR parent_execution_key = :execution_key";
  244. $statement = $this->persistence->prepare( $query );
  245. $statement->bindParam( ':execution_key', $execution_key, PDO::PARAM_STR );
  246. $statement->bindParam( ':is_pinned', $is_pinned, PDO::PARAM_INT );
  247. return $statement->execute();
  248. }
  249. catch ( PDOException $e )
  250. {
  251. trigger_error( "[sifo] [debug] Could not pin a execution. execution_key: $execution_key, is_pinned: $is_pinned.\n
  252. Error message: " . $e->getMessage() . "\n
  253. Error info: " . var_export($this->persistence->errorInfo(), true) );
  254. return false;
  255. }
  256. }
  257. }