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 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)) {
|
||||
// Format: array('MyFieldName')
|
||||
$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))) {
|
||||
// Format: array('MyFieldName' => array(
|
||||
// 'filter => 'ExactMatchFilter',
|
||||
|
@ -5,6 +5,7 @@ namespace SilverStripe\ORM\Search;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Core\Injector\Injectable;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
@ -179,7 +180,26 @@ class SearchContext
|
||||
$filter->setModel($this->modelClass);
|
||||
$filter->setValue($value);
|
||||
if (!$filter->isEmpty()) {
|
||||
$query = $query->alterDataQuery([$filter, 'apply']);
|
||||
$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']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,9 @@ class SearchContextTest extends SapphireTest
|
||||
SearchContextTest\Deadline::class,
|
||||
SearchContextTest\Action::class,
|
||||
SearchContextTest\AllFilterTypes::class,
|
||||
SearchContextTest\Customer::class,
|
||||
SearchContextTest\Address::class,
|
||||
SearchContextTest\Order::class,
|
||||
];
|
||||
|
||||
public function testResultSetFilterReturnsExpectedCount()
|
||||
@ -251,4 +254,18 @@ class SearchContextTest extends SapphireTest
|
||||
$nothing = $list->find('Field', '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
|
||||
EndsWith: abcd-efgh-ijkl
|
||||
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