mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
NEW Allow methods to be used for flexible searchable_fields (#10199)
* Allow methods to be used for flexible searchable_fields * match_any key * Documentation * Update docs/en/02_Developer_Guides/00_Model/11_Scaffolding.md Co-authored-by: GuySartorelli <36352093+GuySartorelli@users.noreply.github.com> * Search fields test * Newlines * Update src/ORM/Search/SearchContext.php Co-authored-by: Steve Boyd <emteknetnz@gmail.com> * Update docs/en/02_Developer_Guides/00_Model/11_Scaffolding.md Co-authored-by: Steve Boyd <emteknetnz@gmail.com> * Removed comments and whitespace. Linting fixes Co-authored-by: GuySartorelli <36352093+GuySartorelli@users.noreply.github.com> Co-authored-by: Steve Boyd <emteknetnz@gmail.com>
This commit is contained in:
parent
9b93399f1f
commit
6b1c5eb6d7
@ -154,6 +154,31 @@ class Player extends DataObject
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Use a single search field that matches on multiple database fields with `'match_any'`
|
||||||
|
|
||||||
|
```php
|
||||||
|
class Order extends DataObject
|
||||||
|
{
|
||||||
|
private static $has_one = [
|
||||||
|
'Customer' => Customer::class,
|
||||||
|
'ShippingAddress' => Address::class,
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $searchable_fields = [
|
||||||
|
'CustomFirstName' => [
|
||||||
|
'title' => 'First Name',
|
||||||
|
'field' => TextField::class,
|
||||||
|
'filter' => 'PartialMatchFilter',
|
||||||
|
'match_any' => [
|
||||||
|
// Searching with the "First Name" field will show Orders matching either Customer.FirstName or ShippingAddress.FirstName
|
||||||
|
'Customer.FirstName',
|
||||||
|
'ShippingAddress.FirstName',
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Summary Fields
|
### Summary Fields
|
||||||
|
|
||||||
Summary fields can be used to show a quick overview of the data for a specific [DataObject](api:SilverStripe\ORM\DataObject) record. The most common use
|
Summary fields can be used to show a quick overview of the data for a specific [DataObject](api:SilverStripe\ORM\DataObject) record. The most common use
|
||||||
|
@ -3754,6 +3754,9 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
if (is_int($name)) {
|
if (is_int($name)) {
|
||||||
// Format: array('MyFieldName')
|
// Format: array('MyFieldName')
|
||||||
$rewrite[$identifier] = [];
|
$rewrite[$identifier] = [];
|
||||||
|
} elseif (is_array($specOrName) && (isset($specOrName['match_any']))) {
|
||||||
|
$rewrite[$identifier] = $fields[$identifier];
|
||||||
|
$rewrite[$identifier]['match_any'] = $specOrName['match_any'];
|
||||||
} elseif (is_array($specOrName) && ($relObject = $this->relObject($identifier))) {
|
} elseif (is_array($specOrName) && ($relObject = $this->relObject($identifier))) {
|
||||||
// Format: array('MyFieldName' => array(
|
// Format: array('MyFieldName' => array(
|
||||||
// 'filter => 'ExactMatchFilter',
|
// 'filter => 'ExactMatchFilter',
|
||||||
|
@ -5,6 +5,7 @@ namespace SilverStripe\ORM\Search;
|
|||||||
use SilverStripe\Control\HTTPRequest;
|
use SilverStripe\Control\HTTPRequest;
|
||||||
use SilverStripe\Core\ClassInfo;
|
use SilverStripe\Core\ClassInfo;
|
||||||
use SilverStripe\Core\Injector\Injectable;
|
use SilverStripe\Core\Injector\Injectable;
|
||||||
|
use SilverStripe\Core\Injector\Injector;
|
||||||
use SilverStripe\Forms\FieldList;
|
use SilverStripe\Forms\FieldList;
|
||||||
use SilverStripe\Forms\FormField;
|
use SilverStripe\Forms\FormField;
|
||||||
use SilverStripe\ORM\DataObject;
|
use SilverStripe\ORM\DataObject;
|
||||||
@ -179,10 +180,29 @@ class SearchContext
|
|||||||
$filter->setModel($this->modelClass);
|
$filter->setModel($this->modelClass);
|
||||||
$filter->setValue($value);
|
$filter->setValue($value);
|
||||||
if (!$filter->isEmpty()) {
|
if (!$filter->isEmpty()) {
|
||||||
|
$modelObj = Injector::inst()->create($this->modelClass);
|
||||||
|
if (isset($modelObj->searchableFields()[$key]['match_any'])) {
|
||||||
|
$query = $query->alterDataQuery(function ($dataQuery) use ($modelObj, $key, $value) {
|
||||||
|
$searchFields = $modelObj->searchableFields()[$key]['match_any'];
|
||||||
|
$sqlSearchFields = [];
|
||||||
|
foreach ($searchFields as $dottedRelation) {
|
||||||
|
$relation = substr($dottedRelation, 0, strpos($dottedRelation, '.'));
|
||||||
|
$relations = explode('.', $dottedRelation);
|
||||||
|
$fieldName = array_pop($relations);
|
||||||
|
$relationModelName = $dataQuery->applyRelation($relation);
|
||||||
|
$relationPrefix = $dataQuery->applyRelationPrefix($relation);
|
||||||
|
$columnName = $modelObj->getSchema()
|
||||||
|
->sqlColumnForField($relationModelName, $fieldName, $relationPrefix);
|
||||||
|
$sqlSearchFields[$columnName] = $value;
|
||||||
|
}
|
||||||
|
$dataQuery = $dataQuery->whereAny($sqlSearchFields);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
$query = $query->alterDataQuery([$filter, 'apply']);
|
$query = $query->alterDataQuery([$filter, 'apply']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->connective != "AND") {
|
if ($this->connective != "AND") {
|
||||||
throw new Exception("SearchContext connective '$this->connective' not supported after ORM-rewrite.");
|
throw new Exception("SearchContext connective '$this->connective' not supported after ORM-rewrite.");
|
||||||
|
@ -26,6 +26,9 @@ class SearchContextTest extends SapphireTest
|
|||||||
SearchContextTest\Deadline::class,
|
SearchContextTest\Deadline::class,
|
||||||
SearchContextTest\Action::class,
|
SearchContextTest\Action::class,
|
||||||
SearchContextTest\AllFilterTypes::class,
|
SearchContextTest\AllFilterTypes::class,
|
||||||
|
SearchContextTest\Customer::class,
|
||||||
|
SearchContextTest\Address::class,
|
||||||
|
SearchContextTest\Order::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
public function testResultSetFilterReturnsExpectedCount()
|
public function testResultSetFilterReturnsExpectedCount()
|
||||||
@ -251,4 +254,18 @@ class SearchContextTest extends SapphireTest
|
|||||||
$nothing = $list->find('Field', 'Nothing');
|
$nothing = $list->find('Field', 'Nothing');
|
||||||
$this->assertNull($nothing);
|
$this->assertNull($nothing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testMatchAnySearch()
|
||||||
|
{
|
||||||
|
$order1 = $this->objFromFixture(SearchContextTest\Order::class, 'order1');
|
||||||
|
$context = $order1->getDefaultSearchContext();
|
||||||
|
|
||||||
|
// Search should match Order's customer FirstName
|
||||||
|
$results = $context->getResults(['CustomFirstName' => 'Bill']);
|
||||||
|
$this->assertEquals(1, $results->Count());
|
||||||
|
|
||||||
|
// Search should match Order's shipping address FirstName
|
||||||
|
$results = $context->getResults(['CustomFirstName' => 'Bob']);
|
||||||
|
$this->assertEquals(1, $results->Count());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,3 +70,16 @@ SilverStripe\ORM\Tests\Search\SearchContextTest\AllFilterTypes:
|
|||||||
StartsWith: 12345-6789 CamelCase
|
StartsWith: 12345-6789 CamelCase
|
||||||
EndsWith: abcd-efgh-ijkl
|
EndsWith: abcd-efgh-ijkl
|
||||||
FulltextField: one two three
|
FulltextField: one two three
|
||||||
|
|
||||||
|
SilverStripe\ORM\Tests\Search\SearchContextTest\Customer:
|
||||||
|
customer1:
|
||||||
|
FirstName: Bill
|
||||||
|
|
||||||
|
SilverStripe\ORM\Tests\Search\SearchContextTest\Address:
|
||||||
|
address1:
|
||||||
|
FirstName: Bob
|
||||||
|
|
||||||
|
SilverStripe\ORM\Tests\Search\SearchContextTest\Order:
|
||||||
|
order1:
|
||||||
|
Customer: =>SilverStripe\ORM\Tests\Search\SearchContextTest\Customer.customer1
|
||||||
|
ShippingAddress: =>SilverStripe\ORM\Tests\Search\SearchContextTest\Address.address1
|
||||||
|
15
tests/php/ORM/Search/SearchContextTest/Address.php
Normal file
15
tests/php/ORM/Search/SearchContextTest/Address.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\Search\SearchContextTest;
|
||||||
|
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
|
||||||
|
class Address extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'SearchContextTest_Address';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'FirstName' => 'Text'
|
||||||
|
];
|
||||||
|
}
|
15
tests/php/ORM/Search/SearchContextTest/Customer.php
Normal file
15
tests/php/ORM/Search/SearchContextTest/Customer.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\Search\SearchContextTest;
|
||||||
|
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
|
||||||
|
class Customer extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'SearchContextTest_Customer';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'FirstName' => 'Text'
|
||||||
|
];
|
||||||
|
}
|
30
tests/php/ORM/Search/SearchContextTest/Order.php
Normal file
30
tests/php/ORM/Search/SearchContextTest/Order.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\Search\SearchContextTest;
|
||||||
|
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
use SilverStripe\Forms\TextField;
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
|
||||||
|
class Order extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'SearchContextTest_Order';
|
||||||
|
|
||||||
|
private static $has_one = [
|
||||||
|
'Customer' => Customer::class,
|
||||||
|
'ShippingAddress' => Address::class,
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $searchable_fields = [
|
||||||
|
'CustomFirstName' => [
|
||||||
|
'title' => 'First Name',
|
||||||
|
'field' => TextField::class,
|
||||||
|
'filter' => 'PartialMatchFilter',
|
||||||
|
'match_any' => [
|
||||||
|
// Searching with "First Name" will show Orders with matching Customer or Address names
|
||||||
|
'Customer.FirstName',
|
||||||
|
'ShippingAddress.FirstName',
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user