PageRenderTime 51ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/Framework/Packages/Framework/Database/MysqlDatabase.php

https://gitlab.com/Erdrix/overviewCompanies
PHP | 426 lines | 223 code | 59 blank | 144 comment | 44 complexity | c3a7303b90a6616a51258cab67abad9f MD5 | raw file
  1. <?php
  2. class MysqlDatabase implements Database
  3. {
  4. //////////////////////////
  5. // Attributs
  6. /////////
  7. /**
  8. * Objet base de donnée
  9. * @var PDO
  10. */
  11. private $pdo;
  12. /**
  13. * Objet de gestion du cache
  14. * @var Cache
  15. */
  16. private $cache;
  17. /**
  18. * Active ou désactive la mise en cache des requêtes
  19. * @var boolean
  20. */
  21. private $cache_enable;
  22. /**
  23. * Nom du prefix des tables
  24. * @var string
  25. */
  26. private $prefix;
  27. /**
  28. * Définis le fetchMode suivant une classe
  29. * @var string | boolean
  30. */
  31. private $fetchClass = false;
  32. /**
  33. * Définis des jointures dans la requête
  34. * @var array | boolean
  35. */
  36. private $join = false;
  37. /**
  38. * Liste des configurations
  39. * @var array
  40. */
  41. private $conf = [];
  42. //////////////////////////
  43. // Constructeur
  44. /////////
  45. /**
  46. * Initialisation de la base de données
  47. *
  48. * @param array $config : Liste des configuration
  49. * host : Url vers la base de donnée
  50. * user : Nom d'utilisateur
  51. * password : Mot de passe
  52. * db_type : Type de base de donnée (mysql, ...)
  53. * db_name : Nom de la base de donnée
  54. * prefix : Préfix des tables
  55. * charset : Charset de la base de donnée
  56. * debug_level : Niveau de débugage des erreurs sql
  57. * #cache_duration : Durée de mise en cache (0 pour désactiver)
  58. * #cache_directory : Répertoire de sauvegarde du cache
  59. */
  60. public function __construct(array $config)
  61. {
  62. $this->conf = $config;
  63. $this->cache_enable = (isset($config['cache_duration']) && $config['cache_duration']) > 0 ? true : false;
  64. $this->cache = new Cache($config['cache_directory'] ? $config['cache_directory'] : '',
  65. $config['cache_duration'] ? $config['cache_duration'] : 0);
  66. $this->prefix = $config['prefix'];
  67. }
  68. //////////////////////////
  69. // Public Methods
  70. /////////
  71. /**
  72. * Définis une class comme valeur de retour
  73. *
  74. * @param string $class : Nom de la classe
  75. *
  76. * @return Database
  77. */
  78. public function setFetch($class)
  79. {
  80. $this->fetchClass = $class;
  81. return $this;
  82. }
  83. /**
  84. * Définis une liste de r$egle pour les jointures
  85. *
  86. * @param array $join : Liste des jointure
  87. *
  88. * @return Database
  89. */
  90. public function setJoin(array $join)
  91. {
  92. $this->join = $join;
  93. return $this;
  94. }
  95. /**
  96. * Retourne la structure de la table
  97. *
  98. * @param string $table : Nom de la table
  99. *
  100. * @return mixed
  101. */
  102. public function describe($table)
  103. {
  104. return $this->query('DESCRIBE ' . $this->prefix . $table, [], true);
  105. }
  106. /**
  107. * Recherche une/des entrée(s) suivant les le/les critère(s)
  108. *
  109. * @param string $table : Nom de la table à utiliser
  110. * @param array $criteres : Critères de séléction Array['critere' => 'valeur'(, 'critere' => 'valeur')]
  111. * @param string $data : Elements à retourner Array['Element'(, 'Element')] (default *)
  112. * @param mixed $limit : Limite d'elements à retourner (default 50)
  113. * @param mixed $order : Ordre des elements à retourner (default false)
  114. *
  115. * @return mixed Résultat de la requête sql
  116. */
  117. public function search($table, $criteres = [], $data = '*', $limit = 50, $order = false)
  118. {
  119. if (!is_array($criteres)) {
  120. return [];
  121. }
  122. $class = $this->fetchClass;
  123. $this->fetchClass = false;
  124. if (is_array($data)) {
  125. foreach ($data as $col) {
  126. $column[] = $this->prefix . $table . '.' . $col;
  127. }
  128. } else {
  129. $column[] = $this->prefix . $table . '.' . $data;
  130. }
  131. if ($order) {
  132. $order = ' ORDER BY ' . $table . '.' . $order;
  133. }
  134. $one = $limit === 1 ? true : false;
  135. if ($limit !== false) {
  136. $limit = ' LIMIT ' . $limit;
  137. }
  138. if ($this->join) {
  139. $join = '';
  140. foreach ($this->join as $table_join => $columns) {
  141. foreach ($this->describe($table_join) as $structure) {
  142. $column[] = $this->prefix . $table_join . '.' . $structure['Field'] . ' AS ' . $table_join . '_' .
  143. $structure['Field'];
  144. }
  145. $join .=
  146. ' LEFT JOIN ' . $this->prefix . $table_join . ' ON ' . $this->prefix . $table . '.' . $columns[0] .
  147. ' = ' . $this->prefix . $table_join . '.' . $columns[1];
  148. }
  149. $this->join = false;
  150. } else {
  151. $join = false;
  152. }
  153. $column = implode($column, ', ');
  154. $this->fetchClass = $class;
  155. return $this->query('SELECT ' . $column . ' FROM ' . $this->prefix . $table . $join .
  156. $this->parseSQLWhere($criteres, $table) . $order . $limit, $criteres, true, $one);
  157. }
  158. /**
  159. * Execution d'une requête sql par PDO::prepare
  160. *
  161. * @param string $query : Requête sql
  162. * @param array $data : Données d'execution de la requête
  163. * @param boolean $fetch : Execute fetchAll (defaut false)
  164. * @param boolean $one : Retourne un element de la base
  165. *
  166. * @return mixed Résultat de la requête si fetch à true
  167. */
  168. public function query($query, $data = [], $fetch = false, $one = false)
  169. {
  170. Benchmark::mark('database');
  171. $hash = hash('md2', $query . implode($data, '-'));
  172. if ($fetch) {
  173. if ($content = $this->cache->read($hash)) {
  174. Benchmark::end('database');
  175. return $content;
  176. }
  177. }
  178. $requete = $this->getPdo()->prepare($query);
  179. $data = $requete->execute($data);
  180. if ($fetch) {
  181. if ($this->fetchClass !== false) {
  182. $requete->setFetchMode(PDO::FETCH_CLASS, $this->fetchClass);
  183. $this->fetchClass = false;
  184. }
  185. if ($one) {
  186. $data = $requete->fetch();
  187. } else {
  188. $data = $requete->fetchAll();
  189. }
  190. }
  191. if ($fetch && !$one && $this->cache_enable) {
  192. $this->cache->write($hash, $data);
  193. }
  194. Benchmark::end('database');
  195. return $data;
  196. }
  197. /**
  198. * Transforme un tableau en critères de recherche SQL
  199. *
  200. * @param array $criteres : Array['critere' => 'valeur'(, 'critere' => 'valeur')]
  201. * @param mixed $table : Nom de la table d'identification
  202. *
  203. * @return string Critères de recherche de requête SQL 'WHERE'
  204. */
  205. public function parseSQLWhere($criteres, $table = false)
  206. {
  207. if (count($criteres) > 0) {
  208. $where = ' WHERE ';
  209. foreach ($criteres as $key => $value) {
  210. $already = strpos($key, '.') === false;
  211. if (strpos($value, '%') !== false) {
  212. $where .= ($already && $table !== false ? $this->prefix . $table . '.' : '') . $key . ' LIKE \'' .
  213. $value .
  214. '\' AND ';
  215. } else {
  216. $where .=
  217. ($already && $table !== false ? $this->prefix . $table . '.' : '') . $key . ' = :' . $key .
  218. ' AND ';
  219. }
  220. }
  221. return substr($where, 0, -5);
  222. } else {
  223. return '';
  224. }
  225. }
  226. /**
  227. * Efface une/des entrée(s) suivant les le/les critère(s)
  228. *
  229. * @param string $table : Nom de la table à utiliser
  230. * @param array $criteres : Array['critere' => 'valeur'(, 'critere' => 'valeur')]
  231. *
  232. * @return boolean False si une erreur est survenue
  233. */
  234. public function delete($table, $criteres)
  235. {
  236. if (!isset($criteres) || !is_array($criteres)) {
  237. return false;
  238. }
  239. $this->cache->clear();
  240. return $this->query('DELETE FROM ' . $this->prefix . $table . $this->parseSQLWhere($criteres), $criteres);
  241. }
  242. /**
  243. * Insert dans la table la/les valeur(s) contenu dans le tableau
  244. *
  245. * @param string $table : Nom de la table à utiliser
  246. * @param array $data : Array['critere' => 'valeur'(, 'critere' => 'valeur')]
  247. *
  248. * @return boolean False si une erreur est survenue
  249. */
  250. public function insert($table, array $data)
  251. {
  252. if (!isset($data) || !is_array($data)) {
  253. return false;
  254. }
  255. $tables = '';
  256. $values = '';
  257. if (count($data) > 0) {
  258. foreach ($data as $key => $value) {
  259. $tables .= '`' . $key . '`, ';
  260. $values .= ':' . $key . ', ';
  261. }
  262. $tables = substr($tables, 0, -2);
  263. $values = substr($values, 0, -2);
  264. }
  265. $this->cache->clear();
  266. if ($this->query('INSERT INTO ' . $this->prefix . $table . ' (' . $tables . ') VALUES (' .
  267. $values . ')', $data)
  268. ) {
  269. return $this->getPdo()->lastInsertId();
  270. } else {
  271. return false;
  272. }
  273. }
  274. /**
  275. * Modifie la/les donnée(s) suivant le/les critère(s)
  276. *
  277. * @param string $table : Nom de la table à utiliser
  278. * @param array $data : Array['critere' => 'valeur'(, 'critere' => 'valeur')]
  279. * @param array $criteres : Array['critere' => 'valeur'(, 'critere' => 'valeur')]
  280. *
  281. * @return boolean False si une erreur est survenue
  282. */
  283. public function update($table, $data, $criteres)
  284. {
  285. if (!isset($data) || !is_array($data) || !isset($criteres) || !is_array($criteres)) {
  286. return false;
  287. }
  288. $update = $criteres;
  289. $values = '';
  290. if (count($data) > 0) {
  291. foreach ($data as $key => $value) {
  292. if ("" !== $value) {
  293. $values .= $key . ' = :val_' . $key . ', ';
  294. $update['val_' . $key] = $value;
  295. }
  296. }
  297. $values = substr($values, 0, -2);
  298. }
  299. $this->cache->clear();
  300. if ($this->query('UPDATE ' . $this->prefix . $table . ' SET ' . $values . $this->parseSQLWhere($criteres),
  301. $update)
  302. ) {
  303. return $this->getPdo()->lastInsertId();
  304. } else {
  305. return false;
  306. }
  307. }
  308. /**
  309. * Recherche si le/les critère(s) sont présent dans la base de données
  310. *
  311. * @param string $table : Nom de la table à utiliser
  312. * @param array $criteres : Array['critere' => 'valeur'(, 'critere' => 'valeur')]
  313. *
  314. * @return boolean True si présent dans la base de données
  315. */
  316. public function isexist($table, $criteres)
  317. {
  318. if (!is_array($criteres)) {
  319. return false;
  320. }
  321. $data = $this->query('SELECT COUNT(*) AS nb FROM ' . $this->prefix . $table . $this->parseSQLWhere($criteres),
  322. $criteres, true);
  323. if ($data['0']['nb'] > 0) {
  324. return $data['0']['nb'];
  325. }
  326. return false;
  327. }
  328. //////////////////////////
  329. // Private Methods
  330. /////////
  331. /**
  332. * Retourne l'instance pdo ou la crée si necessaire
  333. *
  334. * @return PDO
  335. * @throws Exception
  336. */
  337. private function getPdo()
  338. {
  339. if (!isset($this->pdo)) {
  340. try {
  341. $charset = '' != $this->conf['charset'] ? ';charset=' . $this->conf['charset'] : '';
  342. $this->pdo = new PDO($this->conf['db_type'] . ':host=' . $this->conf['host'] . ';dbname=' .
  343. $this->conf['db_name'] . $charset, $this->conf['user'], $this->conf['password']);
  344. $this->pdo->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_EMPTY_STRING);
  345. $this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
  346. switch ($this->conf['debug_level']) {
  347. case 0:
  348. $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
  349. break;
  350. case 1:
  351. $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
  352. break;
  353. case 2:
  354. $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  355. break;
  356. default:
  357. break;
  358. }
  359. } catch (PDOException $Exception) {
  360. if ($this->conf['debug_level'] > 0) {
  361. throw new Exception($Exception->getMessage(), $Exception->getCode());
  362. }
  363. }
  364. }
  365. return $this->pdo;
  366. }
  367. }