diff --git a/lib/Service/Query/RelatedRowQueryApplier.php b/lib/Service/Query/RelatedRowQueryApplier.php index 9b707471d3..66f9cbe36a 100644 --- a/lib/Service/Query/RelatedRowQueryApplier.php +++ b/lib/Service/Query/RelatedRowQueryApplier.php @@ -111,6 +111,15 @@ public function apply(IQueryBuilder $qb, array $query, Register $register, strin foreach (array_values($filters) as $position => $filter) { $alias = sprintf('rel%d', $position); $schema = $this->resolveSchema(name: $filter->schema); + + // A schema that has never stored an object has no table yet, so no + // row can match. Same answer the list path gives for a missing table. + if ($this->tableHandler->existsTableForRegisterSchema(register: $register, schema: $schema) === false) { + $qb->andWhere($qb->createFunction('1 = 0')); + $applied++; + continue; + } + $rendered = $clause->render( filter: $filter, engine: $engine, diff --git a/tests/Unit/Service/Query/ReferencedRowFilterTest.php b/tests/Unit/Service/Query/ReferencedRowFilterTest.php index bedd8adfa1..f5e71a361b 100644 --- a/tests/Unit/Service/Query/ReferencedRowFilterTest.php +++ b/tests/Unit/Service/Query/ReferencedRowFilterTest.php @@ -131,6 +131,7 @@ public function testTheApplierAddsForwardBlocksWithTheReferencedSchemasOwnAccess $tableHandler = $this->createMock(MagicTableHandler::class); $tableHandler->method('getTableNameForRegisterSchema')->willReturn('oc_openregister_table_1_7'); + $tableHandler->method('existsTableForRegisterSchema')->willReturn(true); $rbac = $this->createMock(MagicRbacHandler::class); $rbac->expects($this->once())->method('buildRbacPredicateForAlias') diff --git a/tests/Unit/Service/Query/RelatedRowQueryApplierTest.php b/tests/Unit/Service/Query/RelatedRowQueryApplierTest.php index fdfdac6007..2e14f713fa 100644 --- a/tests/Unit/Service/Query/RelatedRowQueryApplierTest.php +++ b/tests/Unit/Service/Query/RelatedRowQueryApplierTest.php @@ -53,16 +53,18 @@ class RelatedRowQueryApplierTest extends TestCase { /** * Build an applier whose schema lookup returns the given rows. * - * @param array $found What findBySlug returns. + * @param array $found What findBySlug returns. + * @param bool $tableExists Whether the related schema's table exists. * * @return RelatedRowQueryApplier The applier. */ - private function applierFinding(array $found): RelatedRowQueryApplier { + private function applierFinding(array $found, bool $tableExists=true): RelatedRowQueryApplier { $schemaMapper = $this->createMock(SchemaMapper::class); $schemaMapper->method('findBySlug')->willReturn($found); $tableHandler = $this->createMock(MagicTableHandler::class); $tableHandler->method('getTableNameForRegisterSchema')->willReturn('oc_openregister_table_1_2'); + $tableHandler->method('existsTableForRegisterSchema')->willReturn($tableExists); $rbac = $this->createMock(MagicRbacHandler::class); $rbac->method('buildRbacPredicateForAlias')->willReturn('rel0._owner = \'alice\''); @@ -229,4 +231,41 @@ public function testTheRegisterMayComeFromTheQueryItself(): void { $this->assertSame(1, $applied); }//end testTheRegisterMayComeFromTheQueryItself() + + /** + * 🔴 A REFERENCED SCHEMA WITHOUT A TABLE MATCHES NOTHING, IT DOES NOT FAIL. + * + * A schema that has never stored an object has no magic table. Rendering + * the subquery against it answered HTTP 500 (`relation does not exist`). + * No row can exist there, so the block narrows to the empty set. + * + * @return void + */ + public function testAReferencedSchemaWithoutATableMatchesNothing(): void { + $conditions = []; + $qb = $this->createMock(originalClassName: IQueryBuilder::class); + $qb->method('createFunction')->willReturnArgument(0); + $qb->expects($this->never())->method('setParameter'); + $qb->method('andWhere')->willReturnCallback( + function ($condition) use (&$conditions, $qb) { + $conditions[] = $condition; + return $qb; + } + ); + + $applied = $this->applierFinding(found: [$this->schema()], tableExists: false)->apply( + qb: $qb, + query: [ + '_referenced' => [ + 'subsidieAanvraag' => [ + 'subsidieaanvraag' => ['case' => '9eab0293-7ce5-4bcf-b7aa-0ab79a1eab4f'], + ], + ], + ], + register: $this->register() + ); + + $this->assertSame(expected: 1, actual: $applied); + $this->assertSame(expected: ['1 = 0'], actual: $conditions); + }//end testAReferencedSchemaWithoutATableMatchesNothing() }//end class