Skip to content

Commit 3cb99f2

Browse files
committed
Merge branch 'master' of github.com:mevdschee/php-crud-api
2 parents 22b282a + ac3b7da commit 3cb99f2

File tree

5 files changed

+143
-49
lines changed

5 files changed

+143
-49
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ Alternatively you can integrate this project into the web framework of your choi
4949

5050
- [Automatic REST API for Laravel](https://tqdev.com/2019-automatic-rest-api-laravel)
5151
- [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)
5353

5454
## Configuration
5555

api.php

Lines changed: 71 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5936,45 +5936,60 @@ public function __construct(LazyPdo $pdo, string $driver, string $database)
59365936
public function getIgnoredTables(): array
59375937
{
59385938
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 [];
59425945
}
59435946
}
59445947

59455948
private function getTablesSQL(): string
59465949
{
59475950
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"';
59515957
}
59525958
}
59535959

59545960
private function getTableColumnsSQL(): string
59555961
{
59565962
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 \'\' <> ?';
59605969
}
59615970
}
59625971

59635972
private function getTablePrimaryKeysSQL(): string
59645973
{
59655974
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 \'\' <> ?';
59695981
}
59705982
}
59715983

59725984
private function getTableForeignKeysSQL(): string
59735985
{
59745986
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 \'\' <> ?';
59785993
}
59795994
}
59805995

@@ -6015,6 +6030,21 @@ public function getTableColumns(string $tableName, string $type): array
60156030
$result['IS_NULLABLE'] = false;
60166031
}
60176032
}
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+
}
60186048
return $results;
60196049
}
60206050

@@ -6195,7 +6225,7 @@ public function __construct(string $driver)
61956225
private $fromJdbc = [
61966226
'mysql' => [
61976227
'clob' => 'longtext',
6198-
'boolean' => 'bit',
6228+
'boolean' => 'tinyint',
61996229
'blob' => 'longblob',
62006230
'timestamp' => 'datetime',
62016231
],
@@ -6228,7 +6258,8 @@ public function __construct(string $driver)
62286258
'timestamp_with_timezone' => 'timestamp',
62296259
],
62306260
'mysql' => [
6231-
'bit' => 'boolean',
6261+
'tinyint(1)' => 'boolean',
6262+
'bit(1)' => 'boolean',
62326263
'tinyblob' => 'blob',
62336264
'mediumblob' => 'blob',
62346265
'longblob' => 'blob',
@@ -9798,18 +9829,34 @@ private function parseBody(string $body) /*: ?object*/
97989829

97999830
private function addParsedBody(ServerRequestInterface $request): ServerRequestInterface
98009831
{
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+
}
98089844
}
98099845
}
98109846
return $request;
98119847
}
98129848

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+
98139860
public function handle(ServerRequestInterface $request): ResponseInterface
98149861
{
98159862
$response = null;

src/Tqdev/PhpCrudApi/Api.php

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -160,18 +160,34 @@ private function parseBody(string $body) /*: ?object*/
160160

161161
private function addParsedBody(ServerRequestInterface $request): ServerRequestInterface
162162
{
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+
}
170175
}
171176
}
172177
return $request;
173178
}
174179

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+
175191
public function handle(ServerRequestInterface $request): ResponseInterface
176192
{
177193
$response = null;

0 commit comments

Comments
 (0)