Browse Source

joinLimits

Maurits van der Schee 5 years ago
parent
commit
0123135172

+ 53
- 2
api.php View File

@@ -3227,6 +3227,52 @@ class FirewallMiddleware extends Middleware
3227 3227
     }
3228 3228
 }
3229 3229
 
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
+
3230 3276
 // file: src/Tqdev/PhpCrudApi/Middleware/JwtAuthMiddleware.php
3231 3277
 
3232 3278
 class JwtAuthMiddleware extends Middleware
@@ -5021,7 +5067,8 @@ class RelationJoiner
5021 5067
             $conditions[] = new ColumnCondition($fk, 'in', $pkValueKeys);
5022 5068
         }
5023 5069
         $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) {
5025 5072
             $records[] = $record;
5026 5073
         }
5027 5074
     }
@@ -5067,7 +5114,8 @@ class RelationJoiner
5067 5114
         $pkIds = implode(',', array_keys($pkValues));
5068 5115
         $condition = new ColumnCondition($t3->getColumn($fk1Name), 'in', $pkIds);
5069 5116
 
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);
5071 5119
         foreach ($records as $record) {
5072 5120
             $val1 = $record[$fk1Name];
5073 5121
             $val2 = $record[$fk2Name];
@@ -5219,6 +5267,9 @@ class Api
5219 5267
                 case 'pageLimits':
5220 5268
                     new PageLimitsMiddleware($router, $responder, $properties, $reflection);
5221 5269
                     break;
5270
+                case 'joinLimits':
5271
+                    new JoinLimitsMiddleware($router, $responder, $properties, $reflection);
5272
+                    break;
5222 5273
                 case 'customization':
5223 5274
                     new CustomizationMiddleware($router, $responder, $properties, $reflection);
5224 5275
                     break;

+ 4
- 0
src/Tqdev/PhpCrudApi/Api.php View File

@@ -15,6 +15,7 @@ use Tqdev\PhpCrudApi\Middleware\BasicAuthMiddleware;
15 15
 use Tqdev\PhpCrudApi\Middleware\CorsMiddleware;
16 16
 use Tqdev\PhpCrudApi\Middleware\CustomizationMiddleware;
17 17
 use Tqdev\PhpCrudApi\Middleware\FirewallMiddleware;
18
+use Tqdev\PhpCrudApi\Middleware\JoinLimitsMiddleware;
18 19
 use Tqdev\PhpCrudApi\Middleware\JwtAuthMiddleware;
19 20
 use Tqdev\PhpCrudApi\Middleware\MultiTenancyMiddleware;
20 21
 use Tqdev\PhpCrudApi\Middleware\PageLimitsMiddleware;
@@ -78,6 +79,9 @@ class Api
78 79
                 case 'pageLimits':
79 80
                     new PageLimitsMiddleware($router, $responder, $properties, $reflection);
80 81
                     break;
82
+                case 'joinLimits':
83
+                    new JoinLimitsMiddleware($router, $responder, $properties, $reflection);
84
+                    break;
81 85
                 case 'customization':
82 86
                     new CustomizationMiddleware($router, $responder, $properties, $reflection);
83 87
                     break;

+ 9
- 6
src/Tqdev/PhpCrudApi/Record/RelationJoiner.php View File

@@ -6,6 +6,7 @@ use Tqdev\PhpCrudApi\Column\Reflection\ReflectedTable;
6 6
 use Tqdev\PhpCrudApi\Database\GenericDB;
7 7
 use Tqdev\PhpCrudApi\Record\Condition\ColumnCondition;
8 8
 use Tqdev\PhpCrudApi\Record\Condition\OrCondition;
9
+use Tqdev\PhpCrudApi\Middleware\Communication\VariableStore;
9 10
 
10 11
 class RelationJoiner
11 12
 {
@@ -133,7 +134,7 @@ class RelationJoiner
133 134
             } 
134 135
             if ($habtmValues != null) {
135 136
                 $this->fillFkValues($t2, $newRecords, $habtmValues->fkValues);
136
-                $this->setHabtmValues($t1, $t3, $records, $habtmValues);
137
+                $this->setHabtmValues($t1, $t2, $records, $habtmValues);
137 138
             }
138 139
         }
139 140
     }
@@ -208,7 +209,8 @@ class RelationJoiner
208 209
             $conditions[] = new ColumnCondition($fk, 'in', $pkValueKeys);
209 210
         }
210 211
         $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) {
212 214
             $records[] = $record;
213 215
         }
214 216
     }
@@ -254,7 +256,8 @@ class RelationJoiner
254 256
         $pkIds = implode(',', array_keys($pkValues));
255 257
         $condition = new ColumnCondition($t3->getColumn($fk1Name), 'in', $pkIds);
256 258
 
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);
258 261
         foreach ($records as $record) {
259 262
             $val1 = $record[$fk1Name];
260 263
             $val2 = $record[$fk2Name];
@@ -265,10 +268,10 @@ class RelationJoiner
265 268
         return new HabtmValues($pkValues, $fkValues);
266 269
     }
267 270
 
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*/
269 272
     {
270 273
         $pkName = $t1->getPk()->getName();
271
-        $t3Name = $t3->getName();
274
+        $t2Name = $t2->getName();
272 275
         foreach ($records as $i => $record) {
273 276
             $key = $record[$pkName];
274 277
             $val = array();
@@ -276,7 +279,7 @@ class RelationJoiner
276 279
             foreach ($fks as $fk) {
277 280
                 $val[] = $habtmValues->fkValues[$fk];
278 281
             }
279
-            $records[$i][$t3Name] = $val;
282
+            $records[$i][$t2Name] = $val;
280 283
         }
281 284
     }
282 285
 }

+ 4
- 1
tests/config/base.php View File

@@ -4,7 +4,7 @@ $settings = [
4 4
     'username' => 'php-crud-api',
5 5
     'password' => 'php-crud-api',
6 6
     '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',
8 8
     'jwtAuth.mode' => 'optional',
9 9
     'jwtAuth.time' => '1538207605',
10 10
     'jwtAuth.secret' => 'axpIrCGNGqxzx2R9dtXLIPUSqPo778uhb8CA0F4Hx',
@@ -30,6 +30,9 @@ $settings = [
30 30
     },
31 31
     'pageLimits.pages' => 5,
32 32
     'pageLimits.records' => 10,
33
+    'joinLimits.depth' => 2,
34
+    'joinLimits.tables' => 4,
35
+    'joinLimits.records' => 10,
33 36
     'customization.beforeHandler' => function ($operation, $tableName, $request, $environment) {
34 37
         $environment->start = 0.003/*microtime(true)*/;
35 38
     },

+ 2
- 2
tests/functional/001_records/030_list_example_from_readme_tags_only.log View File

@@ -2,6 +2,6 @@ GET /records/posts?join=tags&filter=id,eq,1
2 2
 ===
3 3
 200
4 4
 Content-Type: application/json
5
-Content-Length: 182
5
+Content-Length: 177
6 6
 
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}]}]}

+ 2
- 2
tests/functional/001_records/032_list_example_from_readme.log View File

@@ -2,6 +2,6 @@ GET /records/posts?join=categories&join=tags&join=comments&filter=id,eq,1
2 2
 ===
3 3
 200
4 4
 Content-Type: application/json
5
-Content-Length: 350
5
+Content-Length: 345
6 6
 
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}]}]}

+ 2
- 2
tests/functional/001_records/061_get_post_content_with_included_tag_names.log View File

@@ -2,6 +2,6 @@ GET /records/posts/1?include=content,tags.name&join=tags
2 2
 ===
3 3
 200
4 4
 Content-Type: application/json
5
-Content-Length: 99
5
+Content-Length: 94
6 6
 
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"}]}

+ 2
- 2
tests/functional/001_records/079_read_post_with_categories.log View File

@@ -2,9 +2,9 @@ GET /records/posts/1?join=tags&include=tags.name
2 2
 ===
3 3
 200
4 4
 Content-Type: application/json
5
-Content-Length: 74
5
+Content-Length: 69
6 6
 
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"}]}
8 8
 ===
9 9
 GET /records/posts/1?join=categories&include=category_id,categories.name
10 10
 ===

Loading…
Cancel
Save