ILIAS  trunk Revision v11.0_alpha-2662-g519ff7d528f
DatabaseSearcherTest.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
22 
46 
47 class DatabaseSearcherTest extends TestCase
48 {
49  protected const array RESULT = [
50  ['rbac_id' => 37, 'obj_id' => 55, 'obj_type' => 'type1'],
51  ['rbac_id' => 123, 'obj_id' => 85, 'obj_type' => 'type2'],
52  ['rbac_id' => 98, 'obj_id' => 4, 'obj_type' => 'type3']
53  ];
54 
55  protected function mockRessourceIDsMatchArrayData(
56  array $array,
57  RessourceIDInterface ...$ressource_ids
58  ): bool {
59  $data = [];
60  foreach ($ressource_ids as $ressource_id) {
61  $data[] = [
62  'rbac_id' => $ressource_id->obj_id,
63  'obj_id' => $ressource_id->sub_id,
64  'obj_type' => $ressource_id->type
65  ];
66  }
67 
68  return $array === $data;
69  }
70 
71  protected function getDatabaseSearcher(array $db_result): DatabaseSearcher
72  {
73  $ressource_factory = new class () extends NullRessourceIDFactory {
74  public function ressourceID(int $obj_id, int $sub_id, string $type): RessourceIDInterface
75  {
76  return new class ($obj_id, $sub_id, $type) extends NullRessourceID {
77  public function __construct(
78  public int $obj_id,
79  public int $sub_id,
80  public string $type
81  ) {
82  }
83  };
84  }
85  };
86 
87  $paths_parser_factory = new class () extends NullDatabasePathsParserFactory {
88  public function forSearch(): DatabasePathsParserInterface
89  {
90  return new class () extends NullDatabasePathsParser {
91  protected array $paths = [];
92  protected bool $force_join_to_base_table = false;
93 
94  public function addPathAndGetColumn(
96  bool $force_join_to_base_table
97  ): string {
98  if (!$this->force_join_to_base_table) {
99  $this->force_join_to_base_table = $force_join_to_base_table;
100  }
101  $path_string = $path->toString();
102  $this->paths[] = $path_string;
103  return $path_string . '_column';
104  }
105 
106  public function getSelectForQuery(): string
107  {
108  if (empty($this->paths)) {
109  throw new \ilMDRepositoryException('no paths!');
110  }
111  return 'selected paths' . ($this->force_join_to_base_table ? ' (join forced)' : '') .
112  ':[' . implode('~', $this->paths) . ']';
113  }
114 
115  public function getTableAliasForFilters(): string
116  {
117  if (empty($this->paths)) {
118  throw new \ilMDRepositoryException('no paths!');
119  }
120  return 'base_table';
121  }
122  };
123  }
124  };
125 
126  return new class (
127  $ressource_factory,
128  $paths_parser_factory,
129  $db_result
130  ) extends DatabaseSearcher {
131  public string $exposed_last_query;
132 
133  public function __construct(
134  RessourceIDFactoryInterface $ressource_factory,
135  DatabasePathsParserFactoryInterface $paths_parser_factory,
136  protected array $db_result
137  ) {
138  $this->ressource_factory = $ressource_factory;
139  $this->paths_parser_factory = $paths_parser_factory;
140  }
141 
142  protected function queryDB(string $query): \Generator
143  {
144  $this->exposed_last_query = $query;
145  yield from $this->db_result;
146  }
147 
148  protected function quoteIdentifier(string $identifier): string
149  {
150  return '~identifier:' . $identifier . '~';
151  }
152 
153  protected function quoteText(string $text): string
154  {
155  return '~text:' . $text . '~';
156  }
157 
158  protected function quoteInteger(int $integer): string
159  {
160  return '~int:' . $integer . '~';
161  }
162  };
163  }
164 
165  protected function getBasicClause(
166  bool $negated,
167  string $path,
168  Mode $mode,
169  string $value,
170  bool $mode_negated
171  ): ClauseInterface {
172  return new class ($negated, $path, $mode, $value, $mode_negated) extends NullClause {
173  public function __construct(
174  protected bool $negated,
175  protected string $path,
176  protected Mode $mode,
177  protected string $value,
178  protected bool $mode_negated
179  ) {
180  }
181 
182  public function isNegated(): bool
183  {
184  return $this->negated;
185  }
186 
187  public function isJoin(): bool
188  {
189  return false;
190  }
191 
192  public function basicProperties(): ?BasicPropertiesInterface
193  {
194  return new class (
195  $this->path,
196  $this->mode,
197  $this->value,
198  $this->mode_negated
199  ) extends NullBasicProperties {
200  public function __construct(
201  protected string $path,
202  protected Mode $mode,
203  protected string $value,
204  protected bool $mode_negated
205  ) {
206  }
207 
208  public function path(): PathInterface
209  {
210  return new class ($this->path) extends NullPath {
211  public function __construct(protected string $path)
212  {
213  }
214 
215  public function toString(): string
216  {
217  return $this->path;
218  }
219  };
220  }
221 
222  public function isModeNegated(): bool
223  {
224  return $this->mode_negated;
225  }
226 
227  public function mode(): Mode
228  {
229  return $this->mode;
230  }
231 
232  public function value(): string
233  {
234  return $this->value;
235  }
236  };
237  }
238 
239  public function joinProperties(): ?JoinPropertiesInterface
240  {
241  return null;
242  }
243  };
244  }
245 
246  protected function getJoinedClause(
247  bool $negated,
248  Operator $operator,
249  ClauseInterface ...$clauses
250  ): ClauseInterface {
251  return new class ($negated, $operator, $clauses) extends NullClause {
252  public function __construct(
253  protected bool $negated,
254  protected Operator $operator,
255  protected array $clauses
256  ) {
257  }
258 
259  public function isNegated(): bool
260  {
261  return $this->negated;
262  }
263 
264  public function isJoin(): bool
265  {
266  return true;
267  }
268 
269  public function basicProperties(): ?BasicPropertiesInterface
270  {
271  return null;
272  }
273 
274  public function joinProperties(): ?JoinPropertiesInterface
275  {
276  return new class ($this->operator, $this->clauses) extends NullJoinProperties {
277  public function __construct(
278  protected Operator $operator,
279  protected array $clauses
280  ) {
281  }
282 
283  public function operator(): Operator
284  {
285  return $this->operator;
286  }
287 
288  public function subClauses(): \Generator
289  {
290  yield from $this->clauses;
291  }
292  };
293  }
294  };
295  }
296 
297  protected function getFilter(
298  int|Placeholder $obj_id,
299  int|Placeholder $sub_id,
300  string|Placeholder $type
301  ): FilterInterface {
302  return new class ($obj_id, $sub_id, $type) extends NullFilter {
303  public function __construct(
304  protected int|Placeholder $obj_id,
305  protected int|Placeholder $sub_id,
306  protected string|Placeholder $type
307  ) {
308  }
309 
310  public function objID(): int|Placeholder
311  {
312  return $this->obj_id;
313  }
314 
315  public function subID(): int|Placeholder
316  {
317  return $this->sub_id;
318  }
319 
320  public function type(): string|Placeholder
321  {
322  return $this->type;
323  }
324  };
325  }
326 
327  public function testSearchWithNoResults(): void
328  {
329  $searcher = $this->getDatabaseSearcher([]);
330  $clause = $this->getBasicClause(
331  false,
332  'path',
333  Mode::EQUALS,
334  'value',
335  false
336  );
337 
338  $result = $searcher->search($clause, null, null);
339  $this->assertNull($result->current());
340  }
341 
342  public function testSearchWithResults(): void
343  {
344  $searcher = $this->getDatabaseSearcher(self::RESULT);
345  $clause = $this->getBasicClause(
346  false,
347  'path',
348  Mode::EQUALS,
349  'value',
350  false
351  );
352 
353  $result = $searcher->search($clause, null, null);
354  $this->assertTrue(
355  $this->mockRessourceIDsMatchArrayData(self::RESULT, ...$result)
356  );
357  }
358 
359  public function testSearchWithBasicClauseModeEquals(): void
360  {
361  $searcher = $this->getDatabaseSearcher(self::RESULT);
362  $clause = $this->getBasicClause(
363  false,
364  'path',
365  Mode::EQUALS,
366  'value',
367  false
368  );
369 
370  $result = iterator_to_array($searcher->search($clause, null, null));
371  $this->assertSame(
372  'selected paths:[path] GROUP BY ~identifier:base_table~.rbac_id, ' .
373  '~identifier:base_table~.obj_id, ~identifier:base_table~.obj_type ' .
374  'HAVING COUNT(CASE WHEN path_column = ~text:value~ THEN 1 END) > 0 ' .
375  'ORDER BY rbac_id, obj_id, obj_type',
376  $searcher->exposed_last_query
377  );
378  }
379 
381  {
382  $searcher = $this->getDatabaseSearcher(self::RESULT);
383  $clause = $this->getBasicClause(
384  false,
385  'path',
386  Mode::CONTAINS,
387  'value',
388  false
389  );
390 
391  $result = iterator_to_array($searcher->search($clause, null, null));
392  $this->assertSame(
393  'selected paths:[path] GROUP BY ~identifier:base_table~.rbac_id, ' .
394  '~identifier:base_table~.obj_id, ~identifier:base_table~.obj_type ' .
395  'HAVING COUNT(CASE WHEN path_column LIKE ~text:%value%~ THEN 1 END) > 0 ' .
396  'ORDER BY rbac_id, obj_id, obj_type',
397  $searcher->exposed_last_query
398  );
399  }
400 
402  {
403  $searcher = $this->getDatabaseSearcher(self::RESULT);
404  $clause = $this->getBasicClause(
405  false,
406  'path',
407  Mode::STARTS_WITH,
408  'value',
409  false
410  );
411 
412  $result = iterator_to_array($searcher->search($clause, null, null));
413  $this->assertSame(
414  'selected paths:[path] GROUP BY ~identifier:base_table~.rbac_id, ' .
415  '~identifier:base_table~.obj_id, ~identifier:base_table~.obj_type ' .
416  'HAVING COUNT(CASE WHEN path_column LIKE ~text:value%~ THEN 1 END) > 0 ' .
417  'ORDER BY rbac_id, obj_id, obj_type',
418  $searcher->exposed_last_query
419  );
420  }
421 
423  {
424  $searcher = $this->getDatabaseSearcher(self::RESULT);
425  $clause = $this->getBasicClause(
426  false,
427  'path',
429  'value',
430  false
431  );
432 
433  $result = iterator_to_array($searcher->search($clause, null, null));
434  $this->assertSame(
435  'selected paths:[path] GROUP BY ~identifier:base_table~.rbac_id, ' .
436  '~identifier:base_table~.obj_id, ~identifier:base_table~.obj_type ' .
437  'HAVING COUNT(CASE WHEN path_column LIKE ~text:%value~ THEN 1 END) > 0 ' .
438  'ORDER BY rbac_id, obj_id, obj_type',
439  $searcher->exposed_last_query
440  );
441  }
442 
443  public function testSearchWithBasicClauseNegatedMode(): void
444  {
445  $searcher = $this->getDatabaseSearcher(self::RESULT);
446  $clause = $this->getBasicClause(
447  false,
448  'path',
449  Mode::EQUALS,
450  'value',
451  true
452  );
453 
454  $result = iterator_to_array($searcher->search($clause, null, null));
455  $this->assertSame(
456  'selected paths:[path] GROUP BY ~identifier:base_table~.rbac_id, ' .
457  '~identifier:base_table~.obj_id, ~identifier:base_table~.obj_type ' .
458  'HAVING COUNT(CASE WHEN NOT path_column = ~text:value~ THEN 1 END) > 0 ' .
459  'ORDER BY rbac_id, obj_id, obj_type',
460  $searcher->exposed_last_query
461  );
462  }
463 
464  public function testSearchWithNegatedBasicClause(): void
465  {
466  $searcher = $this->getDatabaseSearcher(self::RESULT);
467  $clause = $this->getBasicClause(
468  true,
469  'path',
470  Mode::EQUALS,
471  'value',
472  false
473  );
474 
475  $result = iterator_to_array($searcher->search($clause, null, null));
476  $this->assertSame(
477  'selected paths (join forced):[path] GROUP BY ~identifier:base_table~.rbac_id, ' .
478  '~identifier:base_table~.obj_id, ~identifier:base_table~.obj_type ' .
479  'HAVING NOT COUNT(CASE WHEN path_column = ~text:value~ THEN 1 END) > 0 ' .
480  'ORDER BY rbac_id, obj_id, obj_type',
481  $searcher->exposed_last_query
482  );
483  }
484 
485 
486 
487  public function testSearchWithEmptyValueBasicClause(): void
488  {
489  $searcher = $this->getDatabaseSearcher(self::RESULT);
490  $clause = $this->getBasicClause(
491  false,
492  'path',
493  Mode::EQUALS,
494  '',
495  false
496  );
497 
498  $result = iterator_to_array($searcher->search($clause, null, null));
499  $this->assertSame(
500  'selected paths (join forced):[path] GROUP BY ~identifier:base_table~.rbac_id, ' .
501  '~identifier:base_table~.obj_id, ~identifier:base_table~.obj_type ' .
502  'HAVING COUNT(CASE WHEN path_column = ~text:~ THEN 1 END) > 0 ' .
503  'ORDER BY rbac_id, obj_id, obj_type',
504  $searcher->exposed_last_query
505  );
506  }
507 
508  public function testSearchWithORJoinedClauses(): void
509  {
510  $searcher = $this->getDatabaseSearcher(self::RESULT);
511  $clause1 = $this->getBasicClause(
512  false,
513  'path1',
514  Mode::EQUALS,
515  'value1',
516  false
517  );
518  $clause2 = $this->getBasicClause(
519  false,
520  'path2',
521  Mode::STARTS_WITH,
522  'value2',
523  false
524  );
525  $joined_clause = $this->getJoinedClause(false, Operator::OR, $clause1, $clause2);
526 
527  $result = iterator_to_array($searcher->search($joined_clause, null, null));
528  $this->assertSame(
529  'selected paths:[path1~path2] GROUP BY ~identifier:base_table~.rbac_id, ' .
530  '~identifier:base_table~.obj_id, ~identifier:base_table~.obj_type ' .
531  'HAVING (COUNT(CASE WHEN path1_column = ~text:value1~ THEN 1 END) > 0 ' .
532  'OR COUNT(CASE WHEN path2_column LIKE ~text:value2%~ THEN 1 END) > 0) ' .
533  'ORDER BY rbac_id, obj_id, obj_type',
534  $searcher->exposed_last_query
535  );
536  }
537 
538  public function testSearchWithANDJoinedClauses(): void
539  {
540  $searcher = $this->getDatabaseSearcher(self::RESULT);
541  $clause1 = $this->getBasicClause(
542  false,
543  'path1',
544  Mode::CONTAINS,
545  'value1',
546  false
547  );
548  $clause2 = $this->getBasicClause(
549  false,
550  'path2',
551  Mode::STARTS_WITH,
552  'value2',
553  false
554  );
555  $joined_clause = $this->getJoinedClause(false, Operator::AND, $clause1, $clause2);
556 
557  $result = iterator_to_array($searcher->search($joined_clause, null, null));
558  $this->assertSame(
559  'selected paths:[path1~path2] GROUP BY ~identifier:base_table~.rbac_id, ' .
560  '~identifier:base_table~.obj_id, ~identifier:base_table~.obj_type ' .
561  'HAVING (COUNT(CASE WHEN path1_column LIKE ~text:%value1%~ THEN 1 END) > 0 ' .
562  'AND COUNT(CASE WHEN path2_column LIKE ~text:value2%~ THEN 1 END) > 0) ' .
563  'ORDER BY rbac_id, obj_id, obj_type',
564  $searcher->exposed_last_query
565  );
566  }
567 
568  public function testSearchWithNegatedJoinedClause(): void
569  {
570  $searcher = $this->getDatabaseSearcher(self::RESULT);
571  $clause1 = $this->getBasicClause(
572  false,
573  'path1',
574  Mode::CONTAINS,
575  'value1',
576  false
577  );
578  $clause2 = $this->getBasicClause(
579  false,
580  'path2',
581  Mode::EQUALS,
582  'value2',
583  false
584  );
585  $joined_clause = $this->getJoinedClause(true, Operator::AND, $clause1, $clause2);
586 
587  $result = iterator_to_array($searcher->search($joined_clause, null, null));
588  $this->assertSame(
589  'selected paths:[path1~path2] GROUP BY ~identifier:base_table~.rbac_id, ' .
590  '~identifier:base_table~.obj_id, ~identifier:base_table~.obj_type ' .
591  'HAVING NOT (COUNT(CASE WHEN path1_column LIKE ~text:%value1%~ THEN 1 END) > 0 ' .
592  'AND COUNT(CASE WHEN path2_column = ~text:value2~ THEN 1 END) > 0) ' .
593  'ORDER BY rbac_id, obj_id, obj_type',
594  $searcher->exposed_last_query
595  );
596  }
597 
598  public function testSearchWithNestedJoinedClauses(): void
599  {
600  $searcher = $this->getDatabaseSearcher(self::RESULT);
601  $clause1 = $this->getBasicClause(
602  false,
603  'path1',
604  Mode::CONTAINS,
605  'value1',
606  false
607  );
608  $clause2 = $this->getBasicClause(
609  false,
610  'path2',
611  Mode::EQUALS,
612  'value2',
613  false
614  );
615  $clause3 = $this->getBasicClause(
616  false,
617  'path3',
619  'value3',
620  false
621  );
622  $joined_clause = $this->getJoinedClause(
623  false,
624  Operator::AND,
625  $clause1,
626  $this->getJoinedClause(
627  true,
628  Operator::OR,
629  $clause2,
630  $clause3
631  )
632  );
633 
634  $result = iterator_to_array($searcher->search($joined_clause, null, null));
635  $this->assertSame(
636  'selected paths:[path1~path2~path3] GROUP BY ~identifier:base_table~.rbac_id, ' .
637  '~identifier:base_table~.obj_id, ~identifier:base_table~.obj_type ' .
638  'HAVING (COUNT(CASE WHEN path1_column LIKE ~text:%value1%~ THEN 1 END) > 0 ' .
639  'AND NOT (COUNT(CASE WHEN path2_column = ~text:value2~ THEN 1 END) > 0 OR ' .
640  'COUNT(CASE WHEN path3_column LIKE ~text:%value3~ THEN 1 END) > 0)) ' .
641  'ORDER BY rbac_id, obj_id, obj_type',
642  $searcher->exposed_last_query
643  );
644  }
645 
646  public function testSearchWithLimit(): void
647  {
648  $searcher = $this->getDatabaseSearcher(self::RESULT);
649  $clause = $this->getBasicClause(
650  false,
651  'path',
652  Mode::EQUALS,
653  'value',
654  false
655  );
656 
657  $result = iterator_to_array($searcher->search($clause, 37, null));
658  $this->assertSame(
659  'selected paths:[path] GROUP BY ~identifier:base_table~.rbac_id, ' .
660  '~identifier:base_table~.obj_id, ~identifier:base_table~.obj_type ' .
661  'HAVING COUNT(CASE WHEN path_column = ~text:value~ THEN 1 END) > 0 ' .
662  'ORDER BY rbac_id, obj_id, obj_type LIMIT ~int:37~',
663  $searcher->exposed_last_query
664  );
665  }
666 
667  public function testSearchWithOffset(): void
668  {
669  $searcher = $this->getDatabaseSearcher(self::RESULT);
670  $clause = $this->getBasicClause(
671  false,
672  'path',
673  Mode::EQUALS,
674  'value',
675  false
676  );
677 
678  $result = iterator_to_array($searcher->search($clause, null, 16));
679  $this->assertSame(
680  'selected paths:[path] GROUP BY ~identifier:base_table~.rbac_id, ' .
681  '~identifier:base_table~.obj_id, ~identifier:base_table~.obj_type ' .
682  'HAVING COUNT(CASE WHEN path_column = ~text:value~ THEN 1 END) > 0 ' .
683  'ORDER BY rbac_id, obj_id, obj_type LIMIT ~int:' . PHP_INT_MAX . '~ OFFSET ~int:16~',
684  $searcher->exposed_last_query
685  );
686  }
687 
688  public function testSearchWithLimitAndOffset(): void
689  {
690  $searcher = $this->getDatabaseSearcher(self::RESULT);
691  $clause = $this->getBasicClause(
692  false,
693  'path',
694  Mode::EQUALS,
695  'value',
696  false
697  );
698 
699  $result = iterator_to_array($searcher->search($clause, 37, 16));
700  $this->assertSame(
701  'selected paths:[path] GROUP BY ~identifier:base_table~.rbac_id, ' .
702  '~identifier:base_table~.obj_id, ~identifier:base_table~.obj_type ' .
703  'HAVING COUNT(CASE WHEN path_column = ~text:value~ THEN 1 END) > 0 ' .
704  'ORDER BY rbac_id, obj_id, obj_type LIMIT ~int:37~ OFFSET ~int:16~',
705  $searcher->exposed_last_query
706  );
707  }
708 
709  public function testSearchWithEmptyFilter(): void
710  {
711  $searcher = $this->getDatabaseSearcher(self::RESULT);
712  $clause = $this->getBasicClause(
713  false,
714  'path',
715  Mode::EQUALS,
716  'value',
717  false
718  );
720 
721  $result = iterator_to_array($searcher->search($clause, null, null, $filter));
722  $this->assertSame(
723  'selected paths:[path] GROUP BY ~identifier:base_table~.rbac_id, ' .
724  '~identifier:base_table~.obj_id, ~identifier:base_table~.obj_type ' .
725  'HAVING COUNT(CASE WHEN path_column = ~text:value~ THEN 1 END) > 0 ' .
726  'ORDER BY rbac_id, obj_id, obj_type',
727  $searcher->exposed_last_query
728  );
729  }
730 
731  public function testSearchWithSingleValueObjIDFilter(): void
732  {
733  $searcher = $this->getDatabaseSearcher(self::RESULT);
734  $clause = $this->getBasicClause(
735  false,
736  'path',
737  Mode::EQUALS,
738  'value',
739  false
740  );
741  $filter = $this->getFilter(37, Placeholder::ANY, Placeholder::ANY);
742 
743  $result = iterator_to_array($searcher->search($clause, null, null, $filter));
744  $this->assertSame(
745  'selected paths:[path] GROUP BY ~identifier:base_table~.rbac_id, ' .
746  '~identifier:base_table~.obj_id, ~identifier:base_table~.obj_type ' .
747  'HAVING COUNT(CASE WHEN path_column = ~text:value~ THEN 1 END) > 0 ' .
748  'AND ((~identifier:base_table~.rbac_id = ~int:37~)) ' .
749  'ORDER BY rbac_id, obj_id, obj_type',
750  $searcher->exposed_last_query
751  );
752  }
753 
754  public function testSearchWithSingleValueSubIDFilter(): void
755  {
756  $searcher = $this->getDatabaseSearcher(self::RESULT);
757  $clause = $this->getBasicClause(
758  false,
759  'path',
760  Mode::EQUALS,
761  'value',
762  false
763  );
764  $filter = $this->getFilter(Placeholder::ANY, 15, Placeholder::ANY);
765 
766  $result = iterator_to_array($searcher->search($clause, null, null, $filter));
767  $this->assertSame(
768  'selected paths:[path] GROUP BY ~identifier:base_table~.rbac_id, ' .
769  '~identifier:base_table~.obj_id, ~identifier:base_table~.obj_type ' .
770  'HAVING COUNT(CASE WHEN path_column = ~text:value~ THEN 1 END) > 0 ' .
771  'AND ((~identifier:base_table~.obj_id = ~int:15~)) ' .
772  'ORDER BY rbac_id, obj_id, obj_type',
773  $searcher->exposed_last_query
774  );
775  }
776 
777  public function testSearchWithSingleValueTypeFilter(): void
778  {
779  $searcher = $this->getDatabaseSearcher(self::RESULT);
780  $clause = $this->getBasicClause(
781  false,
782  'path',
783  Mode::EQUALS,
784  'value',
785  false
786  );
787  $filter = $this->getFilter(Placeholder::ANY, Placeholder::ANY, 'some type');
788 
789  $result = iterator_to_array($searcher->search($clause, null, null, $filter));
790  $this->assertSame(
791  'selected paths:[path] GROUP BY ~identifier:base_table~.rbac_id, ' .
792  '~identifier:base_table~.obj_id, ~identifier:base_table~.obj_type ' .
793  'HAVING COUNT(CASE WHEN path_column = ~text:value~ THEN 1 END) > 0 ' .
794  'AND ((~identifier:base_table~.obj_type = ~text:some type~)) ' .
795  'ORDER BY rbac_id, obj_id, obj_type',
796  $searcher->exposed_last_query
797  );
798  }
799 
800  public function testSearchWithMultiValueFilter(): void
801  {
802  $searcher = $this->getDatabaseSearcher(self::RESULT);
803  $clause = $this->getBasicClause(
804  false,
805  'path',
806  Mode::EQUALS,
807  'value',
808  false
809  );
810  $filter = $this->getFilter(37, 15, 'some type');
811 
812  $result = iterator_to_array($searcher->search($clause, null, null, $filter));
813  $this->assertSame(
814  'selected paths:[path] GROUP BY ~identifier:base_table~.rbac_id, ' .
815  '~identifier:base_table~.obj_id, ~identifier:base_table~.obj_type ' .
816  'HAVING COUNT(CASE WHEN path_column = ~text:value~ THEN 1 END) > 0 ' .
817  'AND ((~identifier:base_table~.rbac_id = ~int:37~ AND ' .
818  '~identifier:base_table~.obj_id = ~int:15~ AND ' .
819  '~identifier:base_table~.obj_type = ~text:some type~)) ' .
820  'ORDER BY rbac_id, obj_id, obj_type',
821  $searcher->exposed_last_query
822  );
823  }
824 
825  public function testSearchWithMultipleFilters(): void
826  {
827  $searcher = $this->getDatabaseSearcher(self::RESULT);
828  $clause = $this->getBasicClause(
829  false,
830  'path',
831  Mode::EQUALS,
832  'value',
833  false
834  );
835  $filter1 = $this->getFilter(37, 15, Placeholder::ANY);
836  $filter2 = $this->getFilter(Placeholder::ANY, 15, 'some type');
837  $filter3 = $this->getFilter(37, Placeholder::ANY, 'some type');
838 
839  $result = iterator_to_array($searcher->search(
840  $clause,
841  null,
842  null,
843  $filter1,
844  $filter2,
845  $filter3
846  ));
847  $this->assertSame(
848  'selected paths:[path] GROUP BY ~identifier:base_table~.rbac_id, ' .
849  '~identifier:base_table~.obj_id, ~identifier:base_table~.obj_type ' .
850  'HAVING COUNT(CASE WHEN path_column = ~text:value~ THEN 1 END) > 0 ' .
851  'AND ((~identifier:base_table~.rbac_id = ~int:37~ AND ~identifier:base_table~.obj_id = ~int:15~) ' .
852  'OR (~identifier:base_table~.obj_id = ~int:15~ AND ~identifier:base_table~.obj_type = ~text:some type~) ' .
853  'OR (~identifier:base_table~.rbac_id = ~int:37~ AND ~identifier:base_table~.obj_type = ~text:some type~)) ' .
854  'ORDER BY rbac_id, obj_id, obj_type',
855  $searcher->exposed_last_query
856  );
857  }
858 
859  public function testSearchWithObjIDPlaceholderFilter(): void
860  {
861  $searcher = $this->getDatabaseSearcher(self::RESULT);
862  $clause = $this->getBasicClause(
863  false,
864  'path',
865  Mode::EQUALS,
866  'value',
867  false
868  );
869  $filter = $this->getFilter(Placeholder::ANY, Placeholder::OBJ_ID, Placeholder::ANY);
870 
871  $result = iterator_to_array($searcher->search($clause, null, null, $filter));
872  $this->assertSame(
873  'selected paths:[path] GROUP BY ~identifier:base_table~.rbac_id, ' .
874  '~identifier:base_table~.obj_id, ~identifier:base_table~.obj_type ' .
875  'HAVING COUNT(CASE WHEN path_column = ~text:value~ THEN 1 END) > 0 ' .
876  'AND ((~identifier:base_table~.obj_id = ~identifier:base_table~.rbac_id)) ' .
877  'ORDER BY rbac_id, obj_id, obj_type',
878  $searcher->exposed_last_query
879  );
880  }
881 
882  public function testSearchWithSubIDPlaceholderFilter(): void
883  {
884  $searcher = $this->getDatabaseSearcher(self::RESULT);
885  $clause = $this->getBasicClause(
886  false,
887  'path',
888  Mode::EQUALS,
889  'value',
890  false
891  );
892  $filter = $this->getFilter(Placeholder::SUB_ID, Placeholder::ANY, Placeholder::ANY);
893 
894  $result = iterator_to_array($searcher->search($clause, null, null, $filter));
895  $this->assertSame(
896  'selected paths:[path] GROUP BY ~identifier:base_table~.rbac_id, ' .
897  '~identifier:base_table~.obj_id, ~identifier:base_table~.obj_type ' .
898  'HAVING COUNT(CASE WHEN path_column = ~text:value~ THEN 1 END) > 0 ' .
899  'AND ((~identifier:base_table~.rbac_id = ~identifier:base_table~.obj_id)) ' .
900  'ORDER BY rbac_id, obj_id, obj_type',
901  $searcher->exposed_last_query
902  );
903  }
904 
905  public function testSearchWithTypePlaceholderFilter(): void
906  {
907  $searcher = $this->getDatabaseSearcher(self::RESULT);
908  $clause = $this->getBasicClause(
909  false,
910  'path',
911  Mode::EQUALS,
912  'value',
913  false
914  );
915  $filter = $this->getFilter(Placeholder::TYPE, Placeholder::ANY, Placeholder::ANY);
916 
917  $result = iterator_to_array($searcher->search($clause, null, null, $filter));
918  $this->assertSame(
919  'selected paths:[path] GROUP BY ~identifier:base_table~.rbac_id, ' .
920  '~identifier:base_table~.obj_id, ~identifier:base_table~.obj_type ' .
921  'HAVING COUNT(CASE WHEN path_column = ~text:value~ THEN 1 END) > 0 ' .
922  'AND ((~identifier:base_table~.rbac_id = ~identifier:base_table~.obj_type)) ' .
923  'ORDER BY rbac_id, obj_id, obj_type',
924  $searcher->exposed_last_query
925  );
926  }
927 }
getJoinedClause(bool $negated, Operator $operator, ClauseInterface ... $clauses)
getBasicClause(bool $negated, string $path, Mode $mode, string $value, bool $mode_negated)
getFilter(int|Placeholder $obj_id, int|Placeholder $sub_id, string|Placeholder $type)
$path
Definition: ltiservices.php:29
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
__construct()
Constructor setup ILIAS global object public.
Definition: class.ilias.php:76
const array mockRessourceIDsMatchArrayData(array $array, RessourceIDInterface ... $ressource_ids)