Skip to content

Commit 34c4f9f

Browse files
committed
Fix for #881
1 parent e988026 commit 34c4f9f

File tree

8 files changed

+206
-4
lines changed

8 files changed

+206
-4
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,7 @@ You can enable the following middleware using the "middlewares" config parameter
664664
- "multiTenancy": Restricts tenants access in a multi-tenant scenario
665665
- "pageLimits": Restricts list operations to prevent database scraping
666666
- "joinLimits": Restricts join parameters to prevent database scraping
667+
- "textSearch": Search in all text fields with a simple paramater
667668
- "customization": Provides handlers for request and response customization
668669
- "json": Support read/write of JSON strings as JSON objects/arrays
669670
- "xml": Translates all input and output from JSON to XML
@@ -742,6 +743,7 @@ You can tune the middleware behavior using middleware specific configuration par
742743
- "joinLimits.depth": The maximum depth (length) that is allowed in a join path ("3")
743744
- "joinLimits.tables": The maximum number of tables that you are allowed to join ("10")
744745
- "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")
745747
- "customization.beforeHandler": Handler to implement request customization ("")
746748
- "customization.afterHandler": Handler to implement response customization ("")
747749
- "json.controllers": Controllers to process JSON strings for ("records,geojson")

api.include.php

Lines changed: 65 additions & 1 deletion
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,
@@ -9088,6 +9093,61 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
90889093
}
90899094
}
90909095

9096+
// file: src/Tqdev/PhpCrudApi/Middleware/TextSearchMiddleware.php
9097+
namespace Tqdev\PhpCrudApi\Middleware {
9098+
9099+
use Psr\Http\Message\ResponseInterface;
9100+
use Psr\Http\Message\ServerRequestInterface;
9101+
use Psr\Http\Server\RequestHandlerInterface;
9102+
use Tqdev\PhpCrudApi\Column\ReflectionService;
9103+
use Tqdev\PhpCrudApi\Controller\Responder;
9104+
use Tqdev\PhpCrudApi\Middleware\Base\Middleware;
9105+
use Tqdev\PhpCrudApi\Middleware\Router\Router;
9106+
use Tqdev\PhpCrudApi\RequestUtils;
9107+
9108+
class TextSearchMiddleware extends Middleware
9109+
{
9110+
private $reflection;
9111+
9112+
public function __construct(Router $router, Responder $responder, array $properties, ReflectionService $reflection)
9113+
{
9114+
parent::__construct($router, $responder, $properties);
9115+
$this->reflection = $reflection;
9116+
}
9117+
9118+
public function process(ServerRequestInterface $request, RequestHandlerInterface $next): ResponseInterface
9119+
{
9120+
$operation = RequestUtils::getOperation($request);
9121+
if ($operation == 'list') {
9122+
$tableName = RequestUtils::getPathSegment($request, 2);
9123+
$params = RequestUtils::getParams($request);
9124+
$parameterName = $this->getProperty('parameter', 'search');
9125+
if (isset($params[$parameterName])) {
9126+
$search = $params[$parameterName][0];
9127+
unset($params[$parameterName]);
9128+
$table = $this->reflection->getTable($tableName);
9129+
$i = 0;
9130+
foreach ($table->getColumnNames() as $columnName) {
9131+
$column = $table->getColumn($columnName);
9132+
while (isset($params["filter$i"])) {
9133+
$i++;
9134+
}
9135+
if ($i >= 10) {
9136+
break;
9137+
}
9138+
if ($column->isText()) {
9139+
$params["filter$i"] = "$columnName,cs,$search";
9140+
$i++;
9141+
}
9142+
}
9143+
}
9144+
$request = RequestUtils::setParams($request, $params);
9145+
}
9146+
return $next->handle($request);
9147+
}
9148+
}
9149+
}
9150+
90919151
// file: src/Tqdev/PhpCrudApi/Middleware/ValidationMiddleware.php
90929152
namespace Tqdev\PhpCrudApi\Middleware {
90939153

@@ -11533,6 +11593,7 @@ private function setHabtmValues(ReflectedTable $t1, ReflectedTable $t2, array &$
1153311593
use Tqdev\PhpCrudApi\Middleware\Router\SimpleRouter;
1153411594
use Tqdev\PhpCrudApi\Middleware\SanitationMiddleware;
1153511595
use Tqdev\PhpCrudApi\Middleware\SslRedirectMiddleware;
11596+
use Tqdev\PhpCrudApi\Middleware\TextSearchMiddleware;
1153611597
use Tqdev\PhpCrudApi\Middleware\ValidationMiddleware;
1153711598
use Tqdev\PhpCrudApi\Middleware\XmlMiddleware;
1153811599
use Tqdev\PhpCrudApi\Middleware\XsrfMiddleware;
@@ -11619,6 +11680,9 @@ public function __construct(Config $config)
1161911680
case 'customization':
1162011681
new CustomizationMiddleware($router, $responder, $properties, $reflection);
1162111682
break;
11683+
case 'textSearch':
11684+
new TextSearchMiddleware($router, $responder, $properties, $reflection);
11685+
break;
1162211686
case 'xml':
1162311687
new XmlMiddleware($router, $responder, $properties, $reflection);
1162411688
break;

api.php

Lines changed: 65 additions & 1 deletion
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,
@@ -9088,6 +9093,61 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
90889093
}
90899094
}
90909095

9096+
// file: src/Tqdev/PhpCrudApi/Middleware/TextSearchMiddleware.php
9097+
namespace Tqdev\PhpCrudApi\Middleware {
9098+
9099+
use Psr\Http\Message\ResponseInterface;
9100+
use Psr\Http\Message\ServerRequestInterface;
9101+
use Psr\Http\Server\RequestHandlerInterface;
9102+
use Tqdev\PhpCrudApi\Column\ReflectionService;
9103+
use Tqdev\PhpCrudApi\Controller\Responder;
9104+
use Tqdev\PhpCrudApi\Middleware\Base\Middleware;
9105+
use Tqdev\PhpCrudApi\Middleware\Router\Router;
9106+
use Tqdev\PhpCrudApi\RequestUtils;
9107+
9108+
class TextSearchMiddleware extends Middleware
9109+
{
9110+
private $reflection;
9111+
9112+
public function __construct(Router $router, Responder $responder, array $properties, ReflectionService $reflection)
9113+
{
9114+
parent::__construct($router, $responder, $properties);
9115+
$this->reflection = $reflection;
9116+
}
9117+
9118+
public function process(ServerRequestInterface $request, RequestHandlerInterface $next): ResponseInterface
9119+
{
9120+
$operation = RequestUtils::getOperation($request);
9121+
if ($operation == 'list') {
9122+
$tableName = RequestUtils::getPathSegment($request, 2);
9123+
$params = RequestUtils::getParams($request);
9124+
$parameterName = $this->getProperty('parameter', 'search');
9125+
if (isset($params[$parameterName])) {
9126+
$search = $params[$parameterName][0];
9127+
unset($params[$parameterName]);
9128+
$table = $this->reflection->getTable($tableName);
9129+
$i = 0;
9130+
foreach ($table->getColumnNames() as $columnName) {
9131+
$column = $table->getColumn($columnName);
9132+
while (isset($params["filter$i"])) {
9133+
$i++;
9134+
}
9135+
if ($i >= 10) {
9136+
break;
9137+
}
9138+
if ($column->isText()) {
9139+
$params["filter$i"] = "$columnName,cs,$search";
9140+
$i++;
9141+
}
9142+
}
9143+
}
9144+
$request = RequestUtils::setParams($request, $params);
9145+
}
9146+
return $next->handle($request);
9147+
}
9148+
}
9149+
}
9150+
90919151
// file: src/Tqdev/PhpCrudApi/Middleware/ValidationMiddleware.php
90929152
namespace Tqdev\PhpCrudApi\Middleware {
90939153

@@ -11533,6 +11593,7 @@ private function setHabtmValues(ReflectedTable $t1, ReflectedTable $t2, array &$
1153311593
use Tqdev\PhpCrudApi\Middleware\Router\SimpleRouter;
1153411594
use Tqdev\PhpCrudApi\Middleware\SanitationMiddleware;
1153511595
use Tqdev\PhpCrudApi\Middleware\SslRedirectMiddleware;
11596+
use Tqdev\PhpCrudApi\Middleware\TextSearchMiddleware;
1153611597
use Tqdev\PhpCrudApi\Middleware\ValidationMiddleware;
1153711598
use Tqdev\PhpCrudApi\Middleware\XmlMiddleware;
1153811599
use Tqdev\PhpCrudApi\Middleware\XsrfMiddleware;
@@ -11619,6 +11680,9 @@ public function __construct(Config $config)
1161911680
case 'customization':
1162011681
new CustomizationMiddleware($router, $responder, $properties, $reflection);
1162111682
break;
11683+
case 'textSearch':
11684+
new TextSearchMiddleware($router, $responder, $properties, $reflection);
11685+
break;
1162211686
case 'xml':
1162311687
new XmlMiddleware($router, $responder, $properties, $reflection);
1162411688
break;

src/Tqdev/PhpCrudApi/Api.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
use Tqdev\PhpCrudApi\Middleware\Router\SimpleRouter;
3636
use Tqdev\PhpCrudApi\Middleware\SanitationMiddleware;
3737
use Tqdev\PhpCrudApi\Middleware\SslRedirectMiddleware;
38+
use Tqdev\PhpCrudApi\Middleware\TextSearchMiddleware;
3839
use Tqdev\PhpCrudApi\Middleware\ValidationMiddleware;
3940
use Tqdev\PhpCrudApi\Middleware\XmlMiddleware;
4041
use Tqdev\PhpCrudApi\Middleware\XsrfMiddleware;
@@ -121,6 +122,9 @@ public function __construct(Config $config)
121122
case 'customization':
122123
new CustomizationMiddleware($router, $responder, $properties, $reflection);
123124
break;
125+
case 'textSearch':
126+
new TextSearchMiddleware($router, $responder, $properties, $reflection);
127+
break;
124128
case 'xml':
125129
new XmlMiddleware($router, $responder, $properties, $reflection);
126130
break;

src/Tqdev/PhpCrudApi/Column/Reflection/ReflectedColumn.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,11 @@ public function isInteger(): bool
181181
return in_array($this->type, ['integer', 'bigint', 'smallint', 'tinyint']);
182182
}
183183

184+
public function isText(): bool
185+
{
186+
return in_array($this->type, ['varchar', 'clob']);
187+
}
188+
184189
public function setPk($value) /*: void*/
185190
{
186191
$this->pk = $value;
@@ -205,7 +210,7 @@ public function serialize()
205210
{
206211
$json = [
207212
'name' => $this->realName,
208-
'alias' => $this->name!=$this->realName?$this->name:null,
213+
'alias' => $this->name != $this->realName ? $this->name : null,
209214
'type' => $this->type,
210215
'length' => $this->length,
211216
'precision' => $this->precision,
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
namespace Tqdev\PhpCrudApi\Middleware;
4+
5+
use Psr\Http\Message\ResponseInterface;
6+
use Psr\Http\Message\ServerRequestInterface;
7+
use Psr\Http\Server\RequestHandlerInterface;
8+
use Tqdev\PhpCrudApi\Column\ReflectionService;
9+
use Tqdev\PhpCrudApi\Controller\Responder;
10+
use Tqdev\PhpCrudApi\Middleware\Base\Middleware;
11+
use Tqdev\PhpCrudApi\Middleware\Router\Router;
12+
use Tqdev\PhpCrudApi\RequestUtils;
13+
14+
class TextSearchMiddleware extends Middleware
15+
{
16+
private $reflection;
17+
18+
public function __construct(Router $router, Responder $responder, array $properties, ReflectionService $reflection)
19+
{
20+
parent::__construct($router, $responder, $properties);
21+
$this->reflection = $reflection;
22+
}
23+
24+
public function process(ServerRequestInterface $request, RequestHandlerInterface $next): ResponseInterface
25+
{
26+
$operation = RequestUtils::getOperation($request);
27+
if ($operation == 'list') {
28+
$tableName = RequestUtils::getPathSegment($request, 2);
29+
$params = RequestUtils::getParams($request);
30+
$parameterName = $this->getProperty('parameter', 'search');
31+
if (isset($params[$parameterName])) {
32+
$search = $params[$parameterName][0];
33+
unset($params[$parameterName]);
34+
$table = $this->reflection->getTable($tableName);
35+
$i = 0;
36+
foreach ($table->getColumnNames() as $columnName) {
37+
$column = $table->getColumn($columnName);
38+
while (isset($params["filter$i"])) {
39+
$i++;
40+
}
41+
if ($i >= 10) {
42+
break;
43+
}
44+
if ($column->isText()) {
45+
$params["filter$i"] = "$columnName,cs,$search";
46+
$i++;
47+
}
48+
}
49+
}
50+
$request = RequestUtils::setParams($request, $params);
51+
}
52+
return $next->handle($request);
53+
}
54+
}

tests/config/base.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
'password' => 'incorrect_password',
99
'mapping' => 'abc_posts.abc_id=posts.id,abc_posts.abc_user_id=posts.user_id,abc_posts.abc_category_id=posts.category_id,abc_posts.abc_content=posts.content',
1010
'controllers' => 'records,columns,cache,openapi,geojson,status',
11-
'middlewares' => 'sslRedirect,xml,cors,json,reconnect,apiKeyAuth,apiKeyDbAuth,dbAuth,jwtAuth,basicAuth,authorization,sanitation,validation,ipAddress,multiTenancy,pageLimits,joinLimits,customization',
11+
'middlewares' => 'sslRedirect,xml,cors,json,reconnect,apiKeyAuth,apiKeyDbAuth,dbAuth,jwtAuth,basicAuth,authorization,sanitation,validation,ipAddress,multiTenancy,pageLimits,joinLimits,textSearch,customization',
1212
'apiKeyAuth.mode' => 'optional',
1313
'apiKeyAuth.keys' => '123456789abc',
1414
'apiKeyDbAuth.mode' => 'optional',
@@ -57,6 +57,7 @@
5757
'joinLimits.depth' => 2,
5858
'joinLimits.tables' => 4,
5959
'joinLimits.records' => 10,
60+
'textSearch.parameter' => 'q',
6061
'customization.beforeHandler' => function ($operation, $tableName, $request, $environment) {
6162
$environment->start = 0.003/*microtime(true)*/;
6263
},
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
===
2+
GET /records/posts?q=Grüßgott
3+
===
4+
200
5+
Content-Type: application/json; charset=utf-8
6+
Content-Length: 209
7+
8+
{"records":[{"id":2,"user_id":2,"category_id":2,"content":"🦀€ Grüßgott, Вiтаю, dobrý deň, hyvää päivää, გამარჯობა, Γεια σας, góðan dag, здравствуйте"}]}

0 commit comments

Comments
 (0)