Skip to content

Commit 0123135

Browse files
committed
joinLimits
1 parent 505492f commit 0123135

File tree

8 files changed

+78
-17
lines changed

8 files changed

+78
-17
lines changed

api.php

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3227,6 +3227,52 @@ public function handle(Request $request): Response
32273227
}
32283228
}
32293229

3230+
// file: src/Tqdev/PhpCrudApi/Middleware/JoinLimitsMiddleware.php
3231+
3232+
class JoinLimitsMiddleware extends Middleware
3233+
{
3234+
private $reflection;
3235+
3236+
public function __construct(Router $router, Responder $responder, array $properties, ReflectionService $reflection)
3237+
{
3238+
parent::__construct($router, $responder, $properties);
3239+
$this->reflection = $reflection;
3240+
$this->utils = new RequestUtils($reflection);
3241+
}
3242+
3243+
public function handle(Request $request): Response
3244+
{
3245+
$operation = $this->utils->getOperation($request);
3246+
$params = $request->getParams();
3247+
if (in_array($operation, ['read', 'list']) && isset($params['join'])) {
3248+
$maxDepth = (int) $this->getProperty('depth', '3');
3249+
$maxTables = (int) $this->getProperty('tables', '10');
3250+
$maxRecords = (int) $this->getProperty('records', '1000');
3251+
$tableCount = 0;
3252+
$joinPaths = array();
3253+
for ($i = 0; $i < count($params['join']); $i++) {
3254+
$joinPath = array();
3255+
$tables = explode(',', $params['join'][$i]);
3256+
for ($depth = 0; $depth < min($maxDepth, count($tables)); $depth++) {
3257+
array_push($joinPath, $table);
3258+
$tableCount += 1;
3259+
if ($tableCount == $maxTables) {
3260+
break;
3261+
}
3262+
}
3263+
array_push($joinPaths, $joinPath);
3264+
if ($tableCount == $maxTables) {
3265+
break;
3266+
}
3267+
}
3268+
$params['join'] = $joinPaths;
3269+
$request->setParams($params);
3270+
VariableStore::set("joinLimits.maxRecords", $maxRecords);
3271+
}
3272+
return $this->next->handle($request);
3273+
}
3274+
}
3275+
32303276
// file: src/Tqdev/PhpCrudApi/Middleware/JwtAuthMiddleware.php
32313277

32323278
class JwtAuthMiddleware extends Middleware
@@ -5021,7 +5067,8 @@ private function addPkRecords(ReflectedTable $t1, ReflectedTable $t2, array $pkV
50215067
$conditions[] = new ColumnCondition($fk, 'in', $pkValueKeys);
50225068
}
50235069
$condition = OrCondition::fromArray($conditions);
5024-
foreach ($db->selectAll($t2, $columnNames, $condition, array(), 0, -1) as $record) {
5070+
$limit = VariableStore::get("joinLimits.maxRecords") ?: -1;
5071+
foreach ($db->selectAll($t2, $columnNames, $condition, array(), 0, $limit) as $record) {
50255072
$records[] = $record;
50265073
}
50275074
}
@@ -5067,7 +5114,8 @@ private function getHabtmEmptyValues(ReflectedTable $t1, ReflectedTable $t2, Ref
50675114
$pkIds = implode(',', array_keys($pkValues));
50685115
$condition = new ColumnCondition($t3->getColumn($fk1Name), 'in', $pkIds);
50695116

5070-
$records = $db->selectAll($t3, $columnNames, $condition, array(), 0, -1);
5117+
$limit = VariableStore::get("joinLimits.maxRecords") ?: -1;
5118+
$records = $db->selectAll($t3, $columnNames, $condition, array(), 0, $limit);
50715119
foreach ($records as $record) {
50725120
$val1 = $record[$fk1Name];
50735121
$val2 = $record[$fk2Name];
@@ -5219,6 +5267,9 @@ public function __construct(Config $config)
52195267
case 'pageLimits':
52205268
new PageLimitsMiddleware($router, $responder, $properties, $reflection);
52215269
break;
5270+
case 'joinLimits':
5271+
new JoinLimitsMiddleware($router, $responder, $properties, $reflection);
5272+
break;
52225273
case 'customization':
52235274
new CustomizationMiddleware($router, $responder, $properties, $reflection);
52245275
break;

src/Tqdev/PhpCrudApi/Api.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Tqdev\PhpCrudApi\Middleware\CorsMiddleware;
1616
use Tqdev\PhpCrudApi\Middleware\CustomizationMiddleware;
1717
use Tqdev\PhpCrudApi\Middleware\FirewallMiddleware;
18+
use Tqdev\PhpCrudApi\Middleware\JoinLimitsMiddleware;
1819
use Tqdev\PhpCrudApi\Middleware\JwtAuthMiddleware;
1920
use Tqdev\PhpCrudApi\Middleware\MultiTenancyMiddleware;
2021
use Tqdev\PhpCrudApi\Middleware\PageLimitsMiddleware;
@@ -78,6 +79,9 @@ public function __construct(Config $config)
7879
case 'pageLimits':
7980
new PageLimitsMiddleware($router, $responder, $properties, $reflection);
8081
break;
82+
case 'joinLimits':
83+
new JoinLimitsMiddleware($router, $responder, $properties, $reflection);
84+
break;
8185
case 'customization':
8286
new CustomizationMiddleware($router, $responder, $properties, $reflection);
8387
break;

src/Tqdev/PhpCrudApi/Record/RelationJoiner.php

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Tqdev\PhpCrudApi\Database\GenericDB;
77
use Tqdev\PhpCrudApi\Record\Condition\ColumnCondition;
88
use Tqdev\PhpCrudApi\Record\Condition\OrCondition;
9+
use Tqdev\PhpCrudApi\Middleware\Communication\VariableStore;
910

1011
class RelationJoiner
1112
{
@@ -133,7 +134,7 @@ private function addJoinsForTables(ReflectedTable $t1, PathTree $joins, array &$
133134
}
134135
if ($habtmValues != null) {
135136
$this->fillFkValues($t2, $newRecords, $habtmValues->fkValues);
136-
$this->setHabtmValues($t1, $t3, $records, $habtmValues);
137+
$this->setHabtmValues($t1, $t2, $records, $habtmValues);
137138
}
138139
}
139140
}
@@ -208,7 +209,8 @@ private function addPkRecords(ReflectedTable $t1, ReflectedTable $t2, array $pkV
208209
$conditions[] = new ColumnCondition($fk, 'in', $pkValueKeys);
209210
}
210211
$condition = OrCondition::fromArray($conditions);
211-
foreach ($db->selectAll($t2, $columnNames, $condition, array(), 0, -1) as $record) {
212+
$limit = VariableStore::get("joinLimits.maxRecords") ?: -1;
213+
foreach ($db->selectAll($t2, $columnNames, $condition, array(), 0, $limit) as $record) {
212214
$records[] = $record;
213215
}
214216
}
@@ -254,7 +256,8 @@ private function getHabtmEmptyValues(ReflectedTable $t1, ReflectedTable $t2, Ref
254256
$pkIds = implode(',', array_keys($pkValues));
255257
$condition = new ColumnCondition($t3->getColumn($fk1Name), 'in', $pkIds);
256258

257-
$records = $db->selectAll($t3, $columnNames, $condition, array(), 0, -1);
259+
$limit = VariableStore::get("joinLimits.maxRecords") ?: -1;
260+
$records = $db->selectAll($t3, $columnNames, $condition, array(), 0, $limit);
258261
foreach ($records as $record) {
259262
$val1 = $record[$fk1Name];
260263
$val2 = $record[$fk2Name];
@@ -265,18 +268,18 @@ private function getHabtmEmptyValues(ReflectedTable $t1, ReflectedTable $t2, Ref
265268
return new HabtmValues($pkValues, $fkValues);
266269
}
267270

268-
private function setHabtmValues(ReflectedTable $t1, ReflectedTable $t3, array &$records, HabtmValues $habtmValues) /*: void*/
271+
private function setHabtmValues(ReflectedTable $t1, ReflectedTable $t2, array &$records, HabtmValues $habtmValues) /*: void*/
269272
{
270273
$pkName = $t1->getPk()->getName();
271-
$t3Name = $t3->getName();
274+
$t2Name = $t2->getName();
272275
foreach ($records as $i => $record) {
273276
$key = $record[$pkName];
274277
$val = array();
275278
$fks = $habtmValues->pkValues[$key];
276279
foreach ($fks as $fk) {
277280
$val[] = $habtmValues->fkValues[$fk];
278281
}
279-
$records[$i][$t3Name] = $val;
282+
$records[$i][$t2Name] = $val;
280283
}
281284
}
282285
}

tests/config/base.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
'username' => 'php-crud-api',
55
'password' => 'php-crud-api',
66
'controllers' => 'records,columns,cache,openapi',
7-
'middlewares' => 'cors,jwtAuth,basicAuth,authorization,validation,sanitation,multiTenancy,pageLimits,customization',
7+
'middlewares' => 'cors,jwtAuth,basicAuth,authorization,validation,sanitation,multiTenancy,pageLimits,joinLimits,customization',
88
'jwtAuth.mode' => 'optional',
99
'jwtAuth.time' => '1538207605',
1010
'jwtAuth.secret' => 'axpIrCGNGqxzx2R9dtXLIPUSqPo778uhb8CA0F4Hx',
@@ -30,6 +30,9 @@
3030
},
3131
'pageLimits.pages' => 5,
3232
'pageLimits.records' => 10,
33+
'joinLimits.depth' => 2,
34+
'joinLimits.tables' => 4,
35+
'joinLimits.records' => 10,
3336
'customization.beforeHandler' => function ($operation, $tableName, $request, $environment) {
3437
$environment->start = 0.003/*microtime(true)*/;
3538
},

tests/functional/001_records/030_list_example_from_readme_tags_only.log

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ GET /records/posts?join=tags&filter=id,eq,1
22
===
33
200
44
Content-Type: application/json
5-
Content-Length: 182
5+
Content-Length: 177
66

7-
{"records":[{"id":1,"user_id":1,"category_id":1,"content":"blog started","post_tags":[{"id":1,"name":"funny","is_important":false},{"id":2,"name":"important","is_important":true}]}]}
7+
{"records":[{"id":1,"user_id":1,"category_id":1,"content":"blog started","tags":[{"id":1,"name":"funny","is_important":false},{"id":2,"name":"important","is_important":true}]}]}

tests/functional/001_records/032_list_example_from_readme.log

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ GET /records/posts?join=categories&join=tags&join=comments&filter=id,eq,1
22
===
33
200
44
Content-Type: application/json
5-
Content-Length: 350
5+
Content-Length: 345
66

7-
{"records":[{"id":1,"user_id":1,"category_id":{"id":1,"name":"announcement","icon":null},"content":"blog started","post_tags":[{"id":1,"name":"funny","is_important":false},{"id":2,"name":"important","is_important":true}],"comments":[{"id":1,"post_id":1,"message":"great","category_id":3},{"id":2,"post_id":1,"message":"fantastic","category_id":3}]}]}
7+
{"records":[{"id":1,"user_id":1,"category_id":{"id":1,"name":"announcement","icon":null},"content":"blog started","tags":[{"id":1,"name":"funny","is_important":false},{"id":2,"name":"important","is_important":true}],"comments":[{"id":1,"post_id":1,"message":"great","category_id":3},{"id":2,"post_id":1,"message":"fantastic","category_id":3}]}]}

tests/functional/001_records/061_get_post_content_with_included_tag_names.log

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ GET /records/posts/1?include=content,tags.name&join=tags
22
===
33
200
44
Content-Type: application/json
5-
Content-Length: 99
5+
Content-Length: 94
66

7-
{"id":1,"content":"blog started","post_tags":[{"id":1,"name":"funny"},{"id":2,"name":"important"}]}
7+
{"id":1,"content":"blog started","tags":[{"id":1,"name":"funny"},{"id":2,"name":"important"}]}

tests/functional/001_records/079_read_post_with_categories.log

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ GET /records/posts/1?join=tags&include=tags.name
22
===
33
200
44
Content-Type: application/json
5-
Content-Length: 74
5+
Content-Length: 69
66

7-
{"id":1,"post_tags":[{"id":1,"name":"funny"},{"id":2,"name":"important"}]}
7+
{"id":1,"tags":[{"id":1,"name":"funny"},{"id":2,"name":"important"}]}
88
===
99
GET /records/posts/1?join=categories&include=category_id,categories.name
1010
===

0 commit comments

Comments
 (0)