diff --git a/docs/en/reference/annotations-reference.rst b/docs/en/reference/annotations-reference.rst index 87ff27968b..7181a73c24 100644 --- a/docs/en/reference/annotations-reference.rst +++ b/docs/en/reference/annotations-reference.rst @@ -526,7 +526,8 @@ Optional attributes: respectively. Special index types (e.g. ``2dsphere``) should be specified as strings. This is required when `@Index`_ is used at the class level. - - ``options`` - Options for creating the index + ``options`` - Options for creating the index. Options are documented in the + :ref:`indexes chapter `. The ``keys`` and ``options`` attributes correspond to the arguments for `MongoCollection::createIndex() `_. @@ -559,6 +560,15 @@ If you are creating a single-field index, you can simply specify an `@Index`_ or /** @Field(type="string") @UniqueIndex */ private $username; +.. note:: + + If the ``name`` option is specified on an index in an embedded document, it + will be prefixed with the embedded field path before creating the index. + This is necessary to avoid index name conflict when the same document is + embedded multiple times in a single collection. Prefixing of the index name + can cause errors due to excessive index name length. In this case, try + shortening the index name or embedded field path. + @Indexes -------- diff --git a/docs/en/reference/indexes.rst b/docs/en/reference/indexes.rst index 35aebcec4d..064913ad70 100644 --- a/docs/en/reference/indexes.rst +++ b/docs/en/reference/indexes.rst @@ -284,6 +284,15 @@ Also, for your convenience you can create the indexes for your mapped documents unless you specify a discriminator map for the :ref:`embed-one ` or :ref:`embed-many ` relationship. +.. note:: + + If the ``name`` option is specified on an index in an embedded document, it + will be prefixed with the embedded field path before creating the index. + This is necessary to avoid index name conflict when the same document is + embedded multiple times in a single collection. Prefixing of the index name + can cause errors due to excessive index name length. In this case, try + shortening the index name or embedded field path. + Geospatial Indexing ------------------- diff --git a/lib/Doctrine/ODM/MongoDB/SchemaManager.php b/lib/Doctrine/ODM/MongoDB/SchemaManager.php index 4fe5f0c325..8f0475ab15 100644 --- a/lib/Doctrine/ODM/MongoDB/SchemaManager.php +++ b/lib/Doctrine/ODM/MongoDB/SchemaManager.php @@ -18,6 +18,7 @@ use function iterator_count; use function iterator_to_array; use function ksort; +use function sprintf; class SchemaManager { @@ -166,6 +167,10 @@ private function doGetDocumentIndexes(string $documentName, array &$visited) : a unset($embeddedIndex['keys'][$key]); } + if (isset($embeddedIndex['options']['name'])) { + $embeddedIndex['options']['name'] = sprintf('%s_%s', $fieldMapping['name'], $embeddedIndex['options']['name']); + } + $indexes[] = $embeddedIndex; } } diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Functional/EnsureShardingTest.php b/tests/Doctrine/ODM/MongoDB/Tests/Functional/EnsureShardingTest.php index 5b17cd7759..704c99f114 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/Functional/EnsureShardingTest.php +++ b/tests/Doctrine/ODM/MongoDB/Tests/Functional/EnsureShardingTest.php @@ -11,6 +11,9 @@ use Documents\Sharded\ShardedOneWithDifferentKey; use function iterator_to_array; +/** + * @group sharding + */ class EnsureShardingTest extends BaseTest { public function setUp() diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Functional/ShardKeyTest.php b/tests/Doctrine/ODM/MongoDB/Tests/Functional/ShardKeyTest.php index a9b05b4a6f..6228c354bb 100644 --- a/tests/Doctrine/ODM/MongoDB/Tests/Functional/ShardKeyTest.php +++ b/tests/Doctrine/ODM/MongoDB/Tests/Functional/ShardKeyTest.php @@ -11,6 +11,9 @@ use function end; use function get_class; +/** + * @group sharding + */ class ShardKeyTest extends BaseTest { /** @var CommandLogger */ diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Functional/Ticket/GH1344Test.php b/tests/Doctrine/ODM/MongoDB/Tests/Functional/Ticket/GH1344Test.php new file mode 100644 index 0000000000..d4f27affdd --- /dev/null +++ b/tests/Doctrine/ODM/MongoDB/Tests/Functional/Ticket/GH1344Test.php @@ -0,0 +1,90 @@ +dm->getSchemaManager()->getDocumentIndexes(GH1344Main::class); + self::assertCount(4, $indexes); + self::assertSame('embedded1_embedded', $indexes[0]['options']['name']); + self::assertSame('embedded1_embedded_nested', $indexes[1]['options']['name']); + self::assertSame('embedded2_embedded', $indexes[2]['options']['name']); + self::assertSame('embedded2_embedded_nested', $indexes[3]['options']['name']); + + $this->dm->getSchemaManager()->ensureDocumentIndexes(GH1344Main::class); + } + + public function testGeneratingIndexesWithTooLongIndexNameThrowsException() + { + // Ensure that at least the beginning of the index name is contained in + // the exception message. This can vary between driver/server versions. + $this->expectException(CommandException::class); + $this->expectExceptionMessageRegExp('#GH1344TooLongIndexName.\$embedded1_this_is_a_really_long_name_that#'); + + $this->dm->getSchemaManager()->ensureDocumentIndexes(GH1344TooLongIndexName::class); + } +} + +/** @ODM\Document */ +class GH1344Main +{ + /** @ODM\Id */ + public $id; + + /** @ODM\EmbedOne(targetDocument=GH1344Embedded::class) */ + public $embedded1; + + /** @ODM\EmbedOne(targetDocument=GH1344Embedded::class) */ + public $embedded2; +} + +/** + * @ODM\EmbeddedDocument + * @ODM\Index(keys={"property"="asc"}, name="embedded") + */ +class GH1344Embedded +{ + /** @ODM\Field */ + public $property; + + /** @ODM\EmbedOne(targetDocument=GH1344EmbeddedNested::class) */ + public $embedded; +} + +/** + * @ODM\EmbeddedDocument + * @ODM\Index(keys={"property"="asc"}, name="nested") + */ +class GH1344EmbeddedNested +{ + /** @ODM\Field */ + public $property; +} + +/** @ODM\Document */ +class GH1344TooLongIndexName +{ + /** @ODM\Id */ + public $id; + + /** @ODM\EmbedOne(targetDocument=GH1344TooLongIndexNameEmbedded::class) */ + public $embedded1; +} + +/** + * @ODM\EmbeddedDocument + * @ODM\Index(keys={"property"="asc"}, name="this_is_a_really_long_name_that_will_cause_problems_for_whoever_tries_to_use_it_whether_in_an_embedded_field_or_not") + */ +class GH1344TooLongIndexNameEmbedded +{ + /** @ODM\Field */ + public $property; +}