|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace SilverStripe\ORM\Tests\Search; |
|
4
|
|
|
|
|
5
|
|
|
use SilverStripe\Dev\SapphireTest; |
|
6
|
|
|
use SilverStripe\Forms\TextField; |
|
7
|
|
|
use SilverStripe\Forms\TextareaField; |
|
8
|
|
|
use SilverStripe\Forms\NumericField; |
|
9
|
|
|
use SilverStripe\Forms\DropdownField; |
|
10
|
|
|
use SilverStripe\Forms\CheckboxField; |
|
11
|
|
|
use SilverStripe\Forms\FieldList; |
|
12
|
|
|
use SilverStripe\ORM\DataList; |
|
13
|
|
|
use SilverStripe\ORM\Filters\PartialMatchFilter; |
|
14
|
|
|
use SilverStripe\ORM\Search\SearchContext; |
|
15
|
|
|
|
|
16
|
|
|
class SearchContextTest extends SapphireTest |
|
17
|
|
|
{ |
|
18
|
|
|
|
|
19
|
|
|
protected static $fixture_file = 'SearchContextTest.yml'; |
|
20
|
|
|
|
|
21
|
|
|
protected static $extra_dataobjects = [ |
|
22
|
|
|
SearchContextTest\Person::class, |
|
23
|
|
|
SearchContextTest\Book::class, |
|
24
|
|
|
SearchContextTest\Company::class, |
|
25
|
|
|
SearchContextTest\Project::class, |
|
26
|
|
|
SearchContextTest\Deadline::class, |
|
27
|
|
|
SearchContextTest\Action::class, |
|
28
|
|
|
SearchContextTest\AllFilterTypes::class, |
|
29
|
|
|
SearchContextTest\Customer::class, |
|
30
|
|
|
SearchContextTest\Address::class, |
|
31
|
|
|
SearchContextTest\Order::class, |
|
32
|
|
|
]; |
|
33
|
|
|
|
|
34
|
|
|
public function testResultSetFilterReturnsExpectedCount() |
|
35
|
|
|
{ |
|
36
|
|
|
$person = SearchContextTest\Person::singleton(); |
|
37
|
|
|
$context = $person->getDefaultSearchContext(); |
|
38
|
|
|
$results = $context->getResults(['Name' => '']); |
|
39
|
|
|
$this->assertEquals(5, $results->Count()); |
|
40
|
|
|
|
|
41
|
|
|
$results = $context->getResults(['EyeColor' => 'green']); |
|
42
|
|
|
$this->assertEquals(2, $results->Count()); |
|
43
|
|
|
|
|
44
|
|
|
$results = $context->getResults(['EyeColor' => 'green', 'HairColor' => 'black']); |
|
45
|
|
|
$this->assertEquals(1, $results->Count()); |
|
46
|
|
|
} |
|
47
|
|
|
|
|
48
|
|
|
public function testSummaryIncludesDefaultFieldsIfNotDefined() |
|
49
|
|
|
{ |
|
50
|
|
|
$person = SearchContextTest\Person::singleton(); |
|
51
|
|
|
$this->assertContains('Name', $person->summaryFields()); |
|
52
|
|
|
|
|
53
|
|
|
$book = SearchContextTest\Book::singleton(); |
|
54
|
|
|
$this->assertContains('Title', $book->summaryFields()); |
|
55
|
|
|
} |
|
56
|
|
|
|
|
57
|
|
|
public function testAccessDefinedSummaryFields() |
|
58
|
|
|
{ |
|
59
|
|
|
$company = SearchContextTest\Company::singleton(); |
|
60
|
|
|
$this->assertContains('Industry', $company->summaryFields()); |
|
61
|
|
|
} |
|
62
|
|
|
|
|
63
|
|
|
public function testPartialMatchUsedByDefaultWhenNotExplicitlySet() |
|
64
|
|
|
{ |
|
65
|
|
|
$person = SearchContextTest\Person::singleton(); |
|
66
|
|
|
$context = $person->getDefaultSearchContext(); |
|
67
|
|
|
|
|
68
|
|
|
$this->assertEquals( |
|
69
|
|
|
[ |
|
70
|
|
|
"Name" => new PartialMatchFilter("Name"), |
|
71
|
|
|
"HairColor" => new PartialMatchFilter("HairColor"), |
|
72
|
|
|
"EyeColor" => new PartialMatchFilter("EyeColor") |
|
73
|
|
|
], |
|
74
|
|
|
$context->getFilters() |
|
75
|
|
|
); |
|
76
|
|
|
} |
|
77
|
|
|
|
|
78
|
|
|
public function testDefaultFiltersDefinedWhenNotSetInDataObject() |
|
79
|
|
|
{ |
|
80
|
|
|
$book = SearchContextTest\Book::singleton(); |
|
81
|
|
|
$context = $book->getDefaultSearchContext(); |
|
82
|
|
|
|
|
83
|
|
|
$this->assertEquals( |
|
84
|
|
|
[ |
|
85
|
|
|
"Title" => new PartialMatchFilter("Title") |
|
86
|
|
|
], |
|
87
|
|
|
$context->getFilters() |
|
88
|
|
|
); |
|
89
|
|
|
} |
|
90
|
|
|
|
|
91
|
|
|
public function testUserDefinedFiltersAppearInSearchContext() |
|
92
|
|
|
{ |
|
93
|
|
|
$company = SearchContextTest\Company::singleton(); |
|
94
|
|
|
$context = $company->getDefaultSearchContext(); |
|
95
|
|
|
|
|
96
|
|
|
$this->assertEquals( |
|
97
|
|
|
[ |
|
98
|
|
|
"Name" => new PartialMatchFilter("Name"), |
|
99
|
|
|
"Industry" => new PartialMatchFilter("Industry"), |
|
100
|
|
|
"AnnualProfit" => new PartialMatchFilter("AnnualProfit") |
|
101
|
|
|
], |
|
102
|
|
|
$context->getFilters() |
|
103
|
|
|
); |
|
104
|
|
|
} |
|
105
|
|
|
|
|
106
|
|
|
public function testUserDefinedFieldsAppearInSearchContext() |
|
107
|
|
|
{ |
|
108
|
|
|
$company = SearchContextTest\Company::singleton(); |
|
109
|
|
|
$context = $company->getDefaultSearchContext(); |
|
110
|
|
|
$this->assertEquals( |
|
111
|
|
|
new FieldList( |
|
112
|
|
|
(new TextField("Name", 'Name')) |
|
113
|
|
|
->setMaxLength(255), |
|
114
|
|
|
new TextareaField("Industry", 'Industry'), |
|
115
|
|
|
new NumericField("AnnualProfit", 'The Almighty Annual Profit') |
|
116
|
|
|
), |
|
117
|
|
|
$context->getFields() |
|
118
|
|
|
); |
|
119
|
|
|
} |
|
120
|
|
|
|
|
121
|
|
|
public function testRelationshipObjectsLinkedInSearch() |
|
122
|
|
|
{ |
|
123
|
|
|
$action3 = $this->objFromFixture(SearchContextTest\Action::class, 'action3'); |
|
124
|
|
|
|
|
125
|
|
|
$project = SearchContextTest\Project::singleton(); |
|
126
|
|
|
$context = $project->getDefaultSearchContext(); |
|
127
|
|
|
|
|
128
|
|
|
$params = ["Name" => "Blog Website", "Actions__SolutionArea" => "technical"]; |
|
129
|
|
|
|
|
130
|
|
|
/** @var DataList $results */ |
|
131
|
|
|
$results = $context->getResults($params); |
|
132
|
|
|
|
|
133
|
|
|
$this->assertEquals(1, $results->count()); |
|
134
|
|
|
|
|
135
|
|
|
/** @var SearchContextTest\Project $project */ |
|
136
|
|
|
$project = $results->first(); |
|
137
|
|
|
|
|
138
|
|
|
$this->assertInstanceOf(SearchContextTest\Project::class, $project); |
|
139
|
|
|
$this->assertEquals("Blog Website", $project->Name); |
|
140
|
|
|
$this->assertEquals(2, $project->Actions()->Count()); |
|
141
|
|
|
|
|
142
|
|
|
$this->assertEquals( |
|
143
|
|
|
"Get RSS feeds working", |
|
144
|
|
|
$project->Actions()->find('ID', $action3->ID)->Description |
|
|
|
|
|
|
145
|
|
|
); |
|
146
|
|
|
} |
|
147
|
|
|
|
|
148
|
|
|
public function testCanGenerateQueryUsingAllFilterTypes() |
|
149
|
|
|
{ |
|
150
|
|
|
$all = SearchContextTest\AllFilterTypes::singleton(); |
|
151
|
|
|
$context = $all->getDefaultSearchContext(); |
|
152
|
|
|
$params = [ |
|
153
|
|
|
"ExactMatch" => "Match me exactly", |
|
154
|
|
|
"PartialMatch" => "partially", |
|
155
|
|
|
"CollectionMatch" => [ |
|
156
|
|
|
"ExistingCollectionValue", |
|
157
|
|
|
"NonExistingCollectionValue", |
|
158
|
|
|
4, |
|
159
|
|
|
"Inline'Quotes'" |
|
160
|
|
|
], |
|
161
|
|
|
"StartsWith" => "12345", |
|
162
|
|
|
"EndsWith" => "ijkl", |
|
163
|
|
|
"Fulltext" => "two" |
|
164
|
|
|
]; |
|
165
|
|
|
|
|
166
|
|
|
$results = $context->getResults($params); |
|
167
|
|
|
$this->assertEquals(1, $results->Count()); |
|
168
|
|
|
$this->assertEquals("Filtered value", $results->First()->HiddenValue); |
|
169
|
|
|
} |
|
170
|
|
|
|
|
171
|
|
|
public function testStartsWithFilterCaseInsensitive() |
|
172
|
|
|
{ |
|
173
|
|
|
$all = SearchContextTest\AllFilterTypes::singleton(); |
|
174
|
|
|
$context = $all->getDefaultSearchContext(); |
|
175
|
|
|
$params = [ |
|
176
|
|
|
"StartsWith" => "12345-6789 camelcase", // spelled lowercase |
|
177
|
|
|
]; |
|
178
|
|
|
|
|
179
|
|
|
$results = $context->getResults($params); |
|
180
|
|
|
$this->assertEquals(1, $results->Count()); |
|
181
|
|
|
$this->assertEquals("Filtered value", $results->First()->HiddenValue); |
|
182
|
|
|
} |
|
183
|
|
|
|
|
184
|
|
|
public function testEndsWithFilterCaseInsensitive() |
|
185
|
|
|
{ |
|
186
|
|
|
$all = SearchContextTest\AllFilterTypes::singleton(); |
|
187
|
|
|
$context = $all->getDefaultSearchContext(); |
|
188
|
|
|
$params = [ |
|
189
|
|
|
"EndsWith" => "IJKL", // spelled uppercase |
|
190
|
|
|
]; |
|
191
|
|
|
|
|
192
|
|
|
$results = $context->getResults($params); |
|
193
|
|
|
$this->assertEquals(1, $results->Count()); |
|
194
|
|
|
$this->assertEquals("Filtered value", $results->First()->HiddenValue); |
|
195
|
|
|
} |
|
196
|
|
|
|
|
197
|
|
|
public function testSearchContextSummary() |
|
198
|
|
|
{ |
|
199
|
|
|
$filters = [ |
|
200
|
|
|
'KeywordSearch' => PartialMatchFilter::create('KeywordSearch'), |
|
201
|
|
|
'Country' => PartialMatchFilter::create('Country'), |
|
202
|
|
|
'CategoryID' => PartialMatchFilter::create('CategoryID'), |
|
203
|
|
|
'Featured' => PartialMatchFilter::create('Featured'), |
|
204
|
|
|
'Nothing' => PartialMatchFilter::create('Nothing'), |
|
205
|
|
|
]; |
|
206
|
|
|
|
|
207
|
|
|
$fields = FieldList::create( |
|
208
|
|
|
TextField::create('KeywordSearch', 'Keywords'), |
|
209
|
|
|
TextField::create('Country', 'Country'), |
|
210
|
|
|
DropdownField::create('CategoryID', 'Category', [ |
|
211
|
|
|
1 => 'Category one', |
|
212
|
|
|
2 => 'Category two', |
|
213
|
|
|
]), |
|
214
|
|
|
CheckboxField::create('Featured', 'Featured') |
|
215
|
|
|
); |
|
216
|
|
|
|
|
217
|
|
|
$context = SearchContext::create( |
|
218
|
|
|
SearchContextTest\Person::class, |
|
219
|
|
|
$fields, |
|
220
|
|
|
$filters |
|
221
|
|
|
); |
|
222
|
|
|
|
|
223
|
|
|
$context->setSearchParams([ |
|
224
|
|
|
'KeywordSearch' => 'tester', |
|
225
|
|
|
'Country' => null, |
|
226
|
|
|
'CategoryID' => 2, |
|
227
|
|
|
'Featured' => 1, |
|
228
|
|
|
'Nothing' => 'empty', |
|
229
|
|
|
]); |
|
230
|
|
|
|
|
231
|
|
|
$list = $context->getSummary(); |
|
232
|
|
|
|
|
233
|
|
|
$this->assertEquals(3, $list->count()); |
|
234
|
|
|
// KeywordSearch should be in the summary |
|
235
|
|
|
$keyword = $list->find('Field', 'Keywords'); |
|
236
|
|
|
$this->assertNotNull($keyword); |
|
237
|
|
|
$this->assertEquals('tester', $keyword->Value); |
|
238
|
|
|
|
|
239
|
|
|
// Country should be skipped over |
|
240
|
|
|
$country = $list->find('Field', 'Country'); |
|
241
|
|
|
$this->assertNull($country); |
|
242
|
|
|
|
|
243
|
|
|
// Category should be expressed as the label |
|
244
|
|
|
$category = $list->find('Field', 'Category'); |
|
245
|
|
|
$this->assertNotNull($category); |
|
246
|
|
|
$this->assertEquals('Category two', $category->Value); |
|
247
|
|
|
|
|
248
|
|
|
// Featured should have no value, since it's binary |
|
249
|
|
|
$featured = $list->find('Field', 'Featured'); |
|
250
|
|
|
$this->assertNotNull($featured); |
|
251
|
|
|
$this->assertNull($featured->Value); |
|
252
|
|
|
|
|
253
|
|
|
// "Nothing" should come back null since there's no field for it |
|
254
|
|
|
$nothing = $list->find('Field', 'Nothing'); |
|
255
|
|
|
$this->assertNull($nothing); |
|
256
|
|
|
} |
|
257
|
|
|
|
|
258
|
|
|
public function testMatchAnySearch() |
|
259
|
|
|
{ |
|
260
|
|
|
$order1 = $this->objFromFixture(SearchContextTest\Order::class, 'order1'); |
|
261
|
|
|
$context = $order1->getDefaultSearchContext(); |
|
262
|
|
|
|
|
263
|
|
|
// Search should match Order's customer FirstName |
|
264
|
|
|
$results = $context->getResults(['CustomFirstName' => 'Bill']); |
|
265
|
|
|
$this->assertEquals(1, $results->Count()); |
|
266
|
|
|
|
|
267
|
|
|
// Search should match Order's shipping address FirstName |
|
268
|
|
|
$results = $context->getResults(['CustomFirstName' => 'Bob']); |
|
269
|
|
|
$this->assertEquals(1, $results->Count()); |
|
270
|
|
|
} |
|
271
|
|
|
} |
|
272
|
|
|
|