diff --git a/docs/en/reference/annotations-reference.rst b/docs/en/reference/annotations-reference.rst index 8d40096ca..27271f491 100644 --- a/docs/en/reference/annotations-reference.rst +++ b/docs/en/reference/annotations-reference.rst @@ -421,6 +421,13 @@ Required attributes: - **name**: Name of the Index - **columns**: Array of columns. +Optional attributes: + +- **options**: Array of platform specific options: + + - ``where``: SQL WHERE condition to be used for partial indexes. It will + only have effect on supported platforms. + Example: .. code-block:: php @@ -1154,6 +1161,13 @@ Required attributes: - **name**: Name of the Index - **columns**: Array of columns. +Optional attributes: + +- **options**: Array of platform specific options: + + - ``where``: SQL WHERE condition to be used for partial indexes. It will + only have effect on supported platforms. + Example: .. code-block:: php diff --git a/doctrine-mapping.xsd b/doctrine-mapping.xsd index fea44a691..a6440a2e8 100644 --- a/doctrine-mapping.xsd +++ b/doctrine-mapping.xsd @@ -5,9 +5,9 @@ xmlns:orm="http://doctrine-project.org/schemas/orm/doctrine-mapping" elementFormDefault="qualified"> - - + @@ -23,27 +23,27 @@ - + - + - - - - - + + + + + - + @@ -64,7 +64,7 @@ - + @@ -73,7 +73,7 @@ - + @@ -199,7 +199,7 @@ - + @@ -245,7 +245,7 @@ - + @@ -253,33 +253,33 @@ - - - + + + - - - - - + + + + + - + - - - - - + + + + + - + - - - - + + + + - + @@ -299,13 +299,13 @@ - + - + @@ -317,16 +317,17 @@ - + + - + @@ -334,9 +335,10 @@ - + + @@ -344,7 +346,7 @@ - + @@ -352,7 +354,7 @@ - + @@ -361,7 +363,7 @@ - + @@ -509,7 +511,7 @@ - + @@ -528,7 +530,7 @@ - + diff --git a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php index 3f46e2c95..85f40b2f5 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php @@ -102,11 +102,15 @@ class AnnotationDriver extends AbstractAnnotationDriver if ($tableAnnot->indexes !== null) { foreach ($tableAnnot->indexes as $indexAnnot) { $index = array('columns' => $indexAnnot->columns); - + if ( ! empty($indexAnnot->flags)) { $index['flags'] = $indexAnnot->flags; } + if ( ! empty($indexAnnot->options)) { + $index['options'] = $indexAnnot->options; + } + if ( ! empty($indexAnnot->name)) { $primaryTable['indexes'][$indexAnnot->name] = $index; } else { @@ -119,6 +123,10 @@ class AnnotationDriver extends AbstractAnnotationDriver foreach ($tableAnnot->uniqueConstraints as $uniqueConstraintAnnot) { $uniqueConstraint = array('columns' => $uniqueConstraintAnnot->columns); + if ( ! empty($uniqueConstraintAnnot->options)) { + $uniqueConstraint['options'] = $uniqueConstraintAnnot->options; + } + if ( ! empty($uniqueConstraintAnnot->name)) { $primaryTable['uniqueConstraints'][$uniqueConstraintAnnot->name] = $uniqueConstraint; } else { diff --git a/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php b/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php index e08ee7ae6..45836a6b9 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php @@ -196,11 +196,15 @@ class XmlDriver extends FileDriver $metadata->table['indexes'] = array(); foreach ($xmlRoot->indexes->index as $indexXml) { $index = array('columns' => explode(',', (string) $indexXml['columns'])); - + if (isset($indexXml['flags'])) { $index['flags'] = explode(',', (string) $indexXml['flags']); } - + + if (isset($indexXml->options)) { + $index['options'] = $this->_parseOptions($indexXml->options->children()); + } + if (isset($indexXml['name'])) { $metadata->table['indexes'][(string) $indexXml['name']] = $index; } else { @@ -212,17 +216,18 @@ class XmlDriver extends FileDriver // Evaluate if (isset($xmlRoot->{'unique-constraints'})) { $metadata->table['uniqueConstraints'] = array(); - foreach ($xmlRoot->{'unique-constraints'}->{'unique-constraint'} as $unique) { - $columns = explode(',', (string)$unique['columns']); + foreach ($xmlRoot->{'unique-constraints'}->{'unique-constraint'} as $uniqueXml) { + $unique = array('columns' => explode(',', (string) $uniqueXml['columns'])); - if (isset($unique['name'])) { - $metadata->table['uniqueConstraints'][(string)$unique['name']] = array( - 'columns' => $columns - ); + + if (isset($uniqueXml->options)) { + $unique['options'] = $this->_parseOptions($uniqueXml->options->children()); + } + + if (isset($uniqueXml['name'])) { + $metadata->table['uniqueConstraints'][(string)$uniqueXml['name']] = $unique; } else { - $metadata->table['uniqueConstraints'][] = array( - 'columns' => $columns - ); + $metadata->table['uniqueConstraints'][] = $unique; } } } diff --git a/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php b/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php index 2772913cc..c492c0f54 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php @@ -220,27 +220,32 @@ class YamlDriver extends FileDriver } } + if (isset($indexYml['options'])) { + $index['options'] = $indexYml['options']; + } + $metadata->table['indexes'][$indexYml['name']] = $index; } } // Evaluate uniqueConstraints if (isset($element['uniqueConstraints'])) { - foreach ($element['uniqueConstraints'] as $name => $unique) { - if ( ! isset($unique['name'])) { - $unique['name'] = $name; + foreach ($element['uniqueConstraints'] as $name => $uniqueYml) { + if ( ! isset($uniqueYml['name'])) { + $uniqueYml['name'] = $name; } - if (is_string($unique['columns'])) { - $columns = explode(',', $unique['columns']); - $columns = array_map('trim', $columns); + if (is_string($uniqueYml['columns'])) { + $unique = array('columns' => array_map('trim', explode(',', $uniqueYml['columns']))); } else { - $columns = $unique['columns']; + $unique = array('columns' => $uniqueYml['columns']); } - $metadata->table['uniqueConstraints'][$unique['name']] = array( - 'columns' => $columns - ); + if (isset($uniqueYml['options'])) { + $unique['options'] = $uniqueYml['options']; + } + + $metadata->table['uniqueConstraints'][$uniqueYml['name']] = $unique; } } diff --git a/lib/Doctrine/ORM/Mapping/Index.php b/lib/Doctrine/ORM/Mapping/Index.php index ff4532d47..45953a804 100644 --- a/lib/Doctrine/ORM/Mapping/Index.php +++ b/lib/Doctrine/ORM/Mapping/Index.php @@ -39,4 +39,9 @@ final class Index implements Annotation * @var array */ public $flags; + + /** + * @var array + */ + public $options; } diff --git a/lib/Doctrine/ORM/Mapping/UniqueConstraint.php b/lib/Doctrine/ORM/Mapping/UniqueConstraint.php index 95d99293f..f117d1873 100644 --- a/lib/Doctrine/ORM/Mapping/UniqueConstraint.php +++ b/lib/Doctrine/ORM/Mapping/UniqueConstraint.php @@ -34,4 +34,9 @@ final class UniqueConstraint implements Annotation * @var array */ public $columns; + + /** + * @var array + */ + public $options; } diff --git a/lib/Doctrine/ORM/Tools/SchemaTool.php b/lib/Doctrine/ORM/Tools/SchemaTool.php index 9bca3ed66..db9438c9f 100644 --- a/lib/Doctrine/ORM/Tools/SchemaTool.php +++ b/lib/Doctrine/ORM/Tools/SchemaTool.php @@ -267,14 +267,14 @@ class SchemaTool if( ! isset($indexData['flags'])) { $indexData['flags'] = array(); } - - $table->addIndex($indexData['columns'], is_numeric($indexName) ? null : $indexName, (array)$indexData['flags']); + + $table->addIndex($indexData['columns'], is_numeric($indexName) ? null : $indexName, (array)$indexData['flags'], isset($indexData['options']) ? $indexData['options'] : array()); } } if (isset($class->table['uniqueConstraints'])) { foreach ($class->table['uniqueConstraints'] as $indexName => $indexData) { - $table->addUniqueIndex($indexData['columns'], is_numeric($indexName) ? null : $indexName); + $table->addUniqueIndex($indexData['columns'], is_numeric($indexName) ? null : $indexName, isset($indexData['options']) ? $indexData['options'] : array()); } } diff --git a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php index 7a22dc1da..b81b3ba1e 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php @@ -73,14 +73,15 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase return $class; } - public function testEntityIndexFlags() + public function testEntityIndexFlagsAndPartialIndexes() { $class = $this->createClassMetadata('Doctrine\Tests\ORM\Mapping\Comment'); $this->assertEquals(array( 0 => array( 'columns' => array('content'), - 'flags' => array('fulltext') + 'flags' => array('fulltext'), + 'options' => array('where' => 'content IS NOT NULL'), ) ), $class->table['indexes']); } @@ -95,7 +96,7 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase 'ClassMetadata should have uniqueConstraints key in table property when Unique Constraints are set.'); $this->assertEquals(array( - "search_idx" => array("columns" => array("name", "user_email")) + "search_idx" => array("columns" => array("name", "user_email"), 'options' => array('where' => 'name IS NOT NULL')) ), $class->table['uniqueConstraints']); return $class; @@ -938,7 +939,7 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase * @HasLifecycleCallbacks * @Table( * name="cms_users", - * uniqueConstraints={@UniqueConstraint(name="search_idx", columns={"name", "user_email"})}, + * uniqueConstraints={@UniqueConstraint(name="search_idx", columns={"name", "user_email"}, options={"where": "name IS NOT NULL"})}, * indexes={@Index(name="name_idx", columns={"name"}), @Index(name="0", columns={"user_email"})}, * options={"foo": "bar", "baz": {"key": "val"}} * ) @@ -1122,7 +1123,7 @@ class User 'orderBy' => NULL, )); $metadata->table['uniqueConstraints'] = array( - 'search_idx' => array('columns' => array('name', 'user_email')), + 'search_idx' => array('columns' => array('name', 'user_email'), 'options'=> array('where' => 'name IS NOT NULL')), ); $metadata->table['indexes'] = array( 'name_idx' => array('columns' => array('name')), 0 => array('columns' => array('user_email')) @@ -1281,7 +1282,7 @@ class Group {} /** * @Entity - * @Table(indexes={@Index(columns={"content"}, flags={"fulltext"})}) + * @Table(indexes={@Index(columns={"content"}, flags={"fulltext"}, options={"where": "content IS NOT NULL"})}) */ class Comment { @@ -1295,7 +1296,7 @@ class Comment $metadata->setInheritanceType(ClassMetadataInfo::INHERITANCE_TYPE_NONE); $metadata->setPrimaryTable(array( 'indexes' => array( - array('columns' => array('content'), 'flags' => array('fulltext')) + array('columns' => array('content'), 'flags' => array('fulltext'), 'options' => array('where' => 'content IS NOT NULL')) ) )); diff --git a/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.Comment.php b/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.Comment.php index 124aafe1d..85cbed4dc 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.Comment.php +++ b/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.Comment.php @@ -5,7 +5,7 @@ use Doctrine\ORM\Mapping\ClassMetadataInfo; $metadata->setInheritanceType(ClassMetadataInfo::INHERITANCE_TYPE_NONE); $metadata->setPrimaryTable(array( 'indexes' => array( - array('columns' => array('content'), 'flags' => array('fulltext')) + array('columns' => array('content'), 'flags' => array('fulltext'), 'options'=> array('where' => 'content IS NOT NULL')) ) )); diff --git a/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.User.php b/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.User.php index 1795793d3..67dbd752d 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.User.php +++ b/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.User.php @@ -112,11 +112,11 @@ $metadata->mapManyToMany(array( 'orderBy' => NULL, )); $metadata->table['options'] = array( - 'foo' => 'bar', + 'foo' => 'bar', 'baz' => array('key' => 'val') ); $metadata->table['uniqueConstraints'] = array( - 'search_idx' => array('columns' => array('name', 'user_email')), + 'search_idx' => array('columns' => array('name', 'user_email'), 'options' => array('where' => 'name IS NOT NULL')), ); $metadata->table['indexes'] = array( 'name_idx' => array('columns' => array('name')), 0 => array('columns' => array('user_email')) diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.Comment.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.Comment.dcm.xml index 659ddccd8..8f02ca852 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.Comment.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.Comment.dcm.xml @@ -8,7 +8,11 @@ - + + + + + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.User.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.User.dcm.xml index 728425a71..28b1e0571 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.User.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.User.dcm.xml @@ -19,7 +19,11 @@ - + + + + + diff --git a/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.Comment.dcm.yml b/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.Comment.dcm.yml index 2186f6a27..f37bfdcc6 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.Comment.dcm.yml +++ b/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.Comment.dcm.yml @@ -7,3 +7,5 @@ Doctrine\Tests\ORM\Mapping\Comment: 0: columns: content flags: fulltext + options: + where: "content IS NOT NULL" diff --git a/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.User.dcm.yml b/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.User.dcm.yml index 6b87472d1..457b24eea 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.User.dcm.yml +++ b/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.User.dcm.yml @@ -69,11 +69,13 @@ Doctrine\Tests\ORM\Mapping\User: cascade: - all lifecycleCallbacks: - prePersist: [ doStuffOnPrePersist, doOtherStuffOnPrePersistToo ] + prePersist: [ doStuffOnPrePersist, doOtherStuffOnPrePersistToo ] postPersist: [ doStuffOnPostPersist ] uniqueConstraints: search_idx: columns: name,user_email + options: + where: name IS NOT NULL indexes: name_idx: columns: name