api de gestion de ticket, basé sur php-crud-api. Le but est de décorrélé les outils de gestion des données, afin
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

GenericDB.php 8.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. <?php
  2. namespace Tqdev\PhpCrudApi\Database;
  3. use Tqdev\PhpCrudApi\Record\Condition\ColumnCondition;
  4. use Tqdev\PhpCrudApi\Record\Condition\Condition;
  5. use Tqdev\PhpCrudApi\Column\Reflection\ReflectedTable;
  6. class GenericDB
  7. {
  8. private $driver;
  9. private $database;
  10. private $pdo;
  11. private $reflection;
  12. private $columns;
  13. private $conditions;
  14. private $converter;
  15. private function getDsn(String $address, String $port = null, String $database = null): String
  16. {
  17. switch ($this->driver) {
  18. case 'mysql':return "$this->driver:host=$address;port=$port;dbname=$database;charset=utf8mb4";
  19. case 'pgsql':return "$this->driver:host=$address port=$port dbname=$database options='--client_encoding=UTF8'";
  20. case 'sqlsrv':return "$this->driver:Server=$address,$port;Database=$database";
  21. }
  22. }
  23. private function getCommands(): array
  24. {
  25. switch ($this->driver) {
  26. case 'mysql':return [
  27. 'SET SESSION sql_warnings=1;',
  28. 'SET NAMES utf8mb4;',
  29. 'SET SESSION sql_mode = "ANSI,TRADITIONAL";',
  30. ];
  31. case 'pgsql':return [
  32. "SET NAMES 'UTF8';",
  33. ];
  34. case 'sqlsrv':return [
  35. ];
  36. }
  37. }
  38. private function getOptions(): array
  39. {
  40. $options = array(
  41. \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
  42. \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
  43. );
  44. switch ($this->driver) {
  45. case 'mysql':return $options + [
  46. \PDO::ATTR_EMULATE_PREPARES => false,
  47. \PDO::MYSQL_ATTR_FOUND_ROWS => true,
  48. ];
  49. case 'pgsql':return $options + [
  50. \PDO::ATTR_EMULATE_PREPARES => false,
  51. ];
  52. case 'sqlsrv':return $options + [
  53. \PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE => true,
  54. ];
  55. }
  56. }
  57. public function __construct(String $driver, String $address, String $port = null, String $database = null, String $username = null, String $password = null)
  58. {
  59. $this->driver = $driver;
  60. $this->database = $database;
  61. $dsn = $this->getDsn($address, $port, $database);
  62. $options = $this->getOptions();
  63. $this->pdo = new \PDO($dsn, $username, $password, $options);
  64. $commands = $this->getCommands();
  65. foreach ($commands as $command) {
  66. $this->pdo->query($command);
  67. }
  68. $this->reflection = new GenericReflection($this->pdo, $driver, $database);
  69. $this->definition = new GenericDefinition($this->pdo, $driver, $database);
  70. $this->conditions = new ConditionsBuilder($driver);
  71. $this->columns = new ColumnsBuilder($driver);
  72. $this->converter = new DataConverter($driver);
  73. }
  74. public function pdo(): \PDO
  75. {
  76. return $this->pdo;
  77. }
  78. public function reflection(): GenericReflection
  79. {
  80. return $this->reflection;
  81. }
  82. public function definition(): GenericDefinition
  83. {
  84. return $this->definition;
  85. }
  86. public function createSingle(ReflectedTable $table, array $columnValues) /*: ?String*/
  87. {
  88. $this->converter->convertColumnValues($table, $columnValues);
  89. $insertColumns = $this->columns->getInsert($table, $columnValues);
  90. $tableName = $table->getName();
  91. $pkName = $table->getPk()->getName();
  92. $parameters = array_values($columnValues);
  93. $sql = 'INSERT INTO "' . $tableName . '" ' . $insertColumns;
  94. $stmt = $this->query($sql, $parameters);
  95. // return primary key value if specified in the input
  96. if (isset($columnValues[$pkName])) {
  97. return $columnValues[$pkName];
  98. }
  99. // work around missing "returning" or "output" in mysql
  100. switch ($this->driver) {
  101. case 'mysql':
  102. $stmt = $this->query('SELECT LAST_INSERT_ID()', []);
  103. break;
  104. }
  105. return $stmt->fetchColumn(0);
  106. }
  107. public function selectSingle(ReflectedTable $table, array $columnNames, String $id) /*: ?array*/
  108. {
  109. $selectColumns = $this->columns->getSelect($table, $columnNames);
  110. $tableName = $table->getName();
  111. $condition = new ColumnCondition($table->getPk(), 'eq', $id);
  112. $parameters = array();
  113. $whereClause = $this->conditions->getWhereClause($condition, $parameters);
  114. $sql = 'SELECT ' . $selectColumns . ' FROM "' . $tableName . '" ' . $whereClause;
  115. $stmt = $this->query($sql, $parameters);
  116. $record = $stmt->fetch() ?: null;
  117. if ($record === null) {
  118. return null;
  119. }
  120. $records = array($record);
  121. $this->converter->convertRecords($table, $columnNames, $records);
  122. return $records[0];
  123. }
  124. public function selectMultiple(ReflectedTable $table, array $columnNames, array $ids): array
  125. {
  126. if (count($ids) == 0) {
  127. return [];
  128. }
  129. $selectColumns = $this->columns->getSelect($table, $columnNames);
  130. $tableName = $table->getName();
  131. $condition = new ColumnCondition($table->getPk(), 'in', implode(',', $ids));
  132. $parameters = array();
  133. $whereClause = $this->conditions->getWhereClause($condition, $parameters);
  134. $sql = 'SELECT ' . $selectColumns . ' FROM "' . $tableName . '" ' . $whereClause;
  135. $stmt = $this->query($sql, $parameters);
  136. $records = $stmt->fetchAll();
  137. $this->converter->convertRecords($table, $columnNames, $records);
  138. return $records;
  139. }
  140. public function selectCount(ReflectedTable $table, Condition $condition): int
  141. {
  142. $tableName = $table->getName();
  143. $parameters = array();
  144. $whereClause = $this->conditions->getWhereClause($condition, $parameters);
  145. $sql = 'SELECT COUNT(*) FROM "' . $tableName . '"' . $whereClause;
  146. $stmt = $this->query($sql, $parameters);
  147. return $stmt->fetchColumn(0);
  148. }
  149. public function selectAllUnordered(ReflectedTable $table, array $columnNames, Condition $condition): array
  150. {
  151. $selectColumns = $this->columns->getSelect($table, $columnNames);
  152. $tableName = $table->getName();
  153. $parameters = array();
  154. $whereClause = $this->conditions->getWhereClause($condition, $parameters);
  155. $sql = 'SELECT ' . $selectColumns . ' FROM "' . $tableName . '"' . $whereClause;
  156. $stmt = $this->query($sql, $parameters);
  157. $records = $stmt->fetchAll();
  158. $this->converter->convertRecords($table, $columnNames, $records);
  159. return $records;
  160. }
  161. public function selectAll(ReflectedTable $table, array $columnNames, Condition $condition, array $columnOrdering, int $offset, int $limit): array
  162. {
  163. if ($limit == 0) {
  164. return array();
  165. }
  166. $selectColumns = $this->columns->getSelect($table, $columnNames);
  167. $tableName = $table->getName();
  168. $parameters = array();
  169. $whereClause = $this->conditions->getWhereClause($condition, $parameters);
  170. $orderBy = $this->columns->getOrderBy($table, $columnOrdering);
  171. $offsetLimit = $this->columns->getOffsetLimit($offset, $limit);
  172. $sql = 'SELECT ' . $selectColumns . ' FROM "' . $tableName . '"' . $whereClause . ' ORDER BY ' . $orderBy . ' ' . $offsetLimit;
  173. $stmt = $this->query($sql, $parameters);
  174. $records = $stmt->fetchAll();
  175. $this->converter->convertRecords($table, $columnNames, $records);
  176. return $records;
  177. }
  178. public function updateSingle(ReflectedTable $table, array $columnValues, String $id)
  179. {
  180. if (count($columnValues) == 0) {
  181. return 0;
  182. }
  183. $this->converter->convertColumnValues($table, $columnValues);
  184. $updateColumns = $this->columns->getUpdate($table, $columnValues);
  185. $tableName = $table->getName();
  186. $condition = new ColumnCondition($table->getPk(), 'eq', $id);
  187. $parameters = array_values($columnValues);
  188. $whereClause = $this->conditions->getWhereClause($condition, $parameters);
  189. $sql = 'UPDATE "' . $tableName . '" SET ' . $updateColumns . $whereClause;
  190. $stmt = $this->query($sql, $parameters);
  191. return $stmt->rowCount();
  192. }
  193. public function deleteSingle(ReflectedTable $table, String $id)
  194. {
  195. $tableName = $table->getName();
  196. $condition = new ColumnCondition($table->getPk(), 'eq', $id);
  197. $parameters = array();
  198. $whereClause = $this->conditions->getWhereClause($condition, $parameters);
  199. $sql = 'DELETE FROM "' . $tableName . '" ' . $whereClause;
  200. $stmt = $this->query($sql, $parameters);
  201. return $stmt->rowCount();
  202. }
  203. private function query(String $sql, array $parameters): \PDOStatement
  204. {
  205. $stmt = $this->pdo->prepare($sql);
  206. $stmt->execute($parameters);
  207. //echo "- $sql -- " . json_encode($parameters, JSON_UNESCAPED_UNICODE) . "\n";
  208. return $stmt;
  209. }
  210. }