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.

GenericReflection.php 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. <?php
  2. namespace Tqdev\PhpCrudApi\Database;
  3. use Tqdev\PhpCrudApi\Database\LazyPdo;
  4. class GenericReflection
  5. {
  6. private $pdo;
  7. private $driver;
  8. private $database;
  9. private $typeConverter;
  10. public function __construct(LazyPdo $pdo, string $driver, string $database)
  11. {
  12. $this->pdo = $pdo;
  13. $this->driver = $driver;
  14. $this->database = $database;
  15. $this->typeConverter = new TypeConverter($driver);
  16. }
  17. public function getIgnoredTables(): array
  18. {
  19. switch ($this->driver) {
  20. case 'mysql':return [];
  21. case 'pgsql':return ['spatial_ref_sys', 'raster_columns', 'raster_overviews', 'geography_columns', 'geometry_columns'];
  22. case 'sqlsrv':return [];
  23. }
  24. }
  25. private function getTablesSQL(): string
  26. {
  27. switch ($this->driver) {
  28. case 'mysql':return 'SELECT "TABLE_NAME", "TABLE_TYPE" FROM "INFORMATION_SCHEMA"."TABLES" WHERE "TABLE_TYPE" IN (\'BASE TABLE\' , \'VIEW\') AND "TABLE_SCHEMA" = ? ORDER BY BINARY "TABLE_NAME"';
  29. case 'pgsql':return 'SELECT c.relname as "TABLE_NAME", c.relkind as "TABLE_TYPE" FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind IN (\'r\', \'v\') AND n.nspname <> \'pg_catalog\' AND n.nspname <> \'information_schema\' AND n.nspname !~ \'^pg_toast\' AND pg_catalog.pg_table_is_visible(c.oid) AND \'\' <> ? ORDER BY "TABLE_NAME";';
  30. case 'sqlsrv':return 'SELECT o.name as "TABLE_NAME", o.xtype as "TABLE_TYPE" FROM sysobjects o WHERE o.xtype IN (\'U\', \'V\') ORDER BY "TABLE_NAME"';
  31. }
  32. }
  33. private function getTableColumnsSQL(): string
  34. {
  35. switch ($this->driver) {
  36. case 'mysql':return 'SELECT "COLUMN_NAME", "IS_NULLABLE", "DATA_TYPE", "CHARACTER_MAXIMUM_LENGTH", "NUMERIC_PRECISION", "NUMERIC_SCALE" FROM "INFORMATION_SCHEMA"."COLUMNS" WHERE "TABLE_NAME" = ? AND "TABLE_SCHEMA" = ?';
  37. case 'pgsql':return 'SELECT a.attname AS "COLUMN_NAME", case when a.attnotnull then \'NO\' else \'YES\' end as "IS_NULLABLE", pg_catalog.format_type(a.atttypid, -1) as "DATA_TYPE", case when a.atttypmod < 0 then NULL else a.atttypmod-4 end as "CHARACTER_MAXIMUM_LENGTH", case when a.atttypid != 1700 then NULL else ((a.atttypmod - 4) >> 16) & 65535 end as "NUMERIC_PRECISION", case when a.atttypid != 1700 then NULL else (a.atttypmod - 4) & 65535 end as "NUMERIC_SCALE" FROM pg_attribute a JOIN pg_class pgc ON pgc.oid = a.attrelid WHERE pgc.relname = ? AND \'\' <> ? AND a.attnum > 0 AND NOT a.attisdropped;';
  38. case 'sqlsrv':return 'SELECT c.name AS "COLUMN_NAME", c.is_nullable AS "IS_NULLABLE", t.Name AS "DATA_TYPE", (c.max_length/2) AS "CHARACTER_MAXIMUM_LENGTH", c.precision AS "NUMERIC_PRECISION", c.scale AS "NUMERIC_SCALE" FROM sys.columns c INNER JOIN sys.types t ON c.user_type_id = t.user_type_id WHERE c.object_id = OBJECT_ID(?) AND \'\' <> ?';
  39. }
  40. }
  41. private function getTablePrimaryKeysSQL(): string
  42. {
  43. switch ($this->driver) {
  44. case 'mysql':return 'SELECT "COLUMN_NAME" FROM "INFORMATION_SCHEMA"."KEY_COLUMN_USAGE" WHERE "CONSTRAINT_NAME" = \'PRIMARY\' AND "TABLE_NAME" = ? AND "TABLE_SCHEMA" = ?';
  45. case 'pgsql':return 'SELECT a.attname AS "COLUMN_NAME" FROM pg_attribute a JOIN pg_constraint c ON (c.conrelid, c.conkey[1]) = (a.attrelid, a.attnum) JOIN pg_class pgc ON pgc.oid = a.attrelid WHERE pgc.relname = ? AND \'\' <> ? AND c.contype = \'p\'';
  46. case 'sqlsrv':return 'SELECT c.NAME as "COLUMN_NAME" FROM sys.key_constraints kc inner join sys.objects t on t.object_id = kc.parent_object_id INNER JOIN sys.index_columns ic ON kc.parent_object_id = ic.object_id and kc.unique_index_id = ic.index_id INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id WHERE kc.type = \'PK\' and t.object_id = OBJECT_ID(?) and \'\' <> ?';
  47. }
  48. }
  49. private function getTableForeignKeysSQL(): string
  50. {
  51. switch ($this->driver) {
  52. case 'mysql':return 'SELECT "COLUMN_NAME", "REFERENCED_TABLE_NAME" FROM "INFORMATION_SCHEMA"."KEY_COLUMN_USAGE" WHERE "REFERENCED_TABLE_NAME" IS NOT NULL AND "TABLE_NAME" = ? AND "TABLE_SCHEMA" = ?';
  53. case 'pgsql':return 'SELECT a.attname AS "COLUMN_NAME", c.confrelid::regclass::text AS "REFERENCED_TABLE_NAME" FROM pg_attribute a JOIN pg_constraint c ON (c.conrelid, c.conkey[1]) = (a.attrelid, a.attnum) JOIN pg_class pgc ON pgc.oid = a.attrelid WHERE pgc.relname = ? AND \'\' <> ? AND c.contype = \'f\'';
  54. case 'sqlsrv':return 'SELECT COL_NAME(fc.parent_object_id, fc.parent_column_id) AS "COLUMN_NAME", OBJECT_NAME (f.referenced_object_id) AS "REFERENCED_TABLE_NAME" FROM sys.foreign_keys AS f INNER JOIN sys.foreign_key_columns AS fc ON f.OBJECT_ID = fc.constraint_object_id WHERE f.parent_object_id = OBJECT_ID(?) and \'\' <> ?';
  55. }
  56. }
  57. public function getDatabaseName(): string
  58. {
  59. return $this->database;
  60. }
  61. public function getTables(): array
  62. {
  63. $sql = $this->getTablesSQL();
  64. $results = $this->query($sql, [$this->database]);
  65. foreach ($results as &$result) {
  66. switch ($this->driver) {
  67. case 'mysql':
  68. $map = ['BASE TABLE' => 'table', 'VIEW' => 'view'];
  69. $result['TABLE_TYPE'] = $map[$result['TABLE_TYPE']];
  70. break;
  71. case 'pgsql':
  72. $map = ['r' => 'table', 'v' => 'view'];
  73. $result['TABLE_TYPE'] = $map[$result['TABLE_TYPE']];
  74. break;
  75. case 'sqlsrv':
  76. $map = ['U' => 'table', 'V' => 'view'];
  77. $result['TABLE_TYPE'] = $map[trim($result['TABLE_TYPE'])];
  78. break;
  79. }
  80. }
  81. return $results;
  82. }
  83. public function getTableColumns(string $tableName, string $type): array
  84. {
  85. $sql = $this->getTableColumnsSQL();
  86. $results = $this->query($sql, [$tableName, $this->database]);
  87. if ($type == 'view') {
  88. foreach ($results as &$result) {
  89. $result['IS_NULLABLE'] = false;
  90. }
  91. }
  92. return $results;
  93. }
  94. public function getTablePrimaryKeys(string $tableName): array
  95. {
  96. $sql = $this->getTablePrimaryKeysSQL();
  97. $results = $this->query($sql, [$tableName, $this->database]);
  98. $primaryKeys = [];
  99. foreach ($results as $result) {
  100. $primaryKeys[] = $result['COLUMN_NAME'];
  101. }
  102. return $primaryKeys;
  103. }
  104. public function getTableForeignKeys(string $tableName): array
  105. {
  106. $sql = $this->getTableForeignKeysSQL();
  107. $results = $this->query($sql, [$tableName, $this->database]);
  108. $foreignKeys = [];
  109. foreach ($results as $result) {
  110. $foreignKeys[$result['COLUMN_NAME']] = $result['REFERENCED_TABLE_NAME'];
  111. }
  112. return $foreignKeys;
  113. }
  114. public function toJdbcType(string $type, int $size): string
  115. {
  116. return $this->typeConverter->toJdbc($type, $size);
  117. }
  118. private function query(string $sql, array $parameters): array
  119. {
  120. $stmt = $this->pdo->prepare($sql);
  121. //echo "- $sql -- " . json_encode($parameters, JSON_UNESCAPED_UNICODE) . "\n";
  122. $stmt->execute($parameters);
  123. return $stmt->fetchAll();
  124. }
  125. }