Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/en/reference/attributes-reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,10 @@ Optional parameters:
- **unique**: Boolean value to determine if the value of the column
should be unique across all rows of the underlying entities table.

- **index**: Boolean value to generate an index for this column.
For more advanced usages, take a look at :ref:`#[Index] <attrref_index>`.
If not specified, default value is ``false``.

- **nullable**: Determines if NULL values allowed for this column.
If not specified, default value is ``false``.

Expand Down Expand Up @@ -245,6 +249,9 @@ Examples:
#[Column(type: "string", length: 32, unique: true, nullable: false)]
protected $username;

#[Column(type: "string", index: true)]
protected $firstName;

#[Column(type: "string", columnDefinition: "CHAR(2) NOT NULL")]
protected $country;

Expand Down
1 change: 1 addition & 0 deletions docs/en/reference/php-mapping.rst
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ Field & Association Getters

- ``isUniqueField($fieldName)``
- ``isNullable($fieldName)``
- ``isIndexed($fieldName)``
- ``getColumnName($fieldName)``
- ``getFieldMapping($fieldName)``
- ``getAssociationMapping($fieldName)``
Expand Down
5 changes: 3 additions & 2 deletions docs/en/reference/xml-mapping.rst
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ of several common elements:

<indexes>
<index name="name_idx" columns="name"/>
<index columns="user_email"/>
</indexes>

<unique-constraints>
Expand All @@ -131,7 +130,7 @@ of several common elements:
</id>

<field name="name" column="name" type="string" length="50" nullable="true" unique="true" />
<field name="email" column="user_email" type="string" column-definition="CHAR(32) NOT NULL" />
<field name="email" column="user_email" type="string" index="true" column-definition="CHAR(32) NOT NULL" />

<one-to-one field="address" target-entity="Address" inversed-by="user">
<cascade><cascade-remove /></cascade>
Expand Down Expand Up @@ -255,6 +254,8 @@ Optional attributes:
only.
- unique - Should this field contain a unique value across the
table? Defaults to false.
- index - Should an index be created for this column? Defaults to
false.
- nullable - Should this field allow NULL as a value? Defaults to
false.
- insertable - Should this field be inserted? Defaults to true.
Expand Down
1 change: 1 addition & 0 deletions doctrine-mapping.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@
<xs:attribute name="length" type="xs:NMTOKEN" />
<xs:attribute name="unique" type="xs:boolean" default="false" />
<xs:attribute name="nullable" type="xs:boolean" default="false" />
<xs:attribute name="index" type="xs:boolean" default="false" />
<xs:attribute name="insertable" type="xs:boolean" default="true" />
<xs:attribute name="updatable" type="xs:boolean" default="true" />
<xs:attribute name="generated" type="orm:generated-type" default="NEVER" />
Expand Down
12 changes: 12 additions & 0 deletions src/Mapping/Builder/FieldBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,18 @@
return $this;
}

/**
* Sets indexed.
*
* @return $this
*/
public function index(bool $flag = true): static
{
$this->mapping['index'] = $flag;

return $this;
}

/**
* Sets column name.
*
Expand Down
7 changes: 7 additions & 0 deletions src/Mapping/ClassMetadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,13 @@
return $mapping !== false && isset($mapping->nullable) && $mapping->nullable;
}

public function isIndexed(string $fieldName): bool
{
$mapping = $this->getFieldMapping($fieldName);

return isset($mapping->index) && $mapping->index;
}

/**
* Gets a column name for a field name.
* If the column name for the field cannot be found, the given field name
Expand Down
1 change: 1 addition & 0 deletions src/Mapping/Column.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public function __construct(
public readonly array $options = [],
public readonly string|null $columnDefinition = null,
public readonly string|null $generated = null,
public readonly bool $index = false,
) {
}
}
2 changes: 2 additions & 0 deletions src/Mapping/Driver/AttributeDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,7 @@ private function joinColumnToArray(Mapping\JoinColumn|Mapping\InverseJoinColumn
* length: int,
* unique: bool,
* nullable: bool,
* index: bool,
* precision: int,
* enumType?: class-string,
* options?: mixed[],
Expand All @@ -726,6 +727,7 @@ private function columnToArray(string $fieldName, Mapping\Column $column): array
'length' => $column->length,
'unique' => $column->unique,
'nullable' => $column->nullable,
'index' => $column->index,
'precision' => $column->precision,
];

Expand Down
5 changes: 5 additions & 0 deletions src/Mapping/Driver/XmlDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,7 @@ private function joinColumnToArray(SimpleXMLElement $joinColumnElement): array
* scale?: int,
* unique?: bool,
* nullable?: bool,
* index?: bool,
* notInsertable?: bool,
* notUpdatable?: bool,
* enumType?: string,
Expand Down Expand Up @@ -792,6 +793,10 @@ private function columnToArray(SimpleXMLElement $fieldMapping): array
$mapping['unique'] = $this->evaluateBoolean($fieldMapping['unique']);
}

if (isset($fieldMapping['index'])) {
$mapping['index'] = $this->evaluateBoolean($fieldMapping['index']);
}

if (isset($fieldMapping['nullable'])) {
$mapping['nullable'] = $this->evaluateBoolean($fieldMapping['nullable']);
}
Expand Down
3 changes: 3 additions & 0 deletions src/Mapping/FieldMapping.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ final class FieldMapping implements ArrayAccess
public int|null $scale = null;
/** Whether a unique constraint should be generated for the column. */
public bool|null $unique = null;
/** Whether an index should be generated for the column. */
public bool|null $index = null;
/**
* @var class-string|null This is set when the field is inherited by this
* class from another (inheritance) parent <em>entity</em> class. The value
Expand Down Expand Up @@ -93,6 +95,7 @@ public function __construct(
* length?: int|null,
* id?: bool|null,
* nullable?: bool|null,
* index?: bool|null,
* notInsertable?: bool|null,
* notUpdatable?: bool|null,
* columnDefinition?: string|null,
Expand Down
5 changes: 5 additions & 0 deletions src/Tools/SchemaTool.php
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,11 @@ private function gatherColumn(
if ($isUnique) {
$table->addUniqueIndex([$columnName]);
}

$isIndex = $mapping->index ?? false;
if ($isIndex) {
$table->addIndex([$columnName]);
}
}

/**
Expand Down
65 changes: 65 additions & 0 deletions tests/Tests/ORM/Functional/Ticket/GH11982Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\ORM\Functional\Ticket;

use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Tests\OrmFunctionalTestCase;
use PHPUnit\Framework\Attributes\Group;

use function reset;

class GH11982Test extends OrmFunctionalTestCase
{
protected function setUp(): void
{
parent::setUp();

$this->setUpEntitySchema([
GH11982ColumnIndex::class,
]);
}

#[Group('GH-11982')]
public function testSchema(): void
{
if ($this->_em->getConnection()->getDatabasePlatform() instanceof PostgreSQLPlatform) {
self::markTestSkipped('This test does not work on psql.');
}

$indexes = $this->createSchemaManager()
->introspectTable('GH11982ColumnIndex')
->getIndexes();

self::assertCount(3, $indexes); // primary + 2 custom indexes
self::assertArrayHasKey('class_idx', $indexes);

unset($indexes['primary']);
unset($indexes['class_idx']);
$unnamedIndexColumns = reset($indexes)->getColumns();
self::assertCount(1, $unnamedIndexColumns);
self::assertEquals('indexTrue', $unnamedIndexColumns[0]);
}
}

#[ORM\Entity]
#[ORM\Index(
name: 'class_idx',
fields: ['classIndex'],
flags: ['test'],
options: ['test'],
)]
class GH11982ColumnIndex
{
#[ORM\Id]
#[ORM\Column]
public string $noIndex;

#[ORM\Column(index: true)]
public string $indexTrue;

#[ORM\Column]
public string $classIndex;
}
14 changes: 13 additions & 1 deletion tests/Tests/ORM/Mapping/MappingDriverTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -227,11 +227,12 @@ public function testEntityCustomGenerator(): void
#[Depends('testEntityTableNameAndInheritance')]
public function testFieldMappings(ClassMetadata $class): ClassMetadata
{
self::assertEquals(4, count($class->fieldMappings));
self::assertEquals(5, count($class->fieldMappings));
self::assertTrue(isset($class->fieldMappings['id']));
self::assertTrue(isset($class->fieldMappings['name']));
self::assertTrue(isset($class->fieldMappings['email']));
self::assertTrue(isset($class->fieldMappings['version']));
self::assertTrue(isset($class->fieldMappings['indexed']));

return $class;
}
Expand Down Expand Up @@ -262,6 +263,7 @@ public function testStringFieldMappings(ClassMetadata $class): ClassMetadata
self::assertEquals(50, $class->fieldMappings['name']->length);
self::assertTrue($class->fieldMappings['name']->nullable);
self::assertTrue($class->fieldMappings['name']->unique);
self::assertTrue($class->fieldMappings['indexed']->index);

return $class;
}
Expand Down Expand Up @@ -1006,6 +1008,10 @@ class User
#[ORM\Version]
public $version;

/** @var string */
#[ORM\Column(index: true)]
public $indexed;

#[ORM\PrePersist]
public function doStuffOnPrePersist(): void
{
Expand Down Expand Up @@ -1065,6 +1071,12 @@ public static function loadMetadata(ClassMetadata $metadata): void
$mapping = ['fieldName' => 'version', 'type' => 'integer'];
$metadata->setVersionMapping($mapping);
$metadata->mapField($mapping);
$metadata->mapField([
'fieldName' => 'indexed',
'type' => 'string',
'columnName' => 'indexed',
'index' => true,
]);
$metadata->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_AUTO);
$metadata->mapOneToOne(
[
Expand Down
2 changes: 1 addition & 1 deletion tests/Tests/ORM/Mapping/XmlMappingDriverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ public static function dataValidSchema(): array
[
User::class,
'cms_users',
['name', 'email', 'version', 'id'],
['name', 'email', 'version', 'indexed', 'id'],
['address', 'phonenumbers', 'groups'],
],
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@

<field name="version" type="integer" version="true" />

<field name="indexed" type="string" index="true" />

<one-to-one field="address" target-entity="Address" inversed-by="user">
<cascade><cascade-remove /></cascade>
<join-column name="address_id" referenced-column-name="id" on-delete="CASCADE" />
Expand Down