diff --git a/docs/en/00_Getting_Started/01_Installation/How_To/Configure_Nginx.md b/docs/en/00_Getting_Started/01_Installation/How_To/Configure_Nginx.md
index b1be3f83d..cea572907 100644
--- a/docs/en/00_Getting_Started/01_Installation/How_To/Configure_Nginx.md
+++ b/docs/en/00_Getting_Started/01_Installation/How_To/Configure_Nginx.md
@@ -1,7 +1,7 @@
# Nginx
These instructions are also covered on the
-[Nginx Wiki](http://wiki.nginx.org/SilverStripe).
+[Nginx Wiki](https://www.nginx.com/resources/wiki/start/topics/recipes/silverstripe/).
The prerequisite is that you have already installed Nginx and you are
able to run PHP files via the FastCGI-wrapper from Nginx.
diff --git a/docs/en/02_Developer_Guides/00_Model/12_Indexes.md b/docs/en/02_Developer_Guides/00_Model/12_Indexes.md
index 6d686a26d..294135646 100644
--- a/docs/en/02_Developer_Guides/00_Model/12_Indexes.md
+++ b/docs/en/02_Developer_Guides/00_Model/12_Indexes.md
@@ -93,6 +93,9 @@ other columns. If this is indexed, smaller and reasonably unique it might be fas
Indexes are generated and removed automatically during a `dev/build`. Caution if you're working with large tables and
modify an index as the next `dev/build` will `DROP` the index, and then `ADD` it.
+As of 3.7.0 `default_sort` fields will automatically become database indexes as this provides significant performance
+benefits.
+
## API Documentation
* [DataObject](api:SilverStripe\ORM\DataObject)
diff --git a/src/ORM/DataObjectSchema.php b/src/ORM/DataObjectSchema.php
index 6ad3cfe34..01db82927 100644
--- a/src/ORM/DataObjectSchema.php
+++ b/src/ORM/DataObjectSchema.php
@@ -219,7 +219,7 @@ class DataObjectSchema
// Record specification
foreach ($fields as $name => $specification) {
$prefix = $includeClass ? "{$tableClass}." : "";
- $db[$name] = $prefix . $specification;
+ $db[$name] = $prefix . $specification;
}
}
return $db;
@@ -524,6 +524,7 @@ class DataObjectSchema
{
if (!array_key_exists($class, $this->databaseIndexes)) {
$this->databaseIndexes[$class] = array_merge(
+ $this->buildSortDatabaseIndexes($class),
$this->cacheDefaultDatabaseIndexes($class),
$this->buildCustomDatabaseIndexes($class)
);
@@ -604,6 +605,53 @@ class DataObjectSchema
return $indexes;
}
+ protected function buildSortDatabaseIndexes($class)
+ {
+ $sort = Config::inst()->get($class, 'default_sort', Config::UNINHERITED);
+ $indexes = [];
+
+ if ($sort && is_string($sort)) {
+ $sort = preg_split('/,(?![^()]*+\\))/', $sort);
+ foreach ($sort as $value) {
+ try {
+ list ($table, $column) = $this->parseSortColumn(trim($value));
+ $table = trim($table, '"');
+ $column = trim($column, '"');
+ if ($table && strtolower($table) !== strtolower(self::tableName($class))) {
+ continue;
+ }
+ if ($this->databaseField($class, $column, false)) {
+ $indexes[$column] = [
+ 'type' => 'index',
+ 'columns' => [$column],
+ ];
+ }
+ } catch (InvalidArgumentException $e) {
+ }
+ }
+ }
+ return $indexes;
+ }
+
+ /**
+ * Parses a specified column into a sort field and direction
+ *
+ * @param string $column String to parse containing the column name
+ * @return array Resolved table and column.
+ */
+ protected function parseSortColumn($column)
+ {
+ // Parse column specification, considering possible ansi sql quoting
+ // Note that table prefix is allowed, but discarded
+ if (preg_match('/^("?(?
[^"\s]+)"?\\.)?"?(?[^"\s]+)"?(\s+(?((asc)|(desc))(ending)?))?$/i', $column, $match)) {
+ $table = $match['table'];
+ $column = $match['column'];
+ } else {
+ throw new InvalidArgumentException("Invalid sort() column");
+ }
+ return array($table, $column);
+ }
+
/**
* Returns the table name in the class hierarchy which contains a given
* field column for a {@link DataObject}. If the field does not exist, this
@@ -714,7 +762,6 @@ class DataObjectSchema
}
-
/**
* Parse a belongs_many_many component to extract class and relationship name
*
diff --git a/tests/php/ORM/DataObjectSchemaGenerationTest.php b/tests/php/ORM/DataObjectSchemaGenerationTest.php
index 3f305b824..b366d5d51 100644
--- a/tests/php/ORM/DataObjectSchemaGenerationTest.php
+++ b/tests/php/ORM/DataObjectSchemaGenerationTest.php
@@ -2,11 +2,13 @@
namespace SilverStripe\ORM\Tests;
+use SilverStripe\Core\Config\Config;
use SilverStripe\ORM\Connect\MySQLSchemaManager;
use SilverStripe\ORM\DB;
use SilverStripe\ORM\FieldType\DBClassName;
use SilverStripe\ORM\DataObject;
use SilverStripe\Dev\SapphireTest;
+use SilverStripe\ORM\Tests\DataObjectSchemaGenerationTest\SortedObject;
use SilverStripe\ORM\Tests\DataObjectSchemaGenerationTest\TestIndexObject;
use SilverStripe\ORM\Tests\DataObjectSchemaGenerationTest\TestObject;
@@ -14,7 +16,8 @@ class DataObjectSchemaGenerationTest extends SapphireTest
{
protected static $extra_dataobjects = array(
TestObject::class,
- TestIndexObject::class
+ TestIndexObject::class,
+ SortedObject::class,
);
public static function setUpBeforeClass()
@@ -260,4 +263,65 @@ class DataObjectSchemaGenerationTest extends SapphireTest
$item1->delete();
$item2->delete();
}
+
+ public function testSortFieldBecomeIndexes()
+ {
+ $indexes = DataObject::getSchema()->databaseIndexes(SortedObject::class);
+ $this->assertContains([
+ 'type' => 'index',
+ 'columns' => ['Sort'],
+ ], $indexes);
+ DataObject::getSchema()->reset();
+ Config::inst()->update(SortedObject::class, 'default_sort', 'Sort ASC');
+ $indexes = DataObject::getSchema()->databaseIndexes(SortedObject::class);
+ $this->assertContains([
+ 'type' => 'index',
+ 'columns' => ['Sort'],
+ ], $indexes);
+ DataObject::getSchema()->reset();
+ Config::inst()->update(SortedObject::class, 'default_sort', 'Sort DESC');
+ $indexes = DataObject::getSchema()->databaseIndexes(SortedObject::class);
+ $this->assertContains([
+ 'type' => 'index',
+ 'columns' => ['Sort'],
+ ], $indexes);
+ DataObject::getSchema()->reset();
+ Config::inst()->update(SortedObject::class, 'default_sort', '"Sort" DESC');
+ $indexes = DataObject::getSchema()->databaseIndexes(SortedObject::class);
+ $this->assertContains([
+ 'type' => 'index',
+ 'columns' => ['Sort'],
+ ], $indexes);
+ DataObject::getSchema()->reset();
+ Config::inst()->update(SortedObject::class, 'default_sort', '"DataObjectSchemaGenerationTest_SortedObject"."Sort" ASC');
+ $indexes = DataObject::getSchema()->databaseIndexes(SortedObject::class);
+ $this->assertContains([
+ 'type' => 'index',
+ 'columns' => ['Sort'],
+ ], $indexes);
+ DataObject::getSchema()->reset();
+ Config::inst()->update(SortedObject::class, 'default_sort', '"Sort" DESC, "Title" ASC');
+ $indexes = DataObject::getSchema()->databaseIndexes(SortedObject::class);
+ $this->assertContains([
+ 'type' => 'index',
+ 'columns' => ['Sort'],
+ ], $indexes);
+ $this->assertContains([
+ 'type' => 'index',
+ 'columns' => ['Title'],
+ ], $indexes);
+ DataObject::getSchema()->reset();
+ // make sure that specific indexes aren't overwritten
+ Config::inst()->update(SortedObject::class, 'indexes', [
+ 'Sort' => [
+ 'type' => 'unique',
+ 'columns' => ['Sort'],
+ ],
+ ]);
+ $indexes = DataObject::getSchema()->databaseIndexes(SortedObject::class);
+ $this->assertContains([
+ 'type' => 'unique',
+ 'columns' => ['Sort'],
+ ], $indexes);
+ }
}
diff --git a/tests/php/ORM/DataObjectSchemaGenerationTest/SortedObject.php b/tests/php/ORM/DataObjectSchemaGenerationTest/SortedObject.php
new file mode 100644
index 000000000..51484f72d
--- /dev/null
+++ b/tests/php/ORM/DataObjectSchemaGenerationTest/SortedObject.php
@@ -0,0 +1,18 @@
+ 'Varchar',
+ 'Sort' => 'Int',
+ ];
+
+ private static $default_sort = 'Sort';
+}