Browse Source

Merge branch 'master' of github.com:mevdschee/php-crud-api

Maurits van der Schee 5 years ago
parent
commit
3cb99f2550

+ 1
- 1
README.md View File

@@ -49,7 +49,7 @@ Alternatively you can integrate this project into the web framework of your choi
49 49
 
50 50
 - [Automatic REST API for Laravel](https://tqdev.com/2019-automatic-rest-api-laravel)
51 51
 - [Automatic REST API for Symfony 4](https://tqdev.com/2019-automatic-rest-api-symfony)
52
-- [Automatic REST API for SlimPHP](https://tqdev.com/2019-automatic-api-slimphp-3)
52
+- [Automatic REST API for SlimPHP 4](https://tqdev.com/2019-automatic-api-slimphp-4)
53 53
 
54 54
 ## Configuration
55 55
 

+ 71
- 24
api.php View File

@@ -5936,45 +5936,60 @@ namespace Tqdev\PhpCrudApi\Database {
5936 5936
         public function getIgnoredTables(): array
5937 5937
         {
5938 5938
             switch ($this->driver) {
5939
-                case 'mysql':return [];
5940
-                case 'pgsql':return ['spatial_ref_sys', 'raster_columns', 'raster_overviews', 'geography_columns', 'geometry_columns'];
5941
-                case 'sqlsrv':return [];
5939
+                case 'mysql':
5940
+                    return [];
5941
+                case 'pgsql':
5942
+                    return ['spatial_ref_sys', 'raster_columns', 'raster_overviews', 'geography_columns', 'geometry_columns'];
5943
+                case 'sqlsrv':
5944
+                    return [];
5942 5945
             }
5943 5946
         }
5944 5947
 
5945 5948
         private function getTablesSQL(): string
5946 5949
         {
5947 5950
             switch ($this->driver) {
5948
-                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"';
5949
-                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";';
5950
-                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"';
5951
+                case 'mysql':
5952
+                    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"';
5953
+                case 'pgsql':
5954
+                    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";';
5955
+                case 'sqlsrv':
5956
+                    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"';
5951 5957
             }
5952 5958
         }
5953 5959
 
5954 5960
         private function getTableColumnsSQL(): string
5955 5961
         {
5956 5962
             switch ($this->driver) {
5957
-                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" = ?';
5958
-                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;';
5959
-                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 \'\' <> ?';
5963
+                case 'mysql':
5964
+                    return 'SELECT "COLUMN_NAME", "IS_NULLABLE", "DATA_TYPE", if ("DATA_TYPE"=\'tinyint\' OR "DATA_TYPE"=\'bit\',SUBSTRING_INDEX(SUBSTRING_INDEX("COLUMN_TYPE",\'(\',-1),\')\',1),"CHARACTER_MAXIMUM_LENGTH") as "CHARACTER_MAXIMUM_LENGTH", "NUMERIC_PRECISION", "NUMERIC_SCALE" FROM "INFORMATION_SCHEMA"."COLUMNS" WHERE "TABLE_NAME" = ? AND "TABLE_SCHEMA" = ?';
5965
+                case 'pgsql':
5966
+                    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;';
5967
+                case 'sqlsrv':
5968
+                    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 \'\' <> ?';
5960 5969
             }
5961 5970
         }
5962 5971
 
5963 5972
         private function getTablePrimaryKeysSQL(): string
5964 5973
         {
5965 5974
             switch ($this->driver) {
5966
-                case 'mysql':return 'SELECT "COLUMN_NAME" FROM "INFORMATION_SCHEMA"."KEY_COLUMN_USAGE" WHERE "CONSTRAINT_NAME" = \'PRIMARY\' AND "TABLE_NAME" = ? AND "TABLE_SCHEMA" = ?';
5967
-                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\'';
5968
-                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 \'\' <> ?';
5975
+                case 'mysql':
5976
+                    return 'SELECT "COLUMN_NAME" FROM "INFORMATION_SCHEMA"."KEY_COLUMN_USAGE" WHERE "CONSTRAINT_NAME" = \'PRIMARY\' AND "TABLE_NAME" = ? AND "TABLE_SCHEMA" = ?';
5977
+                case 'pgsql':
5978
+                    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\'';
5979
+                case 'sqlsrv':
5980
+                    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 \'\' <> ?';
5969 5981
             }
5970 5982
         }
5971 5983
 
5972 5984
         private function getTableForeignKeysSQL(): string
5973 5985
         {
5974 5986
             switch ($this->driver) {
5975
-                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" = ?';
5976
-                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\'';
5977
-                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 \'\' <> ?';
5987
+                case 'mysql':
5988
+                    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" = ?';
5989
+                case 'pgsql':
5990
+                    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\'';
5991
+                case 'sqlsrv':
5992
+                    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 \'\' <> ?';
5978 5993
             }
5979 5994
         }
5980 5995
 
@@ -6015,6 +6030,21 @@ namespace Tqdev\PhpCrudApi\Database {
6015 6030
                     $result['IS_NULLABLE'] = false;
6016 6031
                 }
6017 6032
             }
6033
+            if ($this->driver == 'mysql') {
6034
+                foreach ($results as &$result) {
6035
+                    // mysql does not properly reflect display width of types
6036
+                    preg_match('|([a-z]+)(\(([0-9]+)(,([0-9]+))?\))?|', $result['DATA_TYPE'], $matches);
6037
+                    $result['DATA_TYPE'] = $matches[1];
6038
+                    if (!$result['CHARACTER_MAXIMUM_LENGTH']) {
6039
+                        if (isset($matches[3])) {
6040
+                            $result['NUMERIC_PRECISION'] = $matches[3];
6041
+                        }
6042
+                        if (isset($matches[5])) {
6043
+                            $result['NUMERIC_SCALE'] = $matches[5];
6044
+                        }
6045
+                    }
6046
+                }
6047
+            }
6018 6048
             return $results;
6019 6049
         }
6020 6050
 
@@ -6195,7 +6225,7 @@ namespace Tqdev\PhpCrudApi\Database {
6195 6225
         private $fromJdbc = [
6196 6226
             'mysql' => [
6197 6227
                 'clob' => 'longtext',
6198
-                'boolean' => 'bit',
6228
+                'boolean' => 'tinyint',
6199 6229
                 'blob' => 'longblob',
6200 6230
                 'timestamp' => 'datetime',
6201 6231
             ],
@@ -6228,7 +6258,8 @@ namespace Tqdev\PhpCrudApi\Database {
6228 6258
                 'timestamp_with_timezone' => 'timestamp',
6229 6259
             ],
6230 6260
             'mysql' => [
6231
-                'bit' => 'boolean',
6261
+                'tinyint(1)' => 'boolean',
6262
+                'bit(1)' => 'boolean',
6232 6263
                 'tinyblob' => 'blob',
6233 6264
                 'mediumblob' => 'blob',
6234 6265
                 'longblob' => 'blob',
@@ -9798,18 +9829,34 @@ namespace Tqdev\PhpCrudApi {
9798 9829
 
9799 9830
         private function addParsedBody(ServerRequestInterface $request): ServerRequestInterface
9800 9831
         {
9801
-            $body = $request->getBody();
9802
-            if ($body->isReadable() && $body->isSeekable()) {
9803
-                $contents = $body->getContents();
9804
-                $body->rewind();
9805
-                if ($contents) {
9806
-                    $parsedBody = $this->parseBody($contents);
9807
-                    $request = $request->withParsedBody($parsedBody);
9832
+            $parsedBody = $request->getParsedBody();
9833
+            if ($parsedBody) {
9834
+                $request = $this->applySlim3Hack($request);
9835
+            } else {
9836
+                $body = $request->getBody();
9837
+                if ($body->isReadable() && $body->isSeekable()) {
9838
+                    $contents = $body->getContents();
9839
+                    $body->rewind();
9840
+                    if ($contents) {
9841
+                        $parsedBody = $this->parseBody($contents);
9842
+                        $request = $request->withParsedBody($parsedBody);
9843
+                    }
9808 9844
                 }
9809 9845
             }
9810 9846
             return $request;
9811 9847
         }
9812 9848
 
9849
+        private function applySlim3Hack(ServerRequestInterface $request): ServerRequestInterface
9850
+        {
9851
+            if (get_class($request) == 'Slim\Http\Request') {
9852
+                $parsedBody = $request->getParsedBody();
9853
+                $contents = json_encode($parsedBody);
9854
+                $parsedBody = $this->parseBody($contents);
9855
+                $request = $request->withParsedBody($parsedBody);
9856
+            }
9857
+            return $request;
9858
+        }
9859
+
9813 9860
         public function handle(ServerRequestInterface $request): ResponseInterface
9814 9861
         {
9815 9862
             $response = null;

+ 23
- 7
src/Tqdev/PhpCrudApi/Api.php View File

@@ -160,18 +160,34 @@ class Api implements RequestHandlerInterface
160 160
 
161 161
     private function addParsedBody(ServerRequestInterface $request): ServerRequestInterface
162 162
     {
163
-        $body = $request->getBody();
164
-        if ($body->isReadable() && $body->isSeekable()) {
165
-            $contents = $body->getContents();
166
-            $body->rewind();
167
-            if ($contents) {
168
-                $parsedBody = $this->parseBody($contents);
169
-                $request = $request->withParsedBody($parsedBody);
163
+        $parsedBody = $request->getParsedBody();
164
+        if ($parsedBody) {
165
+            $request = $this->applySlim3Hack($request);
166
+        } else {
167
+            $body = $request->getBody();
168
+            if ($body->isReadable() && $body->isSeekable()) {
169
+                $contents = $body->getContents();
170
+                $body->rewind();
171
+                if ($contents) {
172
+                    $parsedBody = $this->parseBody($contents);
173
+                    $request = $request->withParsedBody($parsedBody);
174
+                }
170 175
             }
171 176
         }
172 177
         return $request;
173 178
     }
174 179
 
180
+    private function applySlim3Hack(ServerRequestInterface $request): ServerRequestInterface
181
+    {
182
+        if (get_class($request) == 'Slim\Http\Request') {
183
+            $parsedBody = $request->getParsedBody();
184
+            $contents = json_encode($parsedBody);
185
+            $parsedBody = $this->parseBody($contents);
186
+            $request = $request->withParsedBody($parsedBody);
187
+        }
188
+        return $request;
189
+    }
190
+
175 191
     public function handle(ServerRequestInterface $request): ResponseInterface
176 192
     {
177 193
         $response = null;

+ 45
- 15
src/Tqdev/PhpCrudApi/Database/GenericReflection.php View File

@@ -22,45 +22,60 @@ class GenericReflection
22 22
     public function getIgnoredTables(): array
23 23
     {
24 24
         switch ($this->driver) {
25
-            case 'mysql':return [];
26
-            case 'pgsql':return ['spatial_ref_sys', 'raster_columns', 'raster_overviews', 'geography_columns', 'geometry_columns'];
27
-            case 'sqlsrv':return [];
25
+            case 'mysql':
26
+                return [];
27
+            case 'pgsql':
28
+                return ['spatial_ref_sys', 'raster_columns', 'raster_overviews', 'geography_columns', 'geometry_columns'];
29
+            case 'sqlsrv':
30
+                return [];
28 31
         }
29 32
     }
30 33
 
31 34
     private function getTablesSQL(): string
32 35
     {
33 36
         switch ($this->driver) {
34
-            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"';
35
-            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";';
36
-            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"';
37
+            case 'mysql':
38
+                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"';
39
+            case 'pgsql':
40
+                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";';
41
+            case 'sqlsrv':
42
+                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"';
37 43
         }
38 44
     }
39 45
 
40 46
     private function getTableColumnsSQL(): string
41 47
     {
42 48
         switch ($this->driver) {
43
-            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" = ?';
44
-            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;';
45
-            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 \'\' <> ?';
49
+            case 'mysql':
50
+                return 'SELECT "COLUMN_NAME", "IS_NULLABLE", "DATA_TYPE", if ("DATA_TYPE"=\'tinyint\' OR "DATA_TYPE"=\'bit\',SUBSTRING_INDEX(SUBSTRING_INDEX("COLUMN_TYPE",\'(\',-1),\')\',1),"CHARACTER_MAXIMUM_LENGTH") as "CHARACTER_MAXIMUM_LENGTH", "NUMERIC_PRECISION", "NUMERIC_SCALE" FROM "INFORMATION_SCHEMA"."COLUMNS" WHERE "TABLE_NAME" = ? AND "TABLE_SCHEMA" = ?';
51
+            case 'pgsql':
52
+                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;';
53
+            case 'sqlsrv':
54
+                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 \'\' <> ?';
46 55
         }
47 56
     }
48 57
 
49 58
     private function getTablePrimaryKeysSQL(): string
50 59
     {
51 60
         switch ($this->driver) {
52
-            case 'mysql':return 'SELECT "COLUMN_NAME" FROM "INFORMATION_SCHEMA"."KEY_COLUMN_USAGE" WHERE "CONSTRAINT_NAME" = \'PRIMARY\' AND "TABLE_NAME" = ? AND "TABLE_SCHEMA" = ?';
53
-            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\'';
54
-            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 \'\' <> ?';
61
+            case 'mysql':
62
+                return 'SELECT "COLUMN_NAME" FROM "INFORMATION_SCHEMA"."KEY_COLUMN_USAGE" WHERE "CONSTRAINT_NAME" = \'PRIMARY\' AND "TABLE_NAME" = ? AND "TABLE_SCHEMA" = ?';
63
+            case 'pgsql':
64
+                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\'';
65
+            case 'sqlsrv':
66
+                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 \'\' <> ?';
55 67
         }
56 68
     }
57 69
 
58 70
     private function getTableForeignKeysSQL(): string
59 71
     {
60 72
         switch ($this->driver) {
61
-            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" = ?';
62
-            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\'';
63
-            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 \'\' <> ?';
73
+            case 'mysql':
74
+                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" = ?';
75
+            case 'pgsql':
76
+                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\'';
77
+            case 'sqlsrv':
78
+                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 \'\' <> ?';
64 79
         }
65 80
     }
66 81
 
@@ -101,6 +116,21 @@ class GenericReflection
101 116
                 $result['IS_NULLABLE'] = false;
102 117
             }
103 118
         }
119
+        if ($this->driver == 'mysql') {
120
+            foreach ($results as &$result) {
121
+                // mysql does not properly reflect display width of types
122
+                preg_match('|([a-z]+)(\(([0-9]+)(,([0-9]+))?\))?|', $result['DATA_TYPE'], $matches);
123
+                $result['DATA_TYPE'] = $matches[1];
124
+                if (!$result['CHARACTER_MAXIMUM_LENGTH']) {
125
+                    if (isset($matches[3])) {
126
+                        $result['NUMERIC_PRECISION'] = $matches[3];
127
+                    }
128
+                    if (isset($matches[5])) {
129
+                        $result['NUMERIC_SCALE'] = $matches[5];
130
+                    }
131
+                }
132
+            }
133
+        }
104 134
         return $results;
105 135
     }
106 136
 

+ 3
- 2
src/Tqdev/PhpCrudApi/Database/TypeConverter.php View File

@@ -14,7 +14,7 @@ class TypeConverter
14 14
     private $fromJdbc = [
15 15
         'mysql' => [
16 16
             'clob' => 'longtext',
17
-            'boolean' => 'bit',
17
+            'boolean' => 'tinyint',
18 18
             'blob' => 'longblob',
19 19
             'timestamp' => 'datetime',
20 20
         ],
@@ -47,7 +47,8 @@ class TypeConverter
47 47
             'timestamp_with_timezone' => 'timestamp',
48 48
         ],
49 49
         'mysql' => [
50
-            'bit' => 'boolean',
50
+            'tinyint(1)' => 'boolean',
51
+            'bit(1)' => 'boolean',
51 52
             'tinyblob' => 'blob',
52 53
             'mediumblob' => 'blob',
53 54
             'longblob' => 'blob',

Loading…
Cancel
Save