Skip to content

Commit f302a1c

Browse files
committed
Merge branch 'main' of github.com:mevdschee/php-crud-api into main
2 parents bc6b746 + cfdd503 commit f302a1c

File tree

13 files changed

+354
-29
lines changed

13 files changed

+354
-29
lines changed

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ These are all the configuration options and their default value between brackets
5757
- "username": Username of the user connecting to the database (no default)
5858
- "password": Password of the user connecting to the database (no default)
5959
- "database": Database the connecting is made to (no default)
60+
- "command": Extra SQL to initialize the database connection (none)
6061
- "tables": Comma separated list of tables to publish (defaults to 'all')
6162
- "mapping": Comma separated list of table/column mappings (no mappping)
6263
- "middlewares": List of middlewares to load (`cors`)
@@ -663,6 +664,7 @@ You can enable the following middleware using the "middlewares" config parameter
663664
- "multiTenancy": Restricts tenants access in a multi-tenant scenario
664665
- "pageLimits": Restricts list operations to prevent database scraping
665666
- "joinLimits": Restricts join parameters to prevent database scraping
667+
- "textSearch": Search in all text fields with a simple paramater
666668
- "customization": Provides handlers for request and response customization
667669
- "json": Support read/write of JSON strings as JSON objects/arrays
668670
- "xml": Translates all input and output from JSON to XML
@@ -741,6 +743,7 @@ You can tune the middleware behavior using middleware specific configuration par
741743
- "joinLimits.depth": The maximum depth (length) that is allowed in a join path ("3")
742744
- "joinLimits.tables": The maximum number of tables that you are allowed to join ("10")
743745
- "joinLimits.records": The maximum number of records returned for a joined entity ("1000")
746+
- "textSearch.parameter": The name of the parameter used for the search term ("search")
744747
- "customization.beforeHandler": Handler to implement request customization ("")
745748
- "customization.afterHandler": Handler to implement response customization ("")
746749
- "json.controllers": Controllers to process JSON strings for ("records,geojson")
@@ -1136,6 +1139,28 @@ If you want to allow no more than 10 pages with a maximum of 25 records each, yo
11361139

11371140
NB: The maximum number of records is also applied when there is no page number specified in the request.
11381141

1142+
### Search all text fields
1143+
1144+
You may use the "textSearch" middleware to simplify (wildcard) text searches when listing records.
1145+
It allows you to specify a "search" parameter using:
1146+
1147+
GET /records/posts?search=Hello
1148+
1149+
It will return all records from "posts" that contain "Hello" in one of their text (typed) fields:
1150+
1151+
{
1152+
"records":[
1153+
{
1154+
"id": 1,
1155+
"title": "Hello world!",
1156+
"content": "Welcome to the first post.",
1157+
"created": "2018-03-05T20:12:56Z"
1158+
}
1159+
]
1160+
}
1161+
1162+
The example searches the fields "title" or "content" for the substring "Hello".
1163+
11391164
### Customization handlers
11401165

11411166
You may use the "customization" middleware to modify request and response and implement any other functionality.

api.include.php

Lines changed: 103 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3850,6 +3850,11 @@ public function isInteger(): bool
38503850
return in_array($this->type, ['integer', 'bigint', 'smallint', 'tinyint']);
38513851
}
38523852

3853+
public function isText(): bool
3854+
{
3855+
return in_array($this->type, ['varchar', 'clob']);
3856+
}
3857+
38533858
public function setPk($value) /*: void*/
38543859
{
38553860
$this->pk = $value;
@@ -3874,7 +3879,7 @@ public function serialize()
38743879
{
38753880
$json = [
38763881
'name' => $this->realName,
3877-
'alias' => $this->name!=$this->realName?$this->name:null,
3882+
'alias' => $this->name != $this->realName ? $this->name : null,
38783883
'type' => $this->type,
38793884
'length' => $this->length,
38803885
'precision' => $this->precision,
@@ -5555,6 +5560,7 @@ class GenericDB
55555560
private $address;
55565561
private $port;
55575562
private $database;
5563+
private $command;
55585564
private $tables;
55595565
private $mapping;
55605566
private $username;
@@ -5585,22 +5591,30 @@ private function getCommands(): array
55855591
{
55865592
switch ($this->driver) {
55875593
case 'mysql':
5588-
return [
5594+
$commands = [
55895595
'SET SESSION sql_warnings=1;',
55905596
'SET NAMES utf8mb4;',
55915597
'SET SESSION sql_mode = "ANSI,TRADITIONAL";',
55925598
];
5599+
break;
55935600
case 'pgsql':
5594-
return [
5601+
$commands = [
55955602
"SET NAMES 'UTF8';",
55965603
];
5604+
break;
55975605
case 'sqlsrv':
5598-
return [];
5606+
$commands = [];
5607+
break;
55995608
case 'sqlite':
5600-
return [
5609+
$commands = [
56015610
'PRAGMA foreign_keys = on;',
56025611
];
5612+
break;
5613+
}
5614+
if ($this->command != '') {
5615+
$commands[] = $this->command;
56035616
}
5617+
return $commands;
56045618
}
56055619

56065620
private function getOptions(): array
@@ -5647,20 +5661,21 @@ private function initPdo(): bool
56475661
return $result;
56485662
}
56495663

5650-
public function __construct(string $driver, string $address, int $port, string $database, array $tables, array $mapping, string $username, string $password)
5664+
public function __construct(string $driver, string $address, int $port, string $database, string $command, array $tables, array $mapping, string $username, string $password)
56515665
{
56525666
$this->driver = $driver;
56535667
$this->address = $address;
56545668
$this->port = $port;
56555669
$this->database = $database;
5670+
$this->command = $command;
56565671
$this->tables = $tables;
56575672
$this->mapping = $mapping;
56585673
$this->username = $username;
56595674
$this->password = $password;
56605675
$this->initPdo();
56615676
}
56625677

5663-
public function reconstruct(string $driver, string $address, int $port, string $database, array $tables, array $mapping, string $username, string $password): bool
5678+
public function reconstruct(string $driver, string $address, int $port, string $database, string $command, array $tables, array $mapping, string $username, string $password): bool
56645679
{
56655680
if ($driver) {
56665681
$this->driver = $driver;
@@ -5674,6 +5689,9 @@ public function reconstruct(string $driver, string $address, int $port, string $
56745689
if ($database) {
56755690
$this->database = $database;
56765691
}
5692+
if ($command) {
5693+
$this->command = $command;
5694+
}
56775695
if ($tables) {
56785696
$this->tables = $tables;
56795697
}
@@ -8845,6 +8863,15 @@ private function getDatabase(): string
88458863
return '';
88468864
}
88478865

8866+
private function getCommand(): string
8867+
{
8868+
$commandHandler = $this->getProperty('commandHandler', '');
8869+
if ($commandHandler) {
8870+
return call_user_func($commandHandler);
8871+
}
8872+
return '';
8873+
}
8874+
88488875
private function getTables(): array
88498876
{
88508877
$tablesHandler = $this->getProperty('tablesHandler', '');
@@ -8887,12 +8914,13 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
88878914
$address = $this->getAddress();
88888915
$port = $this->getPort();
88898916
$database = $this->getDatabase();
8917+
$command = $this->getCommand();
88908918
$tables = $this->getTables();
88918919
$mapping = $this->getMapping();
88928920
$username = $this->getUsername();
88938921
$password = $this->getPassword();
8894-
if ($driver || $address || $port || $database || $tables || $mapping || $username || $password) {
8895-
$this->db->reconstruct($driver, $address, $port, $database, $tables, $mapping, $username, $password);
8922+
if ($driver || $address || $port || $database || $command || $tables || $mapping || $username || $password) {
8923+
$this->db->reconstruct($driver, $address, $port, $database, $command, $tables, $mapping, $username, $password);
88968924
}
88978925
return $next->handle($request);
88988926
}
@@ -9079,6 +9107,61 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
90799107
}
90809108
}
90819109

9110+
// file: src/Tqdev/PhpCrudApi/Middleware/TextSearchMiddleware.php
9111+
namespace Tqdev\PhpCrudApi\Middleware {
9112+
9113+
use Psr\Http\Message\ResponseInterface;
9114+
use Psr\Http\Message\ServerRequestInterface;
9115+
use Psr\Http\Server\RequestHandlerInterface;
9116+
use Tqdev\PhpCrudApi\Column\ReflectionService;
9117+
use Tqdev\PhpCrudApi\Controller\Responder;
9118+
use Tqdev\PhpCrudApi\Middleware\Base\Middleware;
9119+
use Tqdev\PhpCrudApi\Middleware\Router\Router;
9120+
use Tqdev\PhpCrudApi\RequestUtils;
9121+
9122+
class TextSearchMiddleware extends Middleware
9123+
{
9124+
private $reflection;
9125+
9126+
public function __construct(Router $router, Responder $responder, array $properties, ReflectionService $reflection)
9127+
{
9128+
parent::__construct($router, $responder, $properties);
9129+
$this->reflection = $reflection;
9130+
}
9131+
9132+
public function process(ServerRequestInterface $request, RequestHandlerInterface $next): ResponseInterface
9133+
{
9134+
$operation = RequestUtils::getOperation($request);
9135+
if ($operation == 'list') {
9136+
$tableName = RequestUtils::getPathSegment($request, 2);
9137+
$params = RequestUtils::getParams($request);
9138+
$parameterName = $this->getProperty('parameter', 'search');
9139+
if (isset($params[$parameterName])) {
9140+
$search = $params[$parameterName][0];
9141+
unset($params[$parameterName]);
9142+
$table = $this->reflection->getTable($tableName);
9143+
$i = 0;
9144+
foreach ($table->getColumnNames() as $columnName) {
9145+
$column = $table->getColumn($columnName);
9146+
while (isset($params["filter$i"])) {
9147+
$i++;
9148+
}
9149+
if ($i >= 10) {
9150+
break;
9151+
}
9152+
if ($column->isText()) {
9153+
$params["filter$i"] = "$columnName,cs,$search";
9154+
$i++;
9155+
}
9156+
}
9157+
}
9158+
$request = RequestUtils::setParams($request, $params);
9159+
}
9160+
return $next->handle($request);
9161+
}
9162+
}
9163+
}
9164+
90829165
// file: src/Tqdev/PhpCrudApi/Middleware/ValidationMiddleware.php
90839166
namespace Tqdev\PhpCrudApi\Middleware {
90849167

@@ -11526,6 +11609,7 @@ private function setHabtmValues(ReflectedTable $t1, ReflectedTable $t2, array &$
1152611609
use Tqdev\PhpCrudApi\Middleware\Router\SimpleRouter;
1152711610
use Tqdev\PhpCrudApi\Middleware\SanitationMiddleware;
1152811611
use Tqdev\PhpCrudApi\Middleware\SslRedirectMiddleware;
11612+
use Tqdev\PhpCrudApi\Middleware\TextSearchMiddleware;
1152911613
use Tqdev\PhpCrudApi\Middleware\ValidationMiddleware;
1153011614
use Tqdev\PhpCrudApi\Middleware\XmlMiddleware;
1153111615
use Tqdev\PhpCrudApi\Middleware\XsrfMiddleware;
@@ -11545,6 +11629,7 @@ public function __construct(Config $config)
1154511629
$config->getAddress(),
1154611630
$config->getPort(),
1154711631
$config->getDatabase(),
11632+
$config->getCommand(),
1154811633
$config->getTables(),
1154911634
$config->getMapping(),
1155011635
$config->getUsername(),
@@ -11611,6 +11696,9 @@ public function __construct(Config $config)
1161111696
case 'customization':
1161211697
new CustomizationMiddleware($router, $responder, $config, $middleware, $reflection);
1161311698
break;
11699+
case 'textSearch':
11700+
new TextSearchMiddleware($router, $responder, $properties, $reflection);
11701+
break;
1161411702
case 'xml':
1161511703
new XmlMiddleware($router, $responder, $config, $middleware, $reflection);
1161611704
break;
@@ -11730,6 +11818,7 @@ class Config
1173011818
'username' => '',
1173111819
'password' => '',
1173211820
'database' => '',
11821+
'command' => '',
1173311822
'tables' => '',
1173411823
'mapping' => '',
1173511824
'middlewares' => 'cors,errors',
@@ -11860,6 +11949,11 @@ public function getDatabase(): string
1186011949
return $this->values['database'];
1186111950
}
1186211951

11952+
public function getCommand(): string
11953+
{
11954+
return $this->values['command'];
11955+
}
11956+
1186311957
public function getTables(): array
1186411958
{
1186511959
return array_filter(array_map('trim', explode(',', $this->values['tables'])));

0 commit comments

Comments
 (0)