diff --git a/src/TestSuite/Fixture/MappingGenerator.php b/src/TestSuite/Fixture/MappingGenerator.php index ee88416..4ba5e98 100644 --- a/src/TestSuite/Fixture/MappingGenerator.php +++ b/src/TestSuite/Fixture/MappingGenerator.php @@ -13,16 +13,38 @@ * Index definition files should return an array of indexes * to create. Each index in the array should follow the form of * + * Simple mapping (properties only): * ``` * [ * 'name' => 'articles', - * 'mapping' => [...], + * 'mapping' => [ + * 'title' => ['type' => 'text'], + * 'body' => ['type' => 'text'], + * ], + * 'settings' => [...], + * ] + * ``` + * + * Full mapping structure (with dynamic_templates, etc.): + * ``` + * [ + * 'name' => 'articles', + * 'mapping' => [ + * 'properties' => [ + * 'title' => ['type' => 'text'], + * 'body' => ['type' => 'text'], + * ], + * 'dynamic_templates' => [...], + * 'dynamic' => 'strict', + * ], * 'settings' => [...], * ] * ``` * * The `mapping` key should be compatible with Elasticsearch's - * mapping API and Elastica. + * mapping API and Elastica. If the mapping contains a 'properties' + * key, it will be treated as a full mapping structure. Otherwise, + * it will be wrapped in a 'properties' key for backward compatibility. * * The `settings` key can contain Elastica compatible index creation * settings. @@ -103,6 +125,12 @@ protected function dropIndex(Connection $db, string $name): void /** * Create an index. * + * Supports two mapping formats: + * - Simple: Direct property definitions (wrapped in 'properties' automatically) + * - Full: Complete mapping structure including 'properties', 'dynamic_templates', etc. + * + * The format is detected by checking if the mapping contains a 'properties' key. + * * @param \Cake\ElasticSearch\Datasource\Connection $db The connection. * @param array $mapping The index mapping and settings. */ @@ -119,11 +147,17 @@ protected function createIndex(Connection $db, array $mapping): void $args['settings'] = $mapping['settings']; } - // In Elastica, mappings should be included in index creation + // Detect if this is a full mapping structure or simple properties if (!empty($mapping['mapping'])) { - $args['mappings'] = [ - 'properties' => $mapping['mapping'], - ]; + if (isset($mapping['mapping']['properties'])) { + // Full mapping structure - use as-is to support dynamic_templates, etc. + $args['mappings'] = $mapping['mapping']; + } else { + // Simple properties only - wrap for backward compatibility + $args['mappings'] = [ + 'properties' => $mapping['mapping'], + ]; + } } $response = $esIndex->create($args); diff --git a/tests/TestCase/TestSuite/Fixture/MappingGeneratorTest.php b/tests/TestCase/TestSuite/Fixture/MappingGeneratorTest.php index bad6773..9987888 100644 --- a/tests/TestCase/TestSuite/Fixture/MappingGeneratorTest.php +++ b/tests/TestCase/TestSuite/Fixture/MappingGeneratorTest.php @@ -332,6 +332,172 @@ public function testReloadWithSettings(): void unlink($file); } + /** + * Test simple mapping format (backward compatibility) + */ + public function testSimpleMappingFormat(): void + { + $file = $this->createMappingFile([ + [ + 'name' => 'test_index_1', + 'mapping' => [ + 'id' => ['type' => 'integer'], + 'title' => ['type' => 'text'], + 'body' => ['type' => 'text'], + ], + ], + ]); + + $generator = new MappingGenerator($file, 'test'); + $generator->reload(['test_index_1']); + + $index = $this->connection->getIndex('test_index_1'); + $this->assertTrue($index->exists()); + + // Verify mapping was created correctly + $mapping = $index->getMapping(); + $this->assertNotEmpty($mapping); + $this->assertArrayHasKey('properties', $mapping); + + $properties = $mapping['properties']; + $this->assertArrayHasKey('id', $properties); + $this->assertArrayHasKey('title', $properties); + $this->assertArrayHasKey('body', $properties); + + unlink($file); + } + + /** + * Test full mapping format with properties key + */ + public function testFullMappingFormatWithProperties(): void + { + $file = $this->createMappingFile([ + [ + 'name' => 'test_index_1', + 'mapping' => [ + 'properties' => [ + 'id' => ['type' => 'integer'], + 'title' => ['type' => 'text'], + 'body' => ['type' => 'text'], + ], + ], + ], + ]); + + $generator = new MappingGenerator($file, 'test'); + $generator->reload(['test_index_1']); + + $index = $this->connection->getIndex('test_index_1'); + $this->assertTrue($index->exists()); + + // Verify mapping was created correctly + $mapping = $index->getMapping(); + $this->assertNotEmpty($mapping); + $this->assertArrayHasKey('properties', $mapping); + + $properties = $mapping['properties']; + $this->assertArrayHasKey('id', $properties); + $this->assertArrayHasKey('title', $properties); + $this->assertArrayHasKey('body', $properties); + + unlink($file); + } + + /** + * Test full mapping format with dynamic_templates + */ + public function testFullMappingFormatWithDynamicTemplates(): void + { + $file = $this->createMappingFile([ + [ + 'name' => 'test_index_1', + 'mapping' => [ + 'properties' => [ + 'id' => ['type' => 'integer'], + 'title' => ['type' => 'text'], + ], + 'dynamic_templates' => [ + [ + 'strings_as_keywords' => [ + 'match_mapping_type' => 'string', + 'mapping' => [ + 'type' => 'keyword', + ], + ], + ], + ], + ], + ], + ]); + + $generator = new MappingGenerator($file, 'test'); + $generator->reload(['test_index_1']); + + $index = $this->connection->getIndex('test_index_1'); + $this->assertTrue($index->exists()); + + // Verify mapping was created with dynamic_templates + $mapping = $index->getMapping(); + $this->assertNotEmpty($mapping); + $this->assertArrayHasKey('properties', $mapping); + $this->assertArrayHasKey('dynamic_templates', $mapping); + + $dynamicTemplates = $mapping['dynamic_templates']; + $this->assertCount(1, $dynamicTemplates); + $this->assertArrayHasKey('strings_as_keywords', $dynamicTemplates[0]); + + unlink($file); + } + + /** + * Test mixing simple and full mapping formats in same file + */ + public function testMixedMappingFormats(): void + { + $file = $this->createMappingFile([ + [ + 'name' => 'test_index_1', + 'mapping' => [ + 'id' => ['type' => 'integer'], + 'title' => ['type' => 'text'], + ], + ], + [ + 'name' => 'test_index_2', + 'mapping' => [ + 'properties' => [ + 'id' => ['type' => 'integer'], + 'name' => ['type' => 'text'], + ], + 'dynamic' => 'strict', + ], + ], + ]); + + $generator = new MappingGenerator($file, 'test'); + $generator->reload(); + + $index1 = $this->connection->getIndex('test_index_1'); + $index2 = $this->connection->getIndex('test_index_2'); + + $this->assertTrue($index1->exists()); + $this->assertTrue($index2->exists()); + + // Verify both mappings were created correctly + $mapping1 = $index1->getMapping(); + $mapping2 = $index2->getMapping(); + + $this->assertNotEmpty($mapping1); + $this->assertNotEmpty($mapping2); + + $this->assertArrayHasKey('properties', $mapping1); + $this->assertArrayHasKey('properties', $mapping2); + $this->assertArrayHasKey('dynamic', $mapping2); + + unlink($file); + } + /** * Helper method to create a temporary mapping file *