Passed
Push — master ( 32a37c...72e173 )
by Sam
09:54
created

DataListTest::testShuffle()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\ORM\Tests;
4
5
use InvalidArgumentException;
6
use SilverStripe\Core\Convert;
7
use SilverStripe\Core\Injector\InjectorNotFoundException;
8
use SilverStripe\ORM\DataList;
9
use SilverStripe\ORM\DataQuery;
10
use SilverStripe\ORM\DB;
11
use SilverStripe\ORM\Filterable;
12
use SilverStripe\ORM\Filters\ExactMatchFilter;
13
use SilverStripe\Dev\SapphireTest;
14
use SilverStripe\ORM\Tests\DataObjectTest\Fixture;
15
use SilverStripe\ORM\Tests\DataObjectTest\Bracket;
16
use SilverStripe\ORM\Tests\DataObjectTest\EquipmentCompany;
17
use SilverStripe\ORM\Tests\DataObjectTest\Fan;
18
use SilverStripe\ORM\Tests\DataObjectTest\Player;
19
use SilverStripe\ORM\Tests\DataObjectTest\Sortable;
20
use SilverStripe\ORM\Tests\DataObjectTest\SubTeam;
21
use SilverStripe\ORM\Tests\DataObjectTest\Team;
22
use SilverStripe\ORM\Tests\DataObjectTest\TeamComment;
23
use SilverStripe\ORM\Tests\DataObjectTest\ValidatedObject;
24
use SilverStripe\ORM\Tests\DataObjectTest\Staff;
25
26
/**
27
 * @skipUpgrade
28
 */
29
class DataListTest extends SapphireTest
30
{
31
32
    // Borrow the model from DataObjectTest
33
    protected static $fixture_file = 'DataObjectTest.yml';
34
35
    public static function getExtraDataObjects()
36
    {
37
        return array_merge(
38
            DataObjectTest::$extra_data_objects,
39
            ManyManyListTest::$extra_data_objects
40
        );
41
    }
42
43
44
    public function testFilterDataObjectByCreatedDate()
45
    {
46
        // create an object to test with
47
        $obj1 = new ValidatedObject();
48
        $obj1->Name = 'test obj 1';
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\Tests\D...ectTest\ValidatedObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
49
        $obj1->write();
50
        $this->assertTrue($obj1->isInDB());
51
52
        // reload the object from the database and reset its Created timestamp to a known value
53
        $obj1 = ValidatedObject::get()->filter(array('Name' => 'test obj 1'))->first();
54
        $this->assertTrue(is_object($obj1));
55
        $this->assertEquals('test obj 1', $obj1->Name);
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
56
        $obj1->Created = '2013-01-01 00:00:00';
57
        $obj1->write();
58
59
        // reload the object again and make sure that our Created date was properly persisted
60
        $obj1 = ValidatedObject::get()->filter(array('Name' => 'test obj 1'))->first();
61
        $this->assertTrue(is_object($obj1));
62
        $this->assertEquals('test obj 1', $obj1->Name);
63
        $this->assertEquals('2013-01-01 00:00:00', $obj1->Created);
64
65
        // now save a second object to the DB with an automatically-set Created value
66
        $obj2 = new ValidatedObject();
67
        $obj2->Name = 'test obj 2';
68
        $obj2->write();
69
        $this->assertTrue($obj2->isInDB());
70
71
        // and a third object
72
        $obj3 = new ValidatedObject();
73
        $obj3->Name = 'test obj 3';
74
        $obj3->write();
75
        $this->assertTrue($obj3->isInDB());
76
77
        // now test the filtering based on Created timestamp
78
        $list = ValidatedObject::get()
79
            ->filter(array('Created:GreaterThan' => '2013-02-01 00:00:00'))
80
            ->toArray();
81
        $this->assertEquals(2, count($list));
82
    }
83
84
    public function testSubtract()
85
    {
86
        $comment1 = $this->objFromFixture(DataObjectTest\TeamComment::class, 'comment1');
87
        $subtractList = TeamComment::get()->filter('ID', $comment1->ID);
88
        $fullList = TeamComment::get();
89
        $newList = $fullList->subtract($subtractList);
90
        $this->assertEquals(2, $newList->Count(), 'List should only contain two objects after subtraction');
91
    }
92
93
    /**
94
     * @expectedException \InvalidArgumentException
95
     */
96
    public function testSubtractBadDataclassThrowsException()
97
    {
98
        $teamsComments = TeamComment::get();
99
        $teams = Team::get();
100
        $teamsComments->subtract($teams);
101
    }
102
103
    public function testListCreationSortAndLimit()
104
    {
105
        // By default, a DataList will contain all items of that class
106
        $list = TeamComment::get()->sort('ID');
107
108
        // We can iterate on the DataList
109
        $names = array();
110
        foreach ($list as $item) {
111
            $names[] = $item->Name;
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
112
        }
113
        $this->assertEquals(array('Joe', 'Bob', 'Phil'), $names);
114
115
        // If we don't want to iterate, we can extract a single column from the list with column()
116
        $this->assertEquals(array('Joe', 'Bob', 'Phil'), $list->column('Name'));
117
118
        // We can sort a list
119
        $list = $list->sort('Name');
120
        $this->assertEquals(array('Bob', 'Joe', 'Phil'), $list->column('Name'));
121
122
        // We can also restrict the output to a range
123
        $this->assertEquals(array('Joe', 'Phil'), $list->limit(2, 1)->column('Name'));
124
    }
125
126
    public function testLimitAndOffset()
127
    {
128
        $list = TeamComment::get();
129
        $check = $list->limit(3);
130
131
        $this->assertEquals(3, $check->count());
132
133
        $check = $list->limit(1);
134
        $this->assertEquals(1, $check->count());
135
136
        $check = $list->limit(1, 1);
137
        $this->assertEquals(1, $check->count());
138
139
        $check = $list->limit(false);
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type integer expected by parameter $limit of SilverStripe\ORM\DataList::limit(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

139
        $check = $list->limit(/** @scrutinizer ignore-type */ false);
Loading history...
140
        $this->assertEquals(3, $check->count());
141
142
        $check = $list->limit(null);
143
        $this->assertEquals(3, $check->count());
144
145
        $check = $list->limit(null, 2);
146
        $this->assertEquals(1, $check->count());
147
148
        // count()/first()/last() methods may alter limit/offset, so run the query and manually check the count
149
        $check = $list->limit(null, 1)->toArray();
150
        $this->assertEquals(2, count($check));
151
    }
152
153
    public function testDistinct()
154
    {
155
        $list = TeamComment::get();
156
        $this->assertContains(
157
            'SELECT DISTINCT',
158
            $list->dataQuery()->sql($params),
159
            'Query is set as distinct by default'
160
        );
161
162
        $list = $list->distinct(false);
163
        $this->assertNotContains(
164
            'SELECT DISTINCT',
165
            $list->dataQuery()->sql($params),
166
            'Query does not contain distinct'
167
        );
168
169
        $list = $list->distinct(true);
170
        $this->assertContains(
171
            'SELECT DISTINCT',
172
            $list->dataQuery()->sql($params),
173
            'Query contains distinct'
174
        );
175
    }
176
177
    public function testDataClass()
178
    {
179
        $list = TeamComment::get();
180
        $this->assertEquals(DataObjectTest\TeamComment::class, $list->dataClass());
181
    }
182
183
    public function testDataClassCaseInsensitive()
184
    {
185
        $list = DataList::create(strtolower(DataObjectTest\TeamComment::class));
186
        $this->assertTrue($list->exists());
187
    }
188
189
    public function testClone()
190
    {
191
        $list = TeamComment::get();
192
        $this->assertEquals($list, clone($list));
193
    }
194
195
    public function testSql()
196
    {
197
        $db = DB::get_conn();
198
        $list = TeamComment::get();
199
        $expected = 'SELECT DISTINCT "DataObjectTest_TeamComment"."ClassName", '
200
            . '"DataObjectTest_TeamComment"."LastEdited", "DataObjectTest_TeamComment"."Created", '
201
            . '"DataObjectTest_TeamComment"."Name", "DataObjectTest_TeamComment"."Comment", '
202
            . '"DataObjectTest_TeamComment"."TeamID", "DataObjectTest_TeamComment"."ID", '
203
            . 'CASE WHEN "DataObjectTest_TeamComment"."ClassName" IS NOT NULL '
204
            . 'THEN "DataObjectTest_TeamComment"."ClassName" ELSE '
205
            . $db->quoteString(DataObjectTest\TeamComment::class)
206
            . ' END AS "RecordClassName" FROM "DataObjectTest_TeamComment"'
207
            . ' ORDER BY "DataObjectTest_TeamComment"."Name" ASC';
208
        $this->assertSQLEquals($expected, $list->sql($parameters));
209
    }
210
211
    public function testInnerJoin()
212
    {
213
        $db = DB::get_conn();
214
215
        $list = TeamComment::get();
216
        $list = $list->innerJoin(
217
            'DataObjectTest_Team',
218
            '"DataObjectTest_Team"."ID" = "DataObjectTest_TeamComment"."TeamID"',
219
            'Team'
220
        );
221
222
        $expected = 'SELECT DISTINCT "DataObjectTest_TeamComment"."ClassName", '
223
            . '"DataObjectTest_TeamComment"."LastEdited", "DataObjectTest_TeamComment"."Created", '
224
            . '"DataObjectTest_TeamComment"."Name", "DataObjectTest_TeamComment"."Comment", '
225
            . '"DataObjectTest_TeamComment"."TeamID", "DataObjectTest_TeamComment"."ID", '
226
            . 'CASE WHEN "DataObjectTest_TeamComment"."ClassName" IS NOT NULL'
227
            . ' THEN "DataObjectTest_TeamComment"."ClassName" ELSE '
228
            . $db->quoteString(DataObjectTest\TeamComment::class)
229
            . ' END AS "RecordClassName" FROM "DataObjectTest_TeamComment" INNER JOIN '
230
            . '"DataObjectTest_Team" AS "Team" ON "DataObjectTest_Team"."ID" = '
231
            . '"DataObjectTest_TeamComment"."TeamID"'
232
            . ' ORDER BY "DataObjectTest_TeamComment"."Name" ASC';
233
234
235
        $this->assertSQLEquals($expected, $list->sql($parameters));
236
        $this->assertEmpty($parameters);
237
    }
238
239
    public function testInnerJoinParameterised()
240
    {
241
        $db = DB::get_conn();
242
243
        $list = TeamComment::get();
244
        $list = $list->innerJoin(
245
            'DataObjectTest_Team',
246
            '"DataObjectTest_Team"."ID" = "DataObjectTest_TeamComment"."TeamID" '
247
            . 'AND "DataObjectTest_Team"."Title" LIKE ?',
248
            'Team',
249
            20,
250
            array('Team%')
251
        );
252
253
        $expected = 'SELECT DISTINCT "DataObjectTest_TeamComment"."ClassName", '
254
            . '"DataObjectTest_TeamComment"."LastEdited", "DataObjectTest_TeamComment"."Created", '
255
            . '"DataObjectTest_TeamComment"."Name", "DataObjectTest_TeamComment"."Comment", '
256
            . '"DataObjectTest_TeamComment"."TeamID", "DataObjectTest_TeamComment"."ID", '
257
            . 'CASE WHEN "DataObjectTest_TeamComment"."ClassName" IS NOT NULL'
258
            . ' THEN "DataObjectTest_TeamComment"."ClassName" ELSE '
259
            . $db->quoteString(DataObjectTest\TeamComment::class)
260
            . ' END AS "RecordClassName" FROM "DataObjectTest_TeamComment" INNER JOIN '
261
            . '"DataObjectTest_Team" AS "Team" ON "DataObjectTest_Team"."ID" = '
262
            . '"DataObjectTest_TeamComment"."TeamID" '
263
            . 'AND "DataObjectTest_Team"."Title" LIKE ?'
264
            . ' ORDER BY "DataObjectTest_TeamComment"."Name" ASC';
265
266
        $this->assertSQLEquals($expected, $list->sql($parameters));
267
        $this->assertEquals(array('Team%'), $parameters);
268
    }
269
270
    public function testLeftJoin()
271
    {
272
        $db = DB::get_conn();
273
274
        $list = TeamComment::get();
275
        $list = $list->leftJoin(
276
            'DataObjectTest_Team',
277
            '"DataObjectTest_Team"."ID" = "DataObjectTest_TeamComment"."TeamID"',
278
            'Team'
279
        );
280
281
        $expected = 'SELECT DISTINCT "DataObjectTest_TeamComment"."ClassName", '
282
            . '"DataObjectTest_TeamComment"."LastEdited", "DataObjectTest_TeamComment"."Created", '
283
            . '"DataObjectTest_TeamComment"."Name", "DataObjectTest_TeamComment"."Comment", '
284
            . '"DataObjectTest_TeamComment"."TeamID", "DataObjectTest_TeamComment"."ID", '
285
            . 'CASE WHEN "DataObjectTest_TeamComment"."ClassName" IS NOT NULL '
286
            . 'THEN "DataObjectTest_TeamComment"."ClassName" ELSE '
287
            . $db->quoteString(DataObjectTest\TeamComment::class)
288
            . ' END AS "RecordClassName" FROM "DataObjectTest_TeamComment" LEFT JOIN "DataObjectTest_Team" '
289
            . 'AS "Team" ON "DataObjectTest_Team"."ID" = "DataObjectTest_TeamComment"."TeamID"'
290
            . ' ORDER BY "DataObjectTest_TeamComment"."Name" ASC';
291
292
293
        $this->assertSQLEquals($expected, $list->sql($parameters));
294
        $this->assertEmpty($parameters);
295
    }
296
297
    public function testLeftJoinParameterised()
298
    {
299
        $db = DB::get_conn();
300
301
        $list = TeamComment::get();
302
        $list = $list->leftJoin(
303
            'DataObjectTest_Team',
304
            '"DataObjectTest_Team"."ID" = "DataObjectTest_TeamComment"."TeamID" '
305
            . 'AND "DataObjectTest_Team"."Title" LIKE ?',
306
            'Team',
307
            20,
308
            array('Team%')
309
        );
310
311
        $expected = 'SELECT DISTINCT "DataObjectTest_TeamComment"."ClassName", '
312
            . '"DataObjectTest_TeamComment"."LastEdited", "DataObjectTest_TeamComment"."Created", '
313
            . '"DataObjectTest_TeamComment"."Name", "DataObjectTest_TeamComment"."Comment", '
314
            . '"DataObjectTest_TeamComment"."TeamID", "DataObjectTest_TeamComment"."ID", '
315
            . 'CASE WHEN "DataObjectTest_TeamComment"."ClassName" IS NOT NULL'
316
            . ' THEN "DataObjectTest_TeamComment"."ClassName" ELSE '
317
            . $db->quoteString(DataObjectTest\TeamComment::class)
318
            . ' END AS "RecordClassName" FROM "DataObjectTest_TeamComment" LEFT JOIN '
319
            . '"DataObjectTest_Team" AS "Team" ON "DataObjectTest_Team"."ID" = '
320
            . '"DataObjectTest_TeamComment"."TeamID" '
321
            . 'AND "DataObjectTest_Team"."Title" LIKE ?'
322
            . ' ORDER BY "DataObjectTest_TeamComment"."Name" ASC';
323
324
        $this->assertSQLEquals($expected, $list->sql($parameters));
325
        $this->assertEquals(array('Team%'), $parameters);
326
    }
327
328
    public function testToNestedArray()
329
    {
330
        $list = TeamComment::get()->sort('ID');
331
        $nestedArray = $list->toNestedArray();
332
        $expected = array(
333
            0=>
334
            array(
335
                'ClassName'=>DataObjectTest\TeamComment::class,
336
                'Name'=>'Joe',
337
                'Comment'=>'This is a team comment by Joe',
338
                'TeamID'=> $this->objFromFixture(DataObjectTest\TeamComment::class, 'comment1')->TeamID,
0 ignored issues
show
Bug Best Practice introduced by
The property TeamID does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
339
            ),
340
            1=>
341
            array(
342
                'ClassName'=>DataObjectTest\TeamComment::class,
343
                'Name'=>'Bob',
344
                'Comment'=>'This is a team comment by Bob',
345
                'TeamID'=> $this->objFromFixture(DataObjectTest\TeamComment::class, 'comment2')->TeamID,
346
            ),
347
            2=>
348
            array(
349
                'ClassName'=>DataObjectTest\TeamComment::class,
350
                'Name'=>'Phil',
351
                'Comment'=>'Phil is a unique guy, and comments on team2',
352
                'TeamID'=> $this->objFromFixture(DataObjectTest\TeamComment::class, 'comment3')->TeamID,
353
            ),
354
        );
355
        $this->assertEquals(3, count($nestedArray));
356
        $this->assertEquals($expected[0]['Name'], $nestedArray[0]['Name']);
357
        $this->assertEquals($expected[1]['Comment'], $nestedArray[1]['Comment']);
358
        $this->assertEquals($expected[2]['TeamID'], $nestedArray[2]['TeamID']);
359
    }
360
361
    public function testMap()
362
    {
363
        $map = TeamComment::get()->map()->toArray();
364
        $expected = array(
365
            $this->idFromFixture(DataObjectTest\TeamComment::class, 'comment1') => 'Joe',
366
            $this->idFromFixture(DataObjectTest\TeamComment::class, 'comment2') => 'Bob',
367
            $this->idFromFixture(DataObjectTest\TeamComment::class, 'comment3') => 'Phil'
368
        );
369
370
        $this->assertEquals($expected, $map);
371
        $otherMap = TeamComment::get()->map('Name', 'TeamID')->toArray();
372
        $otherExpected = array(
373
            'Joe' => $this->objFromFixture(DataObjectTest\TeamComment::class, 'comment1')->TeamID,
0 ignored issues
show
Bug Best Practice introduced by
The property TeamID does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
374
            'Bob' => $this->objFromFixture(DataObjectTest\TeamComment::class, 'comment2')->TeamID,
375
            'Phil' => $this->objFromFixture(DataObjectTest\TeamComment::class, 'comment3')->TeamID
376
        );
377
378
        $this->assertEquals($otherExpected, $otherMap);
379
    }
380
381
    public function testAmbiguousAggregate()
382
    {
383
        // Test that we avoid ambiguity error when a field exists on two joined tables
384
        // Fetch the sponsors in a round-about way to simulate this
385
        $teamID = $this->idFromFixture(DataObjectTest\Team::class, 'team2');
386
        $sponsors = EquipmentCompany::get()->filter('SponsoredTeams.ID', $teamID);
387
        $this->assertNotNull($sponsors->Max('ID'));
388
        $this->assertNotNull($sponsors->Min('ID'));
389
        $this->assertNotNull($sponsors->Avg('ID'));
390
        $this->assertNotNull($sponsors->Sum('ID'));
391
392
        // Test non-orm many_many_extraFields
393
        $company = $this->objFromFixture(EquipmentCompany::class, 'equipmentcompany1');
394
        $this->assertNotNull($company->SponsoredTeams()->Max('SponsorFee'));
0 ignored issues
show
Bug introduced by
The method SponsoredTeams() does not exist on SilverStripe\ORM\DataObject. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

394
        $this->assertNotNull($company->/** @scrutinizer ignore-call */ SponsoredTeams()->Max('SponsorFee'));
Loading history...
395
        $this->assertNotNull($company->SponsoredTeams()->Min('SponsorFee'));
396
        $this->assertNotNull($company->SponsoredTeams()->Avg('SponsorFee'));
397
        $this->assertNotNull($company->SponsoredTeams()->Sum('SponsorFee'));
398
    }
399
400
    public function testEach()
401
    {
402
        $list = TeamComment::get();
403
404
        $count = 0;
405
        $list->each(
406
            function ($item) use (&$count) {
407
                $count++;
408
                $this->assertInstanceOf(TeamComment::class, $item);
409
            }
410
        );
411
412
        $this->assertEquals($count, $list->count());
413
    }
414
415
    public function testWhere()
416
    {
417
        // We can use raw SQL queries with where.  This is only recommended for advanced uses;
418
        // if you can, you should use filter().
419
        $list = TeamComment::get();
420
421
        // where() returns a new DataList, like all the other modifiers, so it can be chained.
422
        $list2 = $list->where('"Name" = \'Joe\'');
423
        $this->assertEquals(array('This is a team comment by Joe'), $list2->column('Comment'));
424
425
        // The where() clauses are chained together with AND
426
        $list3 = $list2->where('"Name" = \'Bob\'');
427
        $this->assertEquals(array(), $list3->column('Comment'));
428
    }
429
430
    /**
431
     * Test DataList->byID()
432
     */
433
    public function testByID()
434
    {
435
        // We can get a single item by ID.
436
        $id = $this->idFromFixture(DataObjectTest\Team::class, 'team2');
437
        $team = Team::get()->byID($id);
438
439
        // byID() returns a DataObject, rather than a DataList
440
        $this->assertInstanceOf(DataObjectTest\Team::class, $team);
441
        $this->assertEquals('Team 2', $team->Title);
442
443
        // Assert that filtering on ID searches by the base table, not the child table field
444
        $query = SubTeam::get()->filter('ID', 4)->sql($parameters);
445
        $this->assertContains('WHERE ("DataObjectTest_Team"."ID" = ?)', $query);
446
        $this->assertNotContains('WHERE ("DataObjectTest_SubTeam"."ID" = ?)', $query);
447
    }
448
449
    public function testByIDs()
450
    {
451
        $knownIDs = $this->allFixtureIDs(DataObjectTest\Player::class);
452
        $removedID = array_pop($knownIDs);
453
        $filteredPlayers = Player::get()->byIDs($knownIDs);
454
        foreach ($filteredPlayers as $player) {
455
            $this->assertContains($player->ID, $knownIDs);
456
            $this->assertNotEquals($removedID, $player->ID);
457
        }
458
    }
459
460
    /**
461
     * Test DataList->removeByID()
462
     */
463
    public function testRemoveByID()
464
    {
465
        $list = Team::get();
466
        $id = $this->idFromFixture(DataObjectTest\Team::class, 'team2');
467
468
        $this->assertNotNull($list->byID($id));
469
        $list->removeByID($id);
470
        $this->assertNull($list->byID($id));
471
    }
472
473
    /**
474
     * Test DataList->canSortBy()
475
     */
476
    public function testCanSortBy()
477
    {
478
        // Basic check
479
        $team = Team::get();
480
        $this->assertTrue($team->canSortBy("Title"));
481
        $this->assertFalse($team->canSortBy("SomethingElse"));
482
483
        // Subclasses
484
        $subteam = SubTeam::get();
485
        $this->assertTrue($subteam->canSortBy("Title"));
486
        $this->assertTrue($subteam->canSortBy("SubclassDatabaseField"));
487
    }
488
489
    public function testDataListArrayAccess()
490
    {
491
        $list = Team::get()->sort('Title');
492
493
        // We can use array access to refer to single items in the DataList, as if it were an array
494
        $this->assertEquals("Subteam 1", $list[0]->Title);
495
        $this->assertEquals("Subteam 3", $list[2]->Title);
496
        $this->assertEquals("Team 2", $list[4]->Title);
497
    }
498
499
    public function testFind()
500
    {
501
        $list = Team::get();
502
        $record = $list->find('Title', 'Team 1');
503
        $this->assertEquals($this->idFromFixture(DataObjectTest\Team::class, 'team1'), $record->ID);
504
    }
505
506
    public function testFindById()
507
    {
508
        $list = Team::get();
509
        $record = $list->find('ID', $this->idFromFixture(DataObjectTest\Team::class, 'team1'));
510
        $this->assertEquals('Team 1', $record->Title);
511
        // Test that you can call it twice on the same list
512
        $record = $list->find('ID', $this->idFromFixture(DataObjectTest\Team::class, 'team2'));
513
        $this->assertEquals('Team 2', $record->Title);
514
    }
515
516
    public function testSimpleSort()
517
    {
518
        $list = TeamComment::get();
519
        $list = $list->sort('Name');
520
        $this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
521
        $this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
522
    }
523
524
    public function testSimpleSortOneArgumentASC()
525
    {
526
        $list = TeamComment::get();
527
        $list = $list->sort('Name ASC');
528
        $this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
529
        $this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
530
    }
531
532
    public function testSimpleSortOneArgumentDESC()
533
    {
534
        $list = TeamComment::get();
535
        $list = $list->sort('Name DESC');
536
        $this->assertEquals('Phil', $list->first()->Name, 'Last comment should be from Phil');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
537
        $this->assertEquals('Bob', $list->last()->Name, 'First comment should be from Bob');
538
    }
539
540
    public function testSortOneArgumentMultipleColumns()
541
    {
542
        $list = TeamComment::get();
543
        $list = $list->sort('TeamID ASC, Name DESC');
544
        $this->assertEquals('Joe', $list->first()->Name, 'First comment should be from Bob');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
545
        $this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
546
    }
547
548
    public function testSimpleSortASC()
549
    {
550
        $list = TeamComment::get();
551
        $list = $list->sort('Name', 'asc');
552
        $this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
553
        $this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
554
    }
555
556
    public function testSimpleSortDESC()
557
    {
558
        $list = TeamComment::get();
559
        $list = $list->sort('Name', 'desc');
560
        $this->assertEquals('Phil', $list->first()->Name, 'Last comment should be from Phil');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
561
        $this->assertEquals('Bob', $list->last()->Name, 'First comment should be from Bob');
562
    }
563
564
    public function testSortWithArraySyntaxSortASC()
565
    {
566
        $list = TeamComment::get();
567
        $list = $list->sort(array('Name'=>'asc'));
568
        $this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
569
        $this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
570
    }
571
572
    public function testSortWithArraySyntaxSortDESC()
573
    {
574
        $list = TeamComment::get();
575
        $list = $list->sort(array('Name'=>'desc'));
576
        $this->assertEquals('Phil', $list->first()->Name, 'Last comment should be from Phil');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
577
        $this->assertEquals('Bob', $list->last()->Name, 'First comment should be from Bob');
578
    }
579
580
    public function testSortWithMultipleArraySyntaxSort()
581
    {
582
        $list = TeamComment::get();
583
        $list = $list->sort(array('TeamID'=>'asc','Name'=>'desc'));
584
        $this->assertEquals('Joe', $list->first()->Name, 'First comment should be from Bob');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
585
        $this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
586
    }
587
588
    public function testSortWithCompositeSyntax()
589
    {
590
        // Phil commented on team with founder surname "Aaron"
591
        $list = TeamComment::get();
592
        $list = $list->sort('Team.Founder.Surname', 'asc');
593
        $this->assertEquals('Phil', $list->first()->Name);
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
594
        $list = $list->sort('Team.Founder.Surname', 'desc');
595
        $this->assertEquals('Phil', $list->last()->Name);
596
    }
597
598
    /**
599
     * @expectedException \InvalidArgumentException
600
     * @expectedExceptionMessage Fans is not a linear relation on model SilverStripe\ORM\Tests\DataObjectTest\Player
601
     */
602
    public function testSortInvalidParameters()
603
    {
604
        $list = Team::get();
605
        $list->sort('Founder.Fans.Surname'); // Can't sort on has_many
606
    }
607
608
    public function testSortNumeric()
609
    {
610
        $list = Sortable::get();
611
        $list1 = $list->sort('Sort', 'ASC');
612
        $this->assertEquals(
613
            array(
614
            -10,
615
            -2,
616
            -1,
617
            0,
618
            1,
619
            2,
620
            10
621
            ),
622
            $list1->column('Sort')
623
        );
624
    }
625
626
    public function testSortMixedCase()
627
    {
628
        $list = Sortable::get();
629
        $list1 = $list->sort('Name', 'ASC');
630
        $this->assertEquals(
631
            array(
632
            'Bob',
633
            'bonny',
634
            'jane',
635
            'John',
636
            'sam',
637
            'Steve',
638
            'steven'
639
            ),
640
            $list1->column('Name')
641
        );
642
    }
643
644
    /**
645
     * Test DataList->canFilterBy()
646
     */
647
    public function testCanFilterBy()
648
    {
649
        // Basic check
650
        $team = Team::get();
651
        $this->assertTrue($team->canFilterBy("Title"));
652
        $this->assertFalse($team->canFilterBy("SomethingElse"));
653
654
        // Has one
655
        $this->assertTrue($team->canFilterBy("CaptainID"));
656
        $this->assertTrue($team->canFilterBy("Captain.ShirtNumber"));
657
        $this->assertFalse($team->canFilterBy("SomethingElse.ShirtNumber"));
658
        $this->assertFalse($team->canFilterBy("Captain.SomethingElse"));
659
        $this->assertTrue($team->canFilterBy("Captain.FavouriteTeam.Captain.ShirtNumber"));
660
661
        // Has many
662
        $this->assertTrue($team->canFilterBy("Fans.Name"));
663
        $this->assertFalse($team->canFilterBy("SomethingElse.Name"));
664
        $this->assertFalse($team->canFilterBy("Fans.SomethingElse"));
665
666
        // Many many
667
        $this->assertTrue($team->canFilterBy("Players.FirstName"));
668
        $this->assertFalse($team->canFilterBy("SomethingElse.FirstName"));
669
        $this->assertFalse($team->canFilterBy("Players.SomethingElse"));
670
671
        // Subclasses
672
        $subteam = SubTeam::get();
673
        $this->assertTrue($subteam->canFilterBy("Title"));
674
        $this->assertTrue($subteam->canFilterBy("SubclassDatabaseField"));
675
    }
676
677
    /**
678
     * $list->filter('Name', 'bob'); // only bob in the list
679
     */
680
    public function testSimpleFilter()
681
    {
682
        $list = Team::get();
683
        $list = $list->filter('Title', 'Team 2');
684
        $this->assertEquals(1, $list->count());
685
        $this->assertEquals('Team 2', $list->first()->Title, 'List should only contain Team 2');
686
        $this->assertEquals('Team 2', $list->last()->Title, 'Last should only contain Team 2');
687
    }
688
689
    public function testSimpleFilterEndsWith()
690
    {
691
        $list = TeamComment::get();
692
        $list = $list->filter('Name:EndsWith', 'b');
693
        $this->assertEquals(1, $list->count());
694
        $this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
695
    }
696
697
    public function testSimpleFilterExactMatchFilter()
698
    {
699
        $list = TeamComment::get();
700
        $list = $list->filter('Name:ExactMatch', 'Bob');
701
        $this->assertEquals(1, $list->count());
702
        $this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
703
    }
704
705
    public function testSimpleFilterGreaterThanFilter()
706
    {
707
        $list = TeamComment::get();
708
        $list = $list->filter('TeamID:GreaterThan', $this->idFromFixture(DataObjectTest\Team::class, 'team1'));
709
        $this->assertEquals(1, $list->count());
710
        $this->assertEquals('Phil', $list->first()->Name, 'First comment should be from Phil');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
711
    }
712
713
    public function testSimpleFilterGreaterThanOrEqualFilter()
714
    {
715
        $list = TeamComment::get();
716
        $list = $list->filter(
717
            'TeamID:GreaterThanOrEqual',
718
            $this->idFromFixture(DataObjectTest\Team::class, 'team1')
719
        )->sort("ID");
720
        $this->assertEquals(3, $list->count());
721
        $this->assertEquals('Joe', $list->first()->Name, 'First comment should be from Joe');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
722
        $this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
723
    }
724
725
    public function testSimpleFilterLessThanFilter()
726
    {
727
        $list = TeamComment::get();
728
        $list = $list->filter(
729
            'TeamID:LessThan',
730
            $this->idFromFixture(DataObjectTest\Team::class, 'team2')
731
        )->sort('Name');
732
        $this->assertEquals(2, $list->count());
733
        $this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
734
        $this->assertEquals('Joe', $list->Last()->Name, 'Last comment should be from Joe');
735
    }
736
737
    public function testSimpleFilterLessThanOrEqualFilter()
738
    {
739
        $list = TeamComment::get();
740
        $list = $list->filter(
741
            'TeamID:LessThanOrEqual',
742
            $this->idFromFixture(DataObjectTest\Team::class, 'team1')
743
        )->sort('ID');
744
        $this->assertEquals(2, $list->count());
745
        $this->assertEquals('Joe', $list->first()->Name, 'First comment should be from Joe');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
746
        $this->assertEquals('Bob', $list->Last()->Name, 'Last comment should be from Bob');
747
    }
748
749
    public function testSimplePartialMatchFilter()
750
    {
751
        $list = TeamComment::get();
752
        $list = $list->filter('Name:PartialMatch', 'o')->sort('Name');
753
        $this->assertEquals(2, $list->count());
754
        $this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
755
        $this->assertEquals('Joe', $list->last()->Name, 'First comment should be from Joe');
756
    }
757
758
    public function testSimpleFilterStartsWith()
759
    {
760
        $list = TeamComment::get();
761
        $list = $list->filter('Name:StartsWith', 'B');
762
        $this->assertEquals(1, $list->count());
763
        $this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
764
    }
765
766
    /**
767
     * @expectedException \SilverStripe\Core\Injector\InjectorNotFoundException
768
     * @expectedExceptionMessage Class DataListFilter.Bogus does not exist
769
     */
770
    public function testSimpleFilterWithNonExistingComparisator()
771
    {
772
        $list = TeamComment::get();
773
        $list->filter('Comment:Bogus', 'team comment');
774
    }
775
776
    /**
777
     * Invalid modifiers are treated as failed filter construction
778
     *
779
     * @expectedException \SilverStripe\Core\Injector\InjectorNotFoundException
780
     * @expectedExceptionMessage Class DataListFilter.invalidmodifier does not exist
781
     */
782
    public function testInvalidModifier()
783
    {
784
        $list = TeamComment::get();
785
        $list->filter('Comment:invalidmodifier', 'team comment');
786
    }
787
788
    /**
789
     * $list->filter('Name', array('aziz', 'bob'); // aziz and bob in list
790
     */
791
    public function testSimpleFilterWithMultiple()
792
    {
793
        $list = TeamComment::get();
794
        $list = $list->filter('Name', array('Bob','Phil'));
795
        $list = $list->sort('Name', 'ASC');
796
        $this->assertEquals(2, $list->count());
797
        $this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
798
        $this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
799
    }
800
801
    public function testMultipleFilterWithNoMatch()
802
    {
803
        $list = TeamComment::get();
804
        $list = $list->filter(array('Name'=>'Bob', 'Comment'=>'Phil is a unique guy, and comments on team2'));
805
        $this->assertEquals(0, $list->count());
806
    }
807
808
    /**
809
     *  $list->filter(array('Name'=>'bob, 'Age'=>21)); // bob with the age 21
810
     */
811
    public function testFilterMultipleArray()
812
    {
813
        $list = TeamComment::get();
814
        $list = $list->filter(array('Name'=>'Bob', 'Comment'=>'This is a team comment by Bob'));
815
        $list = $list->sort('Name', 'ASC');
816
        $this->assertEquals(1, $list->count());
817
        $this->assertEquals('Bob', $list->first()->Name, 'Only comment should be from Bob');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
818
    }
819
820
    public function testFilterMultipleWithTwoMatches()
821
    {
822
        $list = TeamComment::get();
823
        $list = $list->filter(array('TeamID'=>$this->idFromFixture(DataObjectTest\Team::class, 'team1')));
824
        $this->assertEquals(2, $list->count());
825
    }
826
827
    public function testFilterMultipleWithArrayFilter()
828
    {
829
        $list = TeamComment::get();
830
        $list = $list->filter(array('Name'=>array('Bob','Phil')));
831
        $list = $list->sort('Name', 'ASC');
832
        $this->assertEquals(2, $list->count(), 'There should be two comments');
833
        $this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
834
        $this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
835
    }
836
837
    public function testFilterMultipleWithArrayFilterAndModifiers()
838
    {
839
        $list = TeamComment::get();
840
        $list = $list->filter(array('Name:StartsWith'=>array('Bo', 'Jo')));
841
        $list = $list->sort('Name', 'ASC');
842
        $this->assertEquals(2, $list->count());
843
        $this->assertEquals('Bob', $list->first()->Name);
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
844
        $this->assertEquals('Joe', $list->last()->Name);
845
    }
846
847
    /**
848
     * $list->filter(array('Name'=>array('aziz','bob'), 'Age'=>array(21, 43)));
849
     */
850
    public function testFilterArrayInArray()
851
    {
852
        $list = TeamComment::get();
853
        $list = $list->filter(
854
            array(
855
            'Name'=>array('Bob','Phil'),
856
            'TeamID'=>array($this->idFromFixture(DataObjectTest\Team::class, 'team1')))
857
        );
858
        $this->assertEquals(1, $list->count(), 'There should be one comment');
859
        $this->assertEquals('Bob', $list->first()->Name, 'Only comment should be from Bob');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
860
    }
861
862
    public function testFilterWithModifiers()
863
    {
864
        $list = TeamComment::get();
865
        $nocaseList = $list->filter('Name:nocase', 'bob');
866
        $this->assertEquals(1, $nocaseList->count(), 'There should be one comment');
867
        $caseList = $list->filter('Name:case', 'bob');
868
        $this->assertEquals(0, $caseList->count(), 'There should be no comments');
869
        $gtList = $list->filter(
870
            'TeamID:GreaterThan:not',
871
            $this->idFromFixture(DataObjectTest\Team::class, 'team1')
872
        );
873
        $this->assertEquals(2, $gtList->count());
874
    }
875
876
    /**
877
     * Test that a filter correctly aliases relationships that share common classes
878
     */
879
    public function testFilterSharedRelationalClasses()
880
    {
881
        /** @var Bracket $final1 */
882
        $final1 = $this->objFromFixture(Bracket::class, 'final');
883
        $prefinal1 = $this->objFromFixture(Bracket::class, 'prefinal1');
884
        $prefinal2 = $this->objFromFixture(Bracket::class, 'prefinal2');
885
        $semifinal1 = $this->objFromFixture(Bracket::class, 'semifinal1');
886
        $team2 = $this->objFromFixture(Team::class, 'team2');
887
888
        // grand child can be found from parent
889
        $found = Bracket::get()->filter('Next.Next.Title', $final1->Title);
890
        $this->assertListEquals(
891
            [['Title' => $semifinal1->Title]],
892
            $found
893
        );
894
895
        // grand child can be found from child
896
        $found = Bracket::get()->filter('Next.Title', $prefinal1->Title);
897
        $this->assertListEquals(
898
            [['Title' => $semifinal1->Title]],
899
            $found
900
        );
901
902
        // child can be found from parent
903
        $found = Bracket::get()->filter('Next.Title', $final1->Title);
904
        $this->assertListEquals(
905
            [
906
                ['Title' => $prefinal1->Title],
907
                ['Title' => $prefinal2->Title]
908
            ],
909
            $found
910
        );
911
912
        // Complex filter, get brackets where the following bracket was won by team 1
913
        // Note: Includes results from multiple levels
914
        $found = Bracket::get()->filter('Next.Winner.Title', $team2->Title);
915
        $this->assertListEquals(
916
            [
917
                ['Title' => $prefinal1->Title],
918
                ['Title' => $prefinal2->Title],
919
                ['Title' => $semifinal1->Title]
920
            ],
921
            $found
922
        );
923
    }
924
925
    public function testFilterOnImplicitJoinWithSharedInheritance()
926
    {
927
        $list = DataObjectTest\RelationChildFirst::get()->filter(array(
928
            'ManyNext.ID' => array(
929
                $this->idFromFixture(DataObjectTest\RelationChildSecond::class, 'test1'),
930
                $this->idFromFixture(DataObjectTest\RelationChildSecond::class, 'test2'),
931
            ),
932
        ));
933
        $this->assertEquals(2, $list->count());
934
        $ids = $list->column('ID');
935
        $this->assertContains($this->idFromFixture(DataObjectTest\RelationChildFirst::class, 'test1'), $ids);
936
        $this->assertContains($this->idFromFixture(DataObjectTest\RelationChildFirst::class, 'test2'), $ids);
937
    }
938
939
    public function testFilterAny()
940
    {
941
        $list = TeamComment::get();
942
        $list = $list->filterAny('Name', 'Bob');
943
        $this->assertEquals(1, $list->count());
944
    }
945
946
    public function testFilterAnyWithRelation()
947
    {
948
        $list = Player::get();
949
        $list = $list->filterAny(array(
950
            'Teams.Title:StartsWith' => 'Team',
951
            'ID:GreaterThan' => 0,
952
        ));
953
        $this->assertCount(4, $list);
954
    }
955
956
    public function testFilterAnyWithTwoGreaterThanFilters()
957
    {
958
959
        for ($i=1; $i<=3; $i++) {
960
            $f = new Fixture();
961
            $f->MyDecimal = $i;
0 ignored issues
show
Bug Best Practice introduced by
The property MyDecimal does not exist on SilverStripe\ORM\Tests\DataObjectTest\Fixture. Since you implemented __set, consider adding a @property annotation.
Loading history...
962
            $f->write();
963
964
            $f = new Fixture();
965
            $f->MyInt = $i;
0 ignored issues
show
Bug Best Practice introduced by
The property MyInt does not exist on SilverStripe\ORM\Tests\DataObjectTest\Fixture. Since you implemented __set, consider adding a @property annotation.
Loading history...
966
            $f->write();
967
        }
968
969
        $list = Fixture::get()->filterAny([
970
            'MyDecimal:GreaterThan' => 1, // 2 records
971
            'MyInt:GreaterThan' => 2, // 1 record
972
        ]);
973
974
        $this->assertCount(3, $list);
975
    }
976
977
    public function testFilterAnyMultipleArray()
978
    {
979
        $list = TeamComment::get();
980
        $list = $list->filterAny(array('Name'=>'Bob', 'Comment'=>'This is a team comment by Bob'));
981
        $this->assertEquals(1, $list->count());
982
        $this->assertEquals('Bob', $list->first()->Name, 'Only comment should be from Bob');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
983
    }
984
985
    public function testFilterAnyOnFilter()
986
    {
987
        $list = TeamComment::get();
988
        $list = $list->filter(
989
            array(
990
            'TeamID'=>$this->idFromFixture(DataObjectTest\Team::class, 'team1')
991
            )
992
        );
993
        $list = $list->filterAny(
994
            array(
995
            'Name'=>array('Phil', 'Joe'),
996
            'Comment'=>'This is a team comment by Bob'
997
            )
998
        );
999
        $list = $list->sort('Name');
1000
        $this->assertEquals(2, $list->count());
1001
        $this->assertEquals(
1002
            'Bob',
1003
            $list->offsetGet(0)->Name,
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
1004
            'Results should include comments from Bob, matched by comment and team'
1005
        );
1006
        $this->assertEquals(
1007
            'Joe',
1008
            $list->offsetGet(1)->Name,
1009
            'Results should include comments by Joe, matched by name and team (not by comment)'
1010
        );
1011
1012
        $list = TeamComment::get();
1013
        $list = $list->filter(
1014
            array(
1015
            'TeamID'=>$this->idFromFixture(DataObjectTest\Team::class, 'team1')
1016
            )
1017
        );
1018
        $list = $list->filterAny(
1019
            array(
1020
            'Name'=>array('Phil', 'Joe'),
1021
            'Comment'=>'This is a team comment by Bob'
1022
            )
1023
        );
1024
        $list = $list->sort('Name');
1025
        $list = $list->filter(array('Name' => 'Bob'));
1026
        $this->assertEquals(1, $list->count());
1027
        $this->assertEquals(
1028
            'Bob',
1029
            $list->offsetGet(0)->Name,
1030
            'Results should include comments from Bob, matched by name and team'
1031
        );
1032
    }
1033
1034
    public function testFilterAnyMultipleWithArrayFilter()
1035
    {
1036
        $list = TeamComment::get();
1037
        $list = $list->filterAny(array('Name'=>array('Bob','Phil')));
1038
        $this->assertEquals(2, $list->count(), 'There should be two comments');
1039
        $this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
1040
        $this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
1041
    }
1042
1043
    public function testFilterAnyArrayInArray()
1044
    {
1045
        $list = TeamComment::get();
1046
        $list = $list->filterAny(
1047
            array(
1048
            'Name'=>array('Bob','Phil'),
1049
            'TeamID'=>array($this->idFromFixture(DataObjectTest\Team::class, 'team1')))
1050
        )
1051
            ->sort('Name');
1052
        $this->assertEquals(3, $list->count());
1053
        $this->assertEquals(
1054
            'Bob',
1055
            $list->offsetGet(0)->Name,
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
1056
            'Results should include comments from Bob, matched by name and team'
1057
        );
1058
        $this->assertEquals(
1059
            'Joe',
1060
            $list->offsetGet(1)->Name,
1061
            'Results should include comments by Joe, matched by team (not by name)'
1062
        );
1063
        $this->assertEquals(
1064
            'Phil',
1065
            $list->offsetGet(2)->Name,
1066
            'Results should include comments from Phil, matched by name (even if he\'s not in Team1)'
1067
        );
1068
    }
1069
1070
    public function testFilterOnJoin()
1071
    {
1072
        $list = TeamComment::get()
1073
            ->leftJoin(
1074
                'DataObjectTest_Team',
1075
                '"DataObjectTest_Team"."ID" = "DataObjectTest_TeamComment"."TeamID"'
1076
            )->filter(
1077
                array(
1078
                'Title' => 'Team 1'
1079
                )
1080
            );
1081
1082
        $this->assertEquals(2, $list->count());
1083
        $values = $list->column('Name');
1084
        $this->assertEquals(array_intersect($values, array('Joe', 'Bob')), $values);
1085
    }
1086
1087
    public function testFilterOnImplicitJoin()
1088
    {
1089
        // Many to many
1090
        $list = Team::get()
1091
            ->filter('Players.FirstName', array('Captain', 'Captain 2'));
1092
1093
        $this->assertEquals(2, $list->count());
1094
1095
        // Has many
1096
        $list = Team::get()
1097
            ->filter('Comments.Name', array('Joe', 'Phil'));
1098
1099
        $this->assertEquals(2, $list->count());
1100
1101
        // Has one
1102
        $list = Player::get()
1103
            ->filter('FavouriteTeam.Title', 'Team 1');
1104
1105
        $this->assertEquals(1, $list->count());
1106
        $this->assertEquals('007', $list->first()->ShirtNumber);
0 ignored issues
show
Bug Best Practice introduced by
The property ShirtNumber does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
1107
    }
1108
1109
    /**
1110
     * @expectedException \InvalidArgumentException
1111
     * @expectedExceptionMessage MascotAnimal is not a relation on model SilverStripe\ORM\Tests\DataObjectTest\Team
1112
     */
1113
    public function testFilterOnInvalidRelation()
1114
    {
1115
        // Filter on missing relation 'MascotAnimal'
1116
        Team::get()
1117
            ->filter('MascotAnimal.Name', 'Richard')
1118
            ->toArray();
1119
    }
1120
1121
    public function testFilterAndExcludeById()
1122
    {
1123
        $id = $this->idFromFixture(SubTeam::class, 'subteam1');
1124
        $list = SubTeam::get()->filter('ID', $id);
1125
        $this->assertEquals($id, $list->first()->ID);
1126
1127
        $list = SubTeam::get();
1128
        $this->assertEquals(3, count($list));
1129
        $this->assertEquals(2, count($list->exclude('ID', $id)));
1130
    }
1131
1132
    /**
1133
     * @skipUpgrade
1134
     */
1135
    public function testFilterByNull()
1136
    {
1137
        $list = Fan::get();
1138
        // Force DataObjectTest_Fan/fan5::Email to empty string
1139
        $fan5id = $this->idFromFixture(Fan::class, 'fan5');
1140
        DB::prepared_query("UPDATE \"DataObjectTest_Fan\" SET \"Email\" = '' WHERE \"ID\" = ?", array($fan5id));
1141
1142
        // Filter by null email
1143
        $nullEmails = $list->filter('Email', null);
1144
        $this->assertListEquals(
1145
            array(
1146
            array(
1147
                'Name' => 'Stephen',
1148
            ),
1149
            array(
1150
                'Name' => 'Mitch',
1151
            )
1152
            ),
1153
            $nullEmails
1154
        );
1155
1156
        // Filter by non-null
1157
        $nonNullEmails = $list->filter('Email:not', null);
1158
        $this->assertListEquals(
1159
            array(
1160
            array(
1161
                'Name' => 'Damian',
1162
                'Email' => '[email protected]',
1163
            ),
1164
            array(
1165
                'Name' => 'Richard',
1166
                'Email' => '[email protected]',
1167
            ),
1168
            array(
1169
                'Name' => 'Hamish',
1170
            )
1171
            ),
1172
            $nonNullEmails
1173
        );
1174
1175
        // Filter by empty only
1176
        $emptyOnly = $list->filter('Email', '');
1177
        $this->assertListEquals(
1178
            array(
1179
            array(
1180
                'Name' => 'Hamish',
1181
            )
1182
            ),
1183
            $emptyOnly
1184
        );
1185
1186
        // Non-empty only. This should include null values, since ExactMatchFilter works around
1187
        // the caveat that != '' also excludes null values in ANSI SQL-92 behaviour.
1188
        $nonEmptyOnly = $list->filter('Email:not', '');
1189
        $this->assertListEquals(
1190
            array(
1191
            array(
1192
                'Name' => 'Damian',
1193
                'Email' => '[email protected]',
1194
            ),
1195
            array(
1196
                'Name' => 'Richard',
1197
                'Email' => '[email protected]',
1198
            ),
1199
            array(
1200
                'Name' => 'Stephen',
1201
            ),
1202
            array(
1203
                'Name' => 'Mitch',
1204
            )
1205
            ),
1206
            $nonEmptyOnly
1207
        );
1208
1209
        // Filter by many including null, empty string, and non-empty
1210
        $items1 = $list->filter('Email', array(null, '', '[email protected]'));
1211
        $this->assertListEquals(
1212
            array(
1213
            array(
1214
                'Name' => 'Damian',
1215
                'Email' => '[email protected]',
1216
            ),
1217
            array(
1218
                'Name' => 'Stephen',
1219
            ),
1220
            array(
1221
                'Name' => 'Mitch',
1222
            ),
1223
            array(
1224
                'Name' => 'Hamish',
1225
            )
1226
            ),
1227
            $items1
1228
        );
1229
1230
        // Filter exclusion of above list
1231
        $items2 = $list->filter('Email:not', array(null, '', '[email protected]'));
1232
        $this->assertListEquals(
1233
            array(
1234
            array(
1235
                'Name' => 'Richard',
1236
                'Email' => '[email protected]',
1237
            ),
1238
            ),
1239
            $items2
1240
        );
1241
1242
        // Filter by many including empty string and non-empty
1243
        $items3 = $list->filter('Email', array('', '[email protected]'));
1244
        $this->assertListEquals(
1245
            array(
1246
            array(
1247
                'Name' => 'Damian',
1248
                'Email' => '[email protected]',
1249
            ),
1250
            array(
1251
                'Name' => 'Hamish',
1252
            )
1253
            ),
1254
            $items3
1255
        );
1256
1257
        // Filter by many including empty string and non-empty
1258
        // This also relies no the workaround for null comparison as in the $nonEmptyOnly test
1259
        $items4 = $list->filter('Email:not', array('', '[email protected]'));
1260
        $this->assertListEquals(
1261
            array(
1262
            array(
1263
                'Name' => 'Richard',
1264
                'Email' => '[email protected]',
1265
            ),
1266
            array(
1267
                'Name' => 'Stephen',
1268
            ),
1269
            array(
1270
                'Name' => 'Mitch',
1271
            )
1272
            ),
1273
            $items4
1274
        );
1275
1276
        // Filter by many including empty string and non-empty
1277
        // The extra null check isn't necessary, but check that this doesn't fail
1278
        $items5 = $list->filterAny(
1279
            array(
1280
            'Email:not' => array('', '[email protected]'),
1281
            'Email' => null
1282
            )
1283
        );
1284
        $this->assertListEquals(
1285
            array(
1286
            array(
1287
                'Name' => 'Richard',
1288
                'Email' => '[email protected]',
1289
            ),
1290
            array(
1291
                'Name' => 'Stephen',
1292
            ),
1293
            array(
1294
                'Name' => 'Mitch',
1295
            )
1296
            ),
1297
            $items5
1298
        );
1299
1300
        // Filter by null or empty values
1301
        $items6 = $list->filter('Email', array(null, ''));
1302
        $this->assertListEquals(
1303
            array(
1304
            array(
1305
                'Name' => 'Stephen',
1306
            ),
1307
            array(
1308
                'Name' => 'Mitch',
1309
            ),
1310
            array(
1311
                'Name' => 'Hamish',
1312
            )
1313
            ),
1314
            $items6
1315
        );
1316
    }
1317
1318
    /**
1319
     * Test null checks with case modifiers
1320
     */
1321
    public function testFilterByNullCase()
1322
    {
1323
        // Test with case (case/nocase both use same code path)
1324
        // Test with and without null, and with inclusion/exclusion permutations
1325
        $list = Fan::get();
1326
1327
        // Only an explicit NOT NULL should include null values
1328
        $items6 = $list->filter('Email:not:case', array(null, '', '[email protected]'));
1329
        $this->assertSQLContains(' AND "DataObjectTest_Fan"."Email" IS NOT NULL', $items6->sql());
1330
1331
        // These should all include values where Email IS NULL
1332
        $items7 = $list->filter('Email:nocase', array(null, '', '[email protected]'));
1333
        $this->assertSQLContains(' OR "DataObjectTest_Fan"."Email" IS NULL', $items7->sql());
1334
        $items8 = $list->filter('Email:not:case', array('', '[email protected]'));
1335
        $this->assertSQLContains(' OR "DataObjectTest_Fan"."Email" IS NULL', $items8->sql());
1336
1337
        // These should not contain any null checks at all
1338
        $items9 = $list->filter('Email:nocase', array('', '[email protected]'));
1339
        $this->assertSQLNotContains('"DataObjectTest_Fan"."Email" IS NULL', $items9->sql());
1340
        $this->assertSQLNotContains('"DataObjectTest_Fan"."Email" IS NOT NULL', $items9->sql());
1341
    }
1342
1343
    public function testAggregateDBName()
1344
    {
1345
        $filter = new ExactMatchFilter(
1346
            'Comments.Count()'
1347
        );
1348
        $filter->apply(new DataQuery(DataObjectTest\Team::class));
1349
        $this->assertEquals('COUNT("comments_DataObjectTest_TeamComment"."ID")', $filter->getDBName());
1350
1351
        foreach (['Comments.Max(ID)', 'Comments.Max( ID )', 'Comments.Max(  ID)'] as $name) {
1352
            $filter = new ExactMatchFilter($name);
1353
            $filter->apply(new DataQuery(DataObjectTest\Team::class));
1354
            $this->assertEquals('MAX("comments_DataObjectTest_TeamComment"."ID")', $filter->getDBName());
1355
        }
1356
    }
1357
1358
    public function testAggregateFilterExceptions()
1359
    {
1360
        $ex = null;
1361
        try {
1362
            $filter = new ExactMatchFilter('Comments.Max( This will not parse! )');
0 ignored issues
show
Unused Code introduced by
The assignment to $filter is dead and can be removed.
Loading history...
1363
        } catch (\Exception $e) {
1364
            $ex = $e;
1365
        }
1366
        $this->assertInstanceOf(\InvalidArgumentException::class, $ex);
1367
        $this->assertRegExp('/Malformed/', $ex->getMessage());
0 ignored issues
show
Bug introduced by
The method getMessage() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1367
        $this->assertRegExp('/Malformed/', $ex->/** @scrutinizer ignore-call */ getMessage());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1368
1369
1370
        $filter = new ExactMatchFilter('Comments.Max(NonExistentColumn)');
1371
        $filter->setModel(new DataObjectTest\Team());
1372
        $ex = null;
1373
        try {
1374
            $name = $filter->getDBName();
0 ignored issues
show
Unused Code introduced by
The assignment to $name is dead and can be removed.
Loading history...
1375
        } catch (\Exception $e) {
1376
            $ex = $e;
1377
        }
1378
        $this->assertInstanceOf(\InvalidArgumentException::class, $ex);
1379
        $this->assertRegExp('/Invalid column/', $ex->getMessage());
1380
    }
1381
1382
    public function testAggregateFilters()
1383
    {
1384
        $teams = Team::get()->filter('Comments.Count()', 2);
1385
1386
        $team1 = $this->objFromFixture(Team::class, 'team1');
1387
        $team2 = $this->objFromFixture(Team::class, 'team2');
1388
        $team3 = $this->objFromFixture(Team::class, 'team3');
1389
        $team4 = $this->objFromFixture(SubTeam::class, 'subteam1');
1390
        $team5 = $this->objFromFixture(SubTeam::class, 'subteam2_with_player_relation');
1391
        $team6 = $this->objFromFixture(SubTeam::class, 'subteam3_with_empty_fields');
1392
1393
        $company1 = $this->objFromFixture(EquipmentCompany::class, 'equipmentcompany1');
1394
        $company2 = $this->objFromFixture(EquipmentCompany::class, 'equipmentcompany2');
1395
1396
        $company1->CurrentStaff()->add(Staff::create(['Salary' => 3])->write());
0 ignored issues
show
Bug introduced by
The method CurrentStaff() does not exist on SilverStripe\ORM\DataObject. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1396
        $company1->/** @scrutinizer ignore-call */ 
1397
                   CurrentStaff()->add(Staff::create(['Salary' => 3])->write());
Loading history...
1397
        $company1->CurrentStaff()->add(Staff::create(['Salary' => 5])->write());
1398
        $company2->CurrentStaff()->add(Staff::create(['Salary' => 4])->write());
1399
1400
        $this->assertCount(1, $teams);
1401
        $this->assertEquals($team1->ID, $teams->first()->ID);
1402
1403
        $teams = Team::get()->filter('Comments.Count()', [1,2]);
1404
1405
        $this->assertCount(2, $teams);
1406
        foreach ([$team1, $team2] as $expectedTeam) {
1407
            $this->assertContains($expectedTeam->ID, $teams->column('ID'));
1408
        }
1409
1410
        $teams = Team::get()->filter('Comments.Count():GreaterThan', 1);
1411
1412
        $this->assertCount(1, $teams);
1413
        $this->assertContains(
1414
            $this->objFromFixture(Team::class, 'team1')->ID,
1415
            $teams->column('ID')
1416
        );
1417
1418
        $teams = Team::get()->filter('Comments.Count():LessThan', 2);
1419
1420
        $this->assertCount(5, $teams);
1421
        foreach ([$team2, $team3, $team4, $team5, $team6] as $expectedTeam) {
1422
            $this->assertContains($expectedTeam->ID, $teams->column('ID'));
1423
        }
1424
1425
        $teams = Team::get()->filter('Comments.Count():GreaterThanOrEqual', 1);
1426
1427
        $this->assertCount(2, $teams);
1428
        foreach ([$team1, $team2] as $expectedTeam) {
1429
            $this->assertContains($expectedTeam->ID, $teams->column('ID'));
1430
        }
1431
1432
        $teams = Team::get()->filter('Comments.Count():LessThanOrEqual', 1);
1433
1434
        $this->assertCount(5, $teams);
1435
        foreach ([$team2, $team3, $team4, $team5, $team6] as $expectedTeam) {
1436
            $this->assertContains($expectedTeam->ID, $teams->column('ID'));
1437
        }
1438
1439
        $companies = EquipmentCompany::get()->filter('CurrentStaff.Max(Salary)', 5);
1440
        $this->assertCount(1, $companies);
1441
        $this->assertEquals($company1->ID, $companies->first()->ID);
1442
1443
        $companies = EquipmentCompany::get()->filter('CurrentStaff.Min(Salary)', 3);
1444
        $this->assertCount(1, $companies);
1445
        $this->assertEquals($company1->ID, $companies->first()->ID);
1446
1447
        $companies = EquipmentCompany::get()->filter('CurrentStaff.Max(Salary):GreaterThan', 3);
1448
        $this->assertCount(2, $companies);
1449
        foreach ([$company1, $company2] as $expectedTeam) {
1450
            $this->assertContains($expectedTeam->ID, $companies->column('ID'));
1451
        }
1452
1453
        $companies = EquipmentCompany::get()->filter('CurrentStaff.Sum(Salary)', 8);
1454
        $this->assertCount(1, $companies);
1455
        $this->assertEquals($company1->ID, $companies->first()->ID);
1456
1457
        $companies = EquipmentCompany::get()->filter('CurrentStaff.Sum(Salary):LessThan', 7);
1458
        $this->assertCount(1, $companies);
1459
        $this->assertEquals($company2->ID, $companies->first()->ID);
1460
1461
        $companies = EquipmentCompany::get()->filter('CurrentStaff.Sum(Salary):GreaterThan', 100);
1462
        $this->assertCount(0, $companies);
1463
1464
        $companies = EquipmentCompany::get()->filter('CurrentStaff.Sum(Salary):GreaterThan', 7);
1465
        $this->assertCount(1, $companies);
1466
        $this->assertEquals($company1->ID, $companies->first()->ID);
1467
1468
        $companies = EquipmentCompany::get()->filter('CurrentStaff.Avg(Salary)', 4);
1469
        $this->assertCount(2, $companies);
1470
        foreach ([$company1, $company2] as $expectedTeam) {
1471
            $this->assertContains($expectedTeam->ID, $companies->column('ID'));
1472
        }
1473
1474
        $companies = EquipmentCompany::get()->filter('CurrentStaff.Avg(Salary):LessThan', 10);
1475
        $this->assertCount(2, $companies);
1476
        foreach ([$company1, $company2] as $expectedTeam) {
1477
            $this->assertContains($expectedTeam->ID, $companies->column('ID'));
1478
        }
1479
    }
1480
1481
    /**
1482
     * $list = $list->filterByCallback(function($item, $list) { return $item->Age == 21; })
1483
     */
1484
    public function testFilterByCallback()
1485
    {
1486
        $team1ID = $this->idFromFixture(DataObjectTest\Team::class, 'team1');
1487
        $list = TeamComment::get();
1488
        $list = $list->filterByCallback(
1489
            function ($item, $list) use ($team1ID) {
0 ignored issues
show
Unused Code introduced by
The parameter $list is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1489
            function ($item, /** @scrutinizer ignore-unused */ $list) use ($team1ID) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1490
                return $item->TeamID == $team1ID;
1491
            }
1492
        );
1493
1494
        $result = $list->column('Name');
1495
        $expected = array_intersect($result, array('Joe', 'Bob'));
1496
1497
        $this->assertEquals(2, $list->count());
1498
        $this->assertEquals($expected, $result, 'List should only contain comments from Team 1 (Joe and Bob)');
1499
        $this->assertTrue($list instanceof Filterable, 'The List should be of type SS_Filterable');
1500
    }
1501
1502
    /**
1503
     * $list->exclude('Name', 'bob'); // exclude bob from list
1504
     */
1505
    public function testSimpleExclude()
1506
    {
1507
        $list = TeamComment::get();
1508
        $list = $list->exclude('Name', 'Bob');
1509
        $list = $list->sort('Name');
1510
        $this->assertEquals(2, $list->count());
1511
        $this->assertEquals('Joe', $list->first()->Name, 'First comment should be from Joe');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
1512
        $this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
1513
    }
1514
    //
1515
    /**
1516
     * $list->exclude('Name', array('aziz', 'bob'); // exclude aziz and bob from list
1517
     */
1518
    public function testSimpleExcludeWithMultiple()
1519
    {
1520
        $list = TeamComment::get();
1521
        $list = $list->exclude('Name', array('Joe','Phil'));
1522
        $this->assertEquals(1, $list->count());
1523
        $this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
1524
    }
1525
1526
    /**
1527
     * $list->exclude(array('Name'=>'bob, 'Age'=>21)); // negative version
1528
     */
1529
    public function testMultipleExcludeWithMiss()
1530
    {
1531
        $list = TeamComment::get();
1532
        $list = $list->exclude(array('Name'=>'Bob', 'Comment'=>'Does not match any comments'));
1533
        $this->assertEquals(3, $list->count());
1534
    }
1535
1536
    /**
1537
     * $list->exclude(array('Name'=>'bob, 'Age'=>21)); // exclude bob that has Age 21
1538
     */
1539
    public function testMultipleExclude()
1540
    {
1541
        $list = TeamComment::get();
1542
        $list = $list->exclude(array('Name'=>'Bob', 'Comment'=>'This is a team comment by Bob'));
1543
        $this->assertEquals(2, $list->count());
1544
    }
1545
1546
    /**
1547
     * Test doesn't exclude if only matches one
1548
     * $list->exclude(array('Name'=>'bob, 'Age'=>21)); // exclude bob that has Age 21
1549
     */
1550
    public function testMultipleExcludeMultipleMatches()
1551
    {
1552
        $list = TeamComment::get();
1553
        $list = $list->exclude(array('Name'=>'Bob', 'Comment'=>'Phil is a unique guy, and comments on team2'));
1554
        $this->assertCount(3, $list);
1555
    }
1556
1557
    /**
1558
     * // exclude only those that match both
1559
     */
1560
    public function testMultipleExcludeArraysMultipleMatches()
1561
    {
1562
        $list = TeamComment::get();
1563
        $list = $list->exclude(array(
1564
            'Name'=> array('Bob', 'Phil'),
1565
            'Comment'=> array(
1566
                'This is a team comment by Bob',
1567
                'Phil is a unique guy, and comments on team2'
1568
            )
1569
        ));
1570
        $this->assertListEquals([['Name' => 'Joe']], $list);
1571
    }
1572
1573
    /**
1574
     * Exclude only which matches both params
1575
     */
1576
    public function testMultipleExcludeArraysMultipleMatchesOneMiss()
1577
    {
1578
        $list = TeamComment::get();
1579
        $list = $list->exclude(array(
1580
            'Name' => array('Bob', 'Phil'),
1581
            'Comment' => array(
1582
                'Does not match any comments',
1583
                'Phil is a unique guy, and comments on team2'
1584
            )
1585
        ));
1586
        $list = $list->sort('Name');
1587
        $this->assertListEquals(
1588
            [
1589
                ['Name' => 'Bob'],
1590
                ['Name' => 'Joe'],
1591
            ],
1592
            $list
1593
        );
1594
    }
1595
1596
    /**
1597
     * Test that if an exclude() is applied to a filter(), the filter() is still preserved.
1598
     */
1599
    public function testExcludeOnFilter()
1600
    {
1601
        $list = TeamComment::get();
1602
        $list = $list->filter('Comment', 'Phil is a unique guy, and comments on team2');
1603
        $list = $list->exclude('Name', 'Bob');
1604
1605
        $sql = $list->sql($parameters);
1606
        $this->assertSQLContains(
1607
            'WHERE ("DataObjectTest_TeamComment"."Comment" = ?) AND (("DataObjectTest_TeamComment"."Name" != ? '
1608
            . 'OR "DataObjectTest_TeamComment"."Name" IS NULL))',
1609
            $sql
1610
        );
1611
        $this->assertEquals(array('Phil is a unique guy, and comments on team2', 'Bob'), $parameters);
1612
        $this->assertListEquals([['Name' => 'Phil']], $list);
1613
    }
1614
1615
    /**
1616
     * Test that if a complicated exclude() is applied to a filter(), the filter() is still preserved.
1617
     */
1618
    public function testComplicatedExcludeOnFilter()
1619
    {
1620
        $list = TeamComment::get();
1621
        $list = $list->filter('Name', array('Phil', 'Bob'));
1622
        $list = $list->exclude('Name', array('Bob', 'Joe'));
1623
1624
        $sql = $list->sql($parameters);
1625
        $this->assertSQLContains(
1626
            'WHERE ("DataObjectTest_TeamComment"."Name" IN (?, ?)) '
1627
            . 'AND (("DataObjectTest_TeamComment"."Name" NOT IN (?, ?) '
1628
            . 'OR "DataObjectTest_TeamComment"."Name" IS NULL))',
1629
            $sql
1630
        );
1631
        $this->assertEquals(array('Phil', 'Bob', 'Bob', 'Joe'), $parameters);
1632
        $this->assertListEquals([['Name' => 'Phil']], $list);
1633
    }
1634
1635
    /**
1636
     * Test that if a very complicated exclude() is applied to a filter(), the filter() is still preserved.
1637
     */
1638
    public function testVeryComplicatedExcludeOnFilter()
1639
    {
1640
        $list = TeamComment::get();
1641
        $list = $list->filter('Name', array('Phil', 'Bob'));
1642
        $list = $list->exclude(array(
1643
            'Name' => array('Joe', 'Phil'),
1644
            'Comment' => array('Matches no comments', 'Not a matching comment')
1645
        ));
1646
1647
        $sql = $list->sql($parameters);
1648
        $this->assertSQLContains(
1649
            'WHERE ("DataObjectTest_TeamComment"."Name" IN (?, ?)) '
1650
            . 'AND (("DataObjectTest_TeamComment"."Name" NOT IN (?, ?) '
1651
            . 'OR "DataObjectTest_TeamComment"."Name" IS NULL) '
1652
            . 'OR ("DataObjectTest_TeamComment"."Comment" NOT IN (?, ?) '
1653
            . 'OR "DataObjectTest_TeamComment"."Comment" IS NULL))',
1654
            $sql
1655
        );
1656
        $this->assertEquals(
1657
            ['Phil', 'Bob', 'Joe', 'Phil', 'Matches no comments', 'Not a matching comment'],
1658
            $parameters
1659
        );
1660
        $list = $list->sort('Name');
1661
        $this->assertListEquals(
1662
            [
1663
                ['Name' => 'Bob'],
1664
                ['Name' => 'Phil'],
1665
            ],
1666
            $list
1667
        );
1668
    }
1669
1670
    public function testExcludeWithSearchFilter()
1671
    {
1672
        $list = TeamComment::get();
1673
        $list = $list->exclude('Name:LessThan', 'Bob');
1674
1675
        $sql = $list->sql($parameters);
1676
        $this->assertSQLContains('WHERE (("DataObjectTest_TeamComment"."Name" >= ?))', $sql);
1677
        $this->assertEquals(array('Bob'), $parameters);
1678
    }
1679
1680
    /**
1681
     * Test that Bob and Phil are excluded (one match each)
1682
     */
1683
    public function testExcludeAny()
1684
    {
1685
        $list = TeamComment::get();
1686
        $list = $list->excludeAny(array(
1687
            'Name' => 'Bob',
1688
            'Comment' => 'Phil is a unique guy, and comments on team2'
1689
        ));
1690
        $this->assertListEquals([['Name' => 'Joe']], $list);
1691
    }
1692
1693
    /**
1694
     * Test that Bob and Phil are excluded by Name
1695
     */
1696
    public function testExcludeAnyArrays()
1697
    {
1698
        $list = TeamComment::get();
1699
        $list = $list->excludeAny(array(
1700
            'Name' => array('Bob', 'Phil'),
1701
            'Comment' => 'No matching comments'
1702
        ));
1703
        $this->assertListEquals([['Name' => 'Joe']], $list);
1704
    }
1705
1706
    /**
1707
     * Test that Bob is excluded by Name, Phil by comment
1708
     */
1709
    public function testExcludeAnyMultiArrays()
1710
    {
1711
        $list = TeamComment::get();
1712
        $list = $list->excludeAny(array(
1713
            'Name' => array('Bob', 'Fred'),
1714
            'Comment' => array('No matching comments', 'Phil is a unique guy, and comments on team2')
1715
        ));
1716
        $this->assertListEquals([['Name' => 'Joe']], $list);
1717
    }
1718
1719
    /**
1720
     * Test exact match filter with empty array items
1721
     *
1722
     * @expectedException \InvalidArgumentException
1723
     * @expectedExceptionMessage Cannot filter "DataObjectTest_TeamComment"."Name" against an empty set
1724
     */
1725
    public function testEmptyFilter()
1726
    {
1727
        $list = TeamComment::get();
1728
        $list->exclude('Name', array());
1729
    }
1730
1731
    /**
1732
     * $list->exclude(array('Name'=>'bob, 'Age'=>array(21, 43))); // exclude bob with Age 21 or 43
1733
     */
1734
    public function testMultipleExcludeWithMultipleThatCheersEitherTeam()
1735
    {
1736
        $list = TeamComment::get();
1737
        $list = $list->exclude(
1738
            array('Name'=>'Bob', 'TeamID'=>array(
1739
            $this->idFromFixture(DataObjectTest\Team::class, 'team1'),
1740
            $this->idFromFixture(DataObjectTest\Team::class, 'team2')
1741
            ))
1742
        );
1743
        $list = $list->sort('Name');
1744
        $this->assertEquals(2, $list->count());
1745
        $this->assertEquals('Joe', $list->first()->Name, 'First comment should be from Phil');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
1746
        $this->assertEquals('Phil', $list->last()->Name, 'First comment should be from Phil');
1747
    }
1748
1749
    /**
1750
     * $list->exclude(array('Name'=>'bob, 'Age'=>array(21, 43))); // negative version
1751
     */
1752
    public function testMultipleExcludeWithMultipleThatCheersOnNonExistingTeam()
1753
    {
1754
        $list = TeamComment::get();
1755
        $list = $list->exclude(array('Name'=>'Bob', 'TeamID'=>array(3)));
1756
        $this->assertEquals(3, $list->count());
1757
    }
1758
1759
    /**
1760
     * $list->exclude(array('Name'=>array('bob','phil'), 'Age'=>array(21, 43))); //negative version
1761
     */
1762
    public function testMultipleExcludeWithNoExclusion()
1763
    {
1764
        $list = TeamComment::get();
1765
        $list = $list->exclude(
1766
            array(
1767
            'Name'=>array('Bob','Joe'),
1768
            'Comment' => 'Phil is a unique guy, and comments on team2')
1769
        );
1770
        $this->assertEquals(3, $list->count());
1771
    }
1772
1773
    /**
1774
     *  $list->exclude(array('Name'=>array('bob','phil'), 'Age'=>array(21, 43)));
1775
     */
1776
    public function testMultipleExcludeWithTwoArray()
1777
    {
1778
        $list = TeamComment::get();
1779
        $list = $list->exclude(
1780
            array('Name' => array('Bob','Joe'), 'TeamID' => array(
1781
            $this->idFromFixture(DataObjectTest\Team::class, 'team1'),
1782
            $this->idFromFixture(DataObjectTest\Team::class, 'team2')
1783
            ))
1784
        );
1785
        $this->assertEquals(1, $list->count());
1786
        $this->assertEquals('Phil', $list->last()->Name, 'Only comment should be from Phil');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
1787
    }
1788
1789
    /**
1790
     *  $list->exclude(array('Name'=>array('bob','phil'), 'Age'=>array(21, 43)));
1791
     */
1792
    public function testMultipleExcludeWithTwoArrayOneTeam()
1793
    {
1794
        $list = TeamComment::get();
1795
        $list = $list->exclude(
1796
            array(
1797
            'Name' => array('Bob', 'Phil'),
1798
            'TeamID' => array($this->idFromFixture(DataObjectTest\Team::class, 'team1')))
1799
        );
1800
        $list = $list->sort('Name');
1801
        $this->assertEquals(2, $list->count());
1802
        $this->assertEquals('Joe', $list->first()->Name, 'First comment should be from Joe');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
1803
        $this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
1804
    }
1805
1806
    /**
1807
     *
1808
     */
1809
    public function testSortByRelation()
1810
    {
1811
        $list = TeamComment::get();
1812
        $list = $list->sort(array('Team.Title' => 'DESC'));
1813
        $this->assertEquals(3, $list->count());
1814
        $this->assertEquals(
1815
            $this->idFromFixture(DataObjectTest\Team::class, 'team2'),
1816
            $list->first()->TeamID,
0 ignored issues
show
Bug Best Practice introduced by
The property TeamID does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
1817
            'First comment should be for Team 2'
1818
        );
1819
        $this->assertEquals(
1820
            $this->idFromFixture(DataObjectTest\Team::class, 'team1'),
1821
            $list->last()->TeamID,
1822
            'Last comment should be for Team 1'
1823
        );
1824
    }
1825
1826
    public function testReverse()
1827
    {
1828
        $list = TeamComment::get();
1829
        $list = $list->sort('Name');
1830
        $list = $list->reverse();
1831
1832
        $this->assertEquals('Bob', $list->last()->Name, 'Last comment should be from Bob');
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
1833
        $this->assertEquals('Phil', $list->first()->Name, 'First comment should be from Phil');
1834
    }
1835
1836
    public function testSortByComplexExpression()
1837
    {
1838
        // Test an expression with both spaces and commas. This test also tests that column() can be called
1839
        // with a complex sort expression, so keep using column() below
1840
        $teamClass = Convert::raw2sql(SubTeam::class);
1841
        $list = Team::get()->sort(
1842
            'CASE WHEN "DataObjectTest_Team"."ClassName" = \'' . $teamClass . '\' THEN 0 ELSE 1 END, "Title" DESC'
1843
        );
1844
        $this->assertEquals(
1845
            array(
1846
            'Subteam 3',
1847
            'Subteam 2',
1848
            'Subteam 1',
1849
            'Team 3',
1850
            'Team 2',
1851
            'Team 1',
1852
            ),
1853
            $list->column("Title")
1854
        );
1855
    }
1856
1857
    public function testShuffle()
1858
    {
1859
        $list = Team::get()->shuffle();
1860
1861
        $this->assertSQLContains(DB::get_conn()->random() . ' AS "_SortColumn', $list->dataQuery()->sql());
1862
    }
1863
}
1864