Completed
Push — namespace-model ( 9b3f38...c67c40 )
by Sam
16:21 queued 05:15
created

DataListTest::testMap()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 13

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 18
rs 9.4285
cc 1
eloc 13
nc 1
nop 0
1
<?php
2
3
/**
4
 * @package framework
5
 * @subpackage tests
6
 */
7
8
use SilverStripe\Model\DataList;
9
use SilverStripe\Model\DB;
10
use SilverStripe\Model\Filterable;
11
12
class DataListTest extends SapphireTest {
13
14
	// Borrow the model from DataObjectTest
15
	protected static $fixture_file = 'DataObjectTest.yml';
16
17
	protected $extraDataObjects = array(
18
		// From DataObjectTest
19
		'DataObjectTest_Team',
20
		'DataObjectTest_Fixture',
21
		'DataObjectTest_SubTeam',
22
		'OtherSubclassWithSameField',
23
		'DataObjectTest_FieldlessTable',
24
		'DataObjectTest_FieldlessSubTable',
25
		'DataObjectTest_ValidatedObject',
26
		'DataObjectTest_Player',
27
		'DataObjectTest_TeamComment',
28
		'DataObjectTest_EquipmentCompany',
29
		'DataObjectTest_SubEquipmentCompany',
30
		'DataObjectTest\NamespacedClass',
31
		'DataObjectTest\RelationClass',
32
		'DataObjectTest_ExtendedTeamComment',
33
		'DataObjectTest_Company',
34
		'DataObjectTest_Staff',
35
		'DataObjectTest_CEO',
36
		'DataObjectTest_Fan',
37
		'DataObjectTest_Play',
38
		'DataObjectTest_Ploy',
39
		'DataObjectTest_Bogey',
40
	);
41
42
	public function testFilterDataObjectByCreatedDate() {
43
		// create an object to test with
44
		$obj1 = new DataObjectTest_ValidatedObject();
45
		$obj1->Name = 'test obj 1';
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<DataObjectTest_ValidatedObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
46
		$obj1->write();
47
		$this->assertTrue($obj1->isInDB());
48
49
		// reload the object from the database and reset its Created timestamp to a known value
50
		$obj1 = DataObjectTest_ValidatedObject::get()->filter(array('Name' => 'test obj 1'))->first();
51
		$this->assertTrue(is_object($obj1));
52
		$this->assertEquals('test obj 1', $obj1->Name);
53
		$obj1->Created = '2013-01-01 00:00:00';
54
		$obj1->write();
55
56
		// reload the object again and make sure that our Created date was properly persisted
57
		$obj1 = DataObjectTest_ValidatedObject::get()->filter(array('Name' => 'test obj 1'))->first();
58
		$this->assertTrue(is_object($obj1));
59
		$this->assertEquals('test obj 1', $obj1->Name);
60
		$this->assertEquals('2013-01-01 00:00:00', $obj1->Created);
61
62
		// now save a second object to the DB with an automatically-set Created value
63
		$obj2 = new DataObjectTest_ValidatedObject();
64
		$obj2->Name = 'test obj 2';
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<DataObjectTest_ValidatedObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
65
		$obj2->write();
66
		$this->assertTrue($obj2->isInDB());
67
68
		// and a third object
69
		$obj3 = new DataObjectTest_ValidatedObject();
70
		$obj3->Name = 'test obj 3';
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<DataObjectTest_ValidatedObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
71
		$obj3->write();
72
		$this->assertTrue($obj3->isInDB());
73
74
		// now test the filtering based on Created timestamp
75
		$list = DataObjectTest_ValidatedObject::get()
76
			->filter(array('Created:GreaterThan' => '2013-02-01 00:00:00'))
77
			->toArray();
78
		$this->assertEquals(2, count($list));
79
80
	}
81
82
	public function testSubtract(){
83
		$comment1 = $this->objFromFixture('DataObjectTest_TeamComment', 'comment1');
84
		$subtractList = DataObjectTest_TeamComment::get()->filter('ID', $comment1->ID);
85
		$fullList = DataObjectTest_TeamComment::get();
86
		$newList = $fullList->subtract($subtractList);
87
		$this->assertEquals(2, $newList->Count(), 'List should only contain two objects after subtraction');
88
	}
89
90
	public function testSubtractBadDataclassThrowsException(){
91
		$this->setExpectedException('InvalidArgumentException');
92
		$teamsComments = DataObjectTest_TeamComment::get();
93
		$teams = DataObjectTest_Team::get();
94
		$teamsComments->subtract($teams);
95
	}
96
97
	public function testListCreationSortAndLimit() {
98
		// By default, a DataList will contain all items of that class
99
		$list = DataObjectTest_TeamComment::get()->sort('ID');
100
101
		// We can iterate on the DataList
102
		$names = array();
103
		foreach($list as $item) {
104
			$names[] = $item->Name;
105
		}
106
		$this->assertEquals(array('Joe', 'Bob', 'Phil'), $names);
107
108
		// If we don't want to iterate, we can extract a single column from the list with column()
109
		$this->assertEquals(array('Joe', 'Bob', 'Phil'), $list->column('Name'));
110
111
		// We can sort a list
112
		$list = $list->sort('Name');
113
		$this->assertEquals(array('Bob', 'Joe', 'Phil'), $list->column('Name'));
114
115
		// We can also restrict the output to a range
116
		$this->assertEquals(array('Joe', 'Phil'), $list->limit(2, 1)->column('Name'));
117
	}
118
119
	public function testLimitAndOffset() {
120
		$list = DataObjectTest_TeamComment::get();
121
		$check = $list->limit(3);
122
123
		$this->assertEquals(3, $check->count());
124
125
		$check = $list->limit(1);
126
		$this->assertEquals(1, $check->count());
127
128
		$check = $list->limit(1, 1);
129
		$this->assertEquals(1, $check->count());
130
131
		$check = $list->limit(false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
132
		$this->assertEquals(3, $check->count());
133
134
		$check = $list->limit(null);
135
		$this->assertEquals(3, $check->count());
136
137
		$check = $list->limit(null, 2);
138
		$this->assertEquals(1, $check->count());
139
140
		// count()/first()/last() methods may alter limit/offset, so run the query and manually check the count
141
		$check = $list->limit(null, 1)->toArray();
142
		$this->assertEquals(2, count($check));
143
	}
144
145
	public function testDistinct() {
146
		$list = DataObjectTest_TeamComment::get();
147
		$this->assertContains('SELECT DISTINCT', $list->dataQuery()->sql($params), 'Query is set as distinct by default');
148
149
		$list = $list->distinct(false);
150
		$this->assertNotContains('SELECT DISTINCT', $list->dataQuery()->sql($params), 'Query does not contain distinct');
151
152
		$list = $list->distinct(true);
153
		$this->assertContains('SELECT DISTINCT', $list->dataQuery()->sql($params), 'Query contains distinct');
154
	}
155
156
	public function testDataClass() {
157
		$list = DataObjectTest_TeamComment::get();
158
		$this->assertEquals('DataObjectTest_TeamComment',$list->dataClass());
159
	}
160
161
	public function testDataClassCaseInsensitive() {
162
		$list = DataList::create('dataobjecttest_teamcomment');
163
		$this->assertTrue($list->exists());
164
	}
165
166
	public function testClone() {
167
		$list = DataObjectTest_TeamComment::get();
168
		$this->assertEquals($list, clone($list));
169
	}
170
171
	public function testSql() {
172
		$db = DB::get_conn();
173
		$list = DataObjectTest_TeamComment::get();
174
		$expected = 'SELECT DISTINCT "DataObjectTest_TeamComment"."ClassName", '
175
			. '"DataObjectTest_TeamComment"."LastEdited", "DataObjectTest_TeamComment"."Created", '
176
			. '"DataObjectTest_TeamComment"."Name", "DataObjectTest_TeamComment"."Comment", '
177
			. '"DataObjectTest_TeamComment"."TeamID", "DataObjectTest_TeamComment"."ID", '
178
			. 'CASE WHEN "DataObjectTest_TeamComment"."ClassName" IS NOT NULL '
179
			. 'THEN "DataObjectTest_TeamComment"."ClassName" ELSE '
180
			. $db->quoteString('DataObjectTest_TeamComment')
181
			. ' END AS "RecordClassName" FROM "DataObjectTest_TeamComment"'
182
			. ' ORDER BY "DataObjectTest_TeamComment"."Name" ASC';
183
		$this->assertSQLEquals($expected, $list->sql($parameters));
184
	}
185
186
	public function testInnerJoin() {
187
		$db = DB::get_conn();
188
189
		$list = DataObjectTest_TeamComment::get();
190
		$list = $list->innerJoin(
191
			'DataObjectTest_Team',
192
			'"DataObjectTest_Team"."ID" = "DataObjectTest_TeamComment"."TeamID"',
193
			'Team'
194
		);
195
196
		$expected = 'SELECT DISTINCT "DataObjectTest_TeamComment"."ClassName", '
197
			. '"DataObjectTest_TeamComment"."LastEdited", "DataObjectTest_TeamComment"."Created", '
198
			. '"DataObjectTest_TeamComment"."Name", "DataObjectTest_TeamComment"."Comment", '
199
			. '"DataObjectTest_TeamComment"."TeamID", "DataObjectTest_TeamComment"."ID", '
200
			. 'CASE WHEN "DataObjectTest_TeamComment"."ClassName" IS NOT NULL'
201
			. ' THEN "DataObjectTest_TeamComment"."ClassName" ELSE '
202
			. $db->quoteString('DataObjectTest_TeamComment')
203
			. ' END AS "RecordClassName" FROM "DataObjectTest_TeamComment" INNER JOIN '
204
			. '"DataObjectTest_Team" AS "Team" ON "DataObjectTest_Team"."ID" = '
205
			. '"DataObjectTest_TeamComment"."TeamID"'
206
			. ' ORDER BY "DataObjectTest_TeamComment"."Name" ASC';
207
208
209
		$this->assertSQLEquals($expected, $list->sql($parameters));
210
		$this->assertEmpty($parameters);
211
	}
212
213 View Code Duplication
	public function testInnerJoinParameterised() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
214
		$db = DB::get_conn();
215
216
		$list = DataObjectTest_TeamComment::get();
217
		$list = $list->innerJoin(
218
			'DataObjectTest_Team',
219
			'"DataObjectTest_Team"."ID" = "DataObjectTest_TeamComment"."TeamID" '
220
			. 'AND "DataObjectTest_Team"."Title" LIKE ?',
221
			'Team',
222
			20,
223
			array('Team%')
224
		);
225
226
		$expected = 'SELECT DISTINCT "DataObjectTest_TeamComment"."ClassName", '
227
			. '"DataObjectTest_TeamComment"."LastEdited", "DataObjectTest_TeamComment"."Created", '
228
			. '"DataObjectTest_TeamComment"."Name", "DataObjectTest_TeamComment"."Comment", '
229
			. '"DataObjectTest_TeamComment"."TeamID", "DataObjectTest_TeamComment"."ID", '
230
			. 'CASE WHEN "DataObjectTest_TeamComment"."ClassName" IS NOT NULL'
231
			. ' THEN "DataObjectTest_TeamComment"."ClassName" ELSE '
232
			. $db->quoteString('DataObjectTest_TeamComment')
233
			. ' END AS "RecordClassName" FROM "DataObjectTest_TeamComment" INNER JOIN '
234
			. '"DataObjectTest_Team" AS "Team" ON "DataObjectTest_Team"."ID" = '
235
			. '"DataObjectTest_TeamComment"."TeamID" '
236
			. 'AND "DataObjectTest_Team"."Title" LIKE ?'
237
			. ' ORDER BY "DataObjectTest_TeamComment"."Name" ASC';
238
239
		$this->assertSQLEquals($expected, $list->sql($parameters));
240
		$this->assertEquals(array('Team%'), $parameters);
241
	}
242
243
	public function testLeftJoin() {
244
		$db = DB::get_conn();
245
246
		$list = DataObjectTest_TeamComment::get();
247
		$list = $list->leftJoin(
248
			'DataObjectTest_Team',
249
			'"DataObjectTest_Team"."ID" = "DataObjectTest_TeamComment"."TeamID"',
250
			'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')
260
			. ' END AS "RecordClassName" FROM "DataObjectTest_TeamComment" LEFT JOIN "DataObjectTest_Team" '
261
			. 'AS "Team" ON "DataObjectTest_Team"."ID" = "DataObjectTest_TeamComment"."TeamID"'
262
			. ' ORDER BY "DataObjectTest_TeamComment"."Name" ASC';
263
264
265
		$this->assertSQLEquals($expected, $list->sql($parameters));
266
		$this->assertEmpty($parameters);
267
268
		// Test with namespaces (with non-sensical join, but good enough for testing)
269
		$list = DataObjectTest_TeamComment::get();
270
		$list = $list->leftJoin(
271
			'DataObjectTest\NamespacedClass',
272
			'"DataObjectTest\NamespacedClass"."ID" = "DataObjectTest_TeamComment"."ID"'
273
		);
274
275
		$expected = 'SELECT DISTINCT "DataObjectTest_TeamComment"."ClassName", '
276
			. '"DataObjectTest_TeamComment"."LastEdited", '
277
			. '"DataObjectTest_TeamComment"."Created", '
278
			. '"DataObjectTest_TeamComment"."Name", '
279
			. '"DataObjectTest_TeamComment"."Comment", '
280
			. '"DataObjectTest_TeamComment"."TeamID", '
281
			. '"DataObjectTest_TeamComment"."ID", '
282
			. 'CASE WHEN "DataObjectTest_TeamComment"."ClassName" IS NOT NULL '
283
			. 'THEN "DataObjectTest_TeamComment"."ClassName" '
284
			. 'ELSE ' . $db->quoteString('DataObjectTest_TeamComment') . ' END AS "RecordClassName" '
285
			. 'FROM "DataObjectTest_TeamComment" '
286
			. 'LEFT JOIN "DataObjectTest\NamespacedClass" ON '
287
			. '"DataObjectTest\NamespacedClass"."ID" = "DataObjectTest_TeamComment"."ID"'
288
			. ' ORDER BY "DataObjectTest_TeamComment"."Name" ASC';
289
		$this->assertSQLEquals($expected, $list->sql($parameters), 'Retains backslashes in namespaced classes');
290
		$this->assertEmpty($parameters);
291
292
	}
293
294 View Code Duplication
	public function testLeftJoinParameterised() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
295
		$db = DB::get_conn();
296
297
		$list = DataObjectTest_TeamComment::get();
298
		$list = $list->leftJoin(
299
			'DataObjectTest_Team',
300
			'"DataObjectTest_Team"."ID" = "DataObjectTest_TeamComment"."TeamID" '
301
			. 'AND "DataObjectTest_Team"."Title" LIKE ?',
302
			'Team',
303
			20,
304
			array('Team%')
305
		);
306
307
		$expected = 'SELECT DISTINCT "DataObjectTest_TeamComment"."ClassName", '
308
			. '"DataObjectTest_TeamComment"."LastEdited", "DataObjectTest_TeamComment"."Created", '
309
			. '"DataObjectTest_TeamComment"."Name", "DataObjectTest_TeamComment"."Comment", '
310
			. '"DataObjectTest_TeamComment"."TeamID", "DataObjectTest_TeamComment"."ID", '
311
			. 'CASE WHEN "DataObjectTest_TeamComment"."ClassName" IS NOT NULL'
312
			. ' THEN "DataObjectTest_TeamComment"."ClassName" ELSE '
313
			. $db->quoteString('DataObjectTest_TeamComment')
314
			. ' END AS "RecordClassName" FROM "DataObjectTest_TeamComment" LEFT JOIN '
315
			. '"DataObjectTest_Team" AS "Team" ON "DataObjectTest_Team"."ID" = '
316
			. '"DataObjectTest_TeamComment"."TeamID" '
317
			. 'AND "DataObjectTest_Team"."Title" LIKE ?'
318
			. ' ORDER BY "DataObjectTest_TeamComment"."Name" ASC';
319
320
		$this->assertSQLEquals($expected, $list->sql($parameters));
321
		$this->assertEquals(array('Team%'), $parameters);
322
	}
323
324
	public function testToNestedArray() {
325
		$list = DataObjectTest_TeamComment::get()->sort('ID');
326
		$nestedArray = $list->toNestedArray();
327
		$expected = array(
328
			0=>
329
			array(
330
				'ClassName'=>'DataObjectTest_TeamComment',
331
				'Name'=>'Joe',
332
				'Comment'=>'This is a team comment by Joe',
333
				'TeamID'=> $this->objFromFixture('DataObjectTest_TeamComment', 'comment1')->TeamID,
334
			),
335
			1=>
336
			array(
337
				'ClassName'=>'DataObjectTest_TeamComment',
338
				'Name'=>'Bob',
339
				'Comment'=>'This is a team comment by Bob',
340
				'TeamID'=> $this->objFromFixture('DataObjectTest_TeamComment', 'comment2')->TeamID,
341
			),
342
			2=>
343
			array(
344
				'ClassName'=>'DataObjectTest_TeamComment',
345
				'Name'=>'Phil',
346
				'Comment'=>'Phil is a unique guy, and comments on team2',
347
				'TeamID'=> $this->objFromFixture('DataObjectTest_TeamComment', 'comment3')->TeamID,
348
			),
349
		);
350
		$this->assertEquals(3, count($nestedArray));
351
		$this->assertEquals($expected[0]['Name'], $nestedArray[0]['Name']);
352
		$this->assertEquals($expected[1]['Comment'], $nestedArray[1]['Comment']);
353
		$this->assertEquals($expected[2]['TeamID'], $nestedArray[2]['TeamID']);
354
	}
355
356
	public function testMap() {
357
		$map = DataObjectTest_TeamComment::get()->map()->toArray();
358
		$expected = array(
359
			$this->idFromFixture('DataObjectTest_TeamComment', 'comment1') => 'Joe',
360
			$this->idFromFixture('DataObjectTest_TeamComment', 'comment2') => 'Bob',
361
			$this->idFromFixture('DataObjectTest_TeamComment', 'comment3') => 'Phil'
362
		);
363
364
		$this->assertEquals($expected, $map);
365
		$otherMap = DataObjectTest_TeamComment::get()->map('Name', 'TeamID')->toArray();
366
		$otherExpected = array(
367
			'Joe' => $this->objFromFixture('DataObjectTest_TeamComment', 'comment1')->TeamID,
368
			'Bob' => $this->objFromFixture('DataObjectTest_TeamComment', 'comment2')->TeamID,
369
			'Phil' => $this->objFromFixture('DataObjectTest_TeamComment', 'comment3')->TeamID
370
		);
371
372
		$this->assertEquals($otherExpected, $otherMap);
373
	}
374
375
	public function testEach() {
376
		$list = DataObjectTest_TeamComment::get();
377
378
		$count = 0;
379
		$test = $this;
380
381
		$list->each(function($item) use (&$count, $test) {
382
			$count++;
383
384
			$test->assertTrue(is_a($item, "DataObjectTest_TeamComment"));
385
		});
386
387
		$this->assertEquals($list->Count(), $count);
388
	}
389
390
	public function testWhere() {
391
		// We can use raw SQL queries with where.  This is only recommended for advanced uses;
392
		// if you can, you should use filter().
393
		$list = DataObjectTest_TeamComment::get();
394
395
		// where() returns a new DataList, like all the other modifiers, so it can be chained.
396
		$list2 = $list->where('"Name" = \'Joe\'');
397
		$this->assertEquals(array('This is a team comment by Joe'), $list2->column('Comment'));
398
399
		// The where() clauses are chained together with AND
400
		$list3 = $list2->where('"Name" = \'Bob\'');
401
		$this->assertEquals(array(), $list3->column('Comment'));
402
	}
403
404
	/**
405
	 * Test DataList->byID()
406
	 */
407
	public function testByID() {
408
		// We can get a single item by ID.
409
		$id = $this->idFromFixture('DataObjectTest_Team','team2');
410
		$team = DataObjectTest_Team::get()->byID($id);
411
412
		// byID() returns a DataObject, rather than a DataList
413
		$this->assertInstanceOf('DataObjectTest_Team', $team);
414
		$this->assertEquals('Team 2', $team->Title);
415
416
		// Assert that filtering on ID searches by the base table, not the child table field
417
		$query = DataObjectTest_SubTeam::get()->filter('ID', 4)->sql($parameters);
418
		$this->assertContains('WHERE ("DataObjectTest_Team"."ID" = ?)', $query);
419
		$this->assertNotContains('WHERE ("DataObjectTest_SubTeam"."ID" = ?)', $query);
420
	}
421
422
	/**
423
	 * Test DataList->removeByID()
424
	 */
425
	public function testRemoveByID() {
426
		$list = DataObjectTest_Team::get();
427
		$id = $this->idFromFixture('DataObjectTest_Team','team2');
428
429
		$this->assertNotNull($list->byID($id));
430
		$list->removeByID($id);
431
		$this->assertNull($list->byID($id));
432
	}
433
434
	/**
435
	 * Test DataList->canSortBy()
436
	 */
437
	public function testCanSortBy() {
438
		// Basic check
439
		$team = DataObjectTest_Team::get();
440
		$this->assertTrue($team->canSortBy("Title"));
441
		$this->assertFalse($team->canSortBy("SomethingElse"));
442
443
		// Subclasses
444
		$subteam = DataObjectTest_SubTeam::get();
445
		$this->assertTrue($subteam->canSortBy("Title"));
446
		$this->assertTrue($subteam->canSortBy("SubclassDatabaseField"));
447
	}
448
449
	public function testDataListArrayAccess() {
450
		$list = DataObjectTest_Team::get()->sort('Title');
451
452
		// We can use array access to refer to single items in the DataList, as if it were an array
453
		$this->assertEquals("Subteam 1", $list[0]->Title);
454
		$this->assertEquals("Subteam 3", $list[2]->Title);
455
		$this->assertEquals("Team 2", $list[4]->Title);
456
	}
457
458
	public function testFind() {
459
		$list = DataObjectTest_Team::get();
460
		$record = $list->find('Title', 'Team 1');
461
		$this->assertEquals($this->idFromFixture('DataObjectTest_Team', 'team1'), $record->ID);
462
	}
463
464
	public function testFindById() {
465
		$list = DataObjectTest_Team::get();
466
		$record = $list->find('ID', $this->idFromFixture('DataObjectTest_Team', 'team1'));
467
		$this->assertEquals('Team 1', $record->Title);
468
		// Test that you can call it twice on the same list
469
		$record = $list->find('ID', $this->idFromFixture('DataObjectTest_Team', 'team2'));
470
		$this->assertEquals('Team 2', $record->Title);
471
	}
472
473
	public function testSimpleSort() {
474
		$list = DataObjectTest_TeamComment::get();
475
		$list = $list->sort('Name');
476
		$this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
477
		$this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
478
	}
479
480
	public function testSimpleSortOneArgumentASC() {
481
		$list = DataObjectTest_TeamComment::get();
482
		$list = $list->sort('Name ASC');
483
		$this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
484
		$this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
485
	}
486
487
	public function testSimpleSortOneArgumentDESC() {
488
		$list = DataObjectTest_TeamComment::get();
489
		$list = $list->sort('Name DESC');
490
		$this->assertEquals('Phil', $list->first()->Name, 'Last comment should be from Phil');
491
		$this->assertEquals('Bob', $list->last()->Name, 'First comment should be from Bob');
492
	}
493
494
	public function testSortOneArgumentMultipleColumns() {
495
		$list = DataObjectTest_TeamComment::get();
496
		$list = $list->sort('TeamID ASC, Name DESC');
497
		$this->assertEquals('Joe', $list->first()->Name, 'First comment should be from Bob');
498
		$this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
499
	}
500
501
	public function testSimpleSortASC() {
502
		$list = DataObjectTest_TeamComment::get();
503
		$list = $list->sort('Name', 'asc');
504
		$this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
505
		$this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
506
	}
507
508
	public function testSimpleSortDESC() {
509
		$list = DataObjectTest_TeamComment::get();
510
		$list = $list->sort('Name', 'desc');
511
		$this->assertEquals('Phil', $list->first()->Name, 'Last comment should be from Phil');
512
		$this->assertEquals('Bob', $list->last()->Name, 'First comment should be from Bob');
513
	}
514
515
	public function testSortWithArraySyntaxSortASC() {
516
		$list = DataObjectTest_TeamComment::get();
517
		$list = $list->sort(array('Name'=>'asc'));
518
		$this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
519
		$this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
520
	}
521
522
	public function testSortWithArraySyntaxSortDESC() {
523
		$list = DataObjectTest_TeamComment::get();
524
		$list = $list->sort(array('Name'=>'desc'));
525
		$this->assertEquals('Phil', $list->first()->Name, 'Last comment should be from Phil');
526
		$this->assertEquals('Bob', $list->last()->Name, 'First comment should be from Bob');
527
	}
528
529
	public function testSortWithMultipleArraySyntaxSort() {
530
		$list = DataObjectTest_TeamComment::get();
531
		$list = $list->sort(array('TeamID'=>'asc','Name'=>'desc'));
532
		$this->assertEquals('Joe', $list->first()->Name, 'First comment should be from Bob');
533
		$this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
534
	}
535
536
	public function testSortWithCompositeSyntax() {
537
		// Phil commented on team with founder surname "Aaron"
538
		$list = DataObjectTest_TeamComment::get();
539
		$list = $list->sort('Team.Founder.Surname', 'asc');
540
		$this->assertEquals('Phil', $list->first()->Name);
541
		$list = $list->sort('Team.Founder.Surname', 'desc');
542
		$this->assertEquals('Phil', $list->last()->Name);
543
	}
544
545
	public function testSortInvalidParameters() {
546
		$this->setExpectedException(
547
			'InvalidArgumentException',
548
			'Fans is not a linear relation on model DataObjectTest_Player'
549
		);
550
		$list = DataObjectTest_Team::get();
551
		$list = $list->sort('Founder.Fans.Surname'); // Can't sort on has_many
0 ignored issues
show
Unused Code introduced by
$list is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
552
	}
553
554
555
556
	/**
557
	 * $list->filter('Name', 'bob'); // only bob in the list
558
	 */
559
	public function testSimpleFilter() {
560
		$list = DataObjectTest_Team::get();
561
		$list = $list->filter('Title','Team 2');
562
		$this->assertEquals(1, $list->count());
563
		$this->assertEquals('Team 2', $list->first()->Title, 'List should only contain Team 2');
564
		$this->assertEquals('Team 2', $list->last()->Title, 'Last should only contain Team 2');
565
	}
566
567
	public function testSimpleFilterEndsWith() {
568
		$list = DataObjectTest_TeamComment::get();
569
		$list = $list->filter('Name:EndsWith', 'b');
570
		$this->assertEquals(1, $list->count());
571
		$this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
572
	}
573
574
	public function testSimpleFilterExactMatchFilter() {
575
		$list = DataObjectTest_TeamComment::get();
576
		$list = $list->filter('Name:ExactMatch', 'Bob');
577
		$this->assertEquals(1, $list->count());
578
		$this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
579
	}
580
581
	public function testSimpleFilterGreaterThanFilter() {
582
		$list = DataObjectTest_TeamComment::get();
583
		$list = $list->filter('TeamID:GreaterThan', $this->idFromFixture('DataObjectTest_Team', 'team1'));
584
		$this->assertEquals(1, $list->count());
585
		$this->assertEquals('Phil', $list->first()->Name, 'First comment should be from Phil');
586
	}
587
588
	public function testSimpleFilterGreaterThanOrEqualFilter() {
589
		$list = DataObjectTest_TeamComment::get();
590
		$list = $list->filter('TeamID:GreaterThanOrEqual',
591
			$this->idFromFixture('DataObjectTest_Team', 'team1'))->sort("ID");
592
		$this->assertEquals(3, $list->count());
593
		$this->assertEquals('Joe', $list->first()->Name, 'First comment should be from Joe');
594
		$this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
595
	}
596
597
	public function testSimpleFilterLessThanFilter() {
598
		$list = DataObjectTest_TeamComment::get();
599
		$list = $list->filter('TeamID:LessThan',
600
			$this->idFromFixture('DataObjectTest_Team', 'team2'))->sort('Name');
601
		$this->assertEquals(2, $list->count());
602
		$this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
603
		$this->assertEquals('Joe', $list->Last()->Name, 'Last comment should be from Joe');
604
	}
605
606
	public function testSimpleFilterLessThanOrEqualFilter() {
607
		$list = DataObjectTest_TeamComment::get();
608
		$list = $list->filter('TeamID:LessThanOrEqual',
609
			$this->idFromFixture('DataObjectTest_Team', 'team1'))->sort('ID');
610
		$this->assertEquals(2, $list->count());
611
		$this->assertEquals('Joe', $list->first()->Name, 'First comment should be from Joe');
612
		$this->assertEquals('Bob', $list->Last()->Name, 'Last comment should be from Bob');
613
	}
614
615
	public function testSimplePartialMatchFilter() {
616
		$list = DataObjectTest_TeamComment::get();
617
		$list = $list->filter('Name:PartialMatch', 'o')->sort('Name');
618
		$this->assertEquals(2, $list->count());
619
		$this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
620
		$this->assertEquals('Joe', $list->last()->Name, 'First comment should be from Joe');
621
	}
622
623
	public function testSimpleFilterStartsWith() {
624
		$list = DataObjectTest_TeamComment::get();
625
		$list = $list->filter('Name:StartsWith', 'B');
626
		$this->assertEquals(1, $list->count());
627
		$this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
628
	}
629
630
	public function testSimpleFilterWithNonExistingComparisator() {
631
		$this->setExpectedException('InvalidArgumentException');
632
		$list = DataObjectTest_TeamComment::get();
633
		$list = $list->filter('Comment:Bogus', 'team comment');
0 ignored issues
show
Unused Code introduced by
$list is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
634
	}
635
636
	/**
637
	 * $list->filter('Name', array('aziz', 'bob'); // aziz and bob in list
638
	 */
639
	public function testSimpleFilterWithMultiple() {
640
		$list = DataObjectTest_TeamComment::get();
641
		$list = $list->filter('Name', array('Bob','Phil'));
642
		$list = $list->sort('Name', 'ASC');
643
		$this->assertEquals(2, $list->count());
644
		$this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
645
		$this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
646
	}
647
648
	public function testMultipleFilterWithNoMatch() {
649
		$list = DataObjectTest_TeamComment::get();
650
		$list = $list->filter(array('Name'=>'Bob', 'Comment'=>'Phil is a unique guy, and comments on team2'));
651
		$this->assertEquals(0, $list->count());
652
	}
653
654
	/**
655
	 *  $list->filter(array('Name'=>'bob, 'Age'=>21)); // bob with the age 21
656
	 */
657 View Code Duplication
	public function testFilterMultipleArray() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
658
		$list = DataObjectTest_TeamComment::get();
659
		$list = $list->filter(array('Name'=>'Bob', 'Comment'=>'This is a team comment by Bob'));
660
		$list = $list->sort('Name', 'ASC');
661
		$this->assertEquals(1, $list->count());
662
		$this->assertEquals('Bob', $list->first()->Name, 'Only comment should be from Bob');
663
	}
664
665
	public function testFilterMultipleWithTwoMatches() {
666
		$list = DataObjectTest_TeamComment::get();
667
		$list = $list->filter(array('TeamID'=>$this->idFromFixture('DataObjectTest_Team', 'team1')));
668
		$this->assertEquals(2, $list->count());
669
	}
670
671
	public function testFilterMultipleWithArrayFilter() {
672
		$list = DataObjectTest_TeamComment::get();
673
		$list = $list->filter(array('Name'=>array('Bob','Phil')));
674
		$list = $list->sort('Name', 'ASC');
675
		$this->assertEquals(2, $list->count(), 'There should be two comments');
676
		$this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
677
		$this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
678
	}
679
680
	public function testFilterMultipleWithArrayFilterAndModifiers() {
681
		$list = DataObjectTest_TeamComment::get();
682
		$list = $list->filter(array('Name:StartsWith'=>array('Bo', 'Jo')));
683
		$list = $list->sort('Name', 'ASC');
684
		$this->assertEquals(2, $list->count());
685
		$this->assertEquals('Bob', $list->first()->Name);
686
		$this->assertEquals('Joe', $list->last()->Name);
687
	}
688
689
	/**
690
	 * $list->filter(array('Name'=>array('aziz','bob'), 'Age'=>array(21, 43)));
691
	 */
692
	public function testFilterArrayInArray() {
693
		$list = DataObjectTest_TeamComment::get();
694
		$list = $list->filter(array(
695
			'Name'=>array('Bob','Phil'),
696
			'TeamID'=>array($this->idFromFixture('DataObjectTest_Team', 'team1'))));
697
		$this->assertEquals(1, $list->count(), 'There should be one comment');
698
		$this->assertEquals('Bob', $list->first()->Name, 'Only comment should be from Bob');
699
	}
700
701
	public function testFilterWithModifiers() {
702
		$list = DataObjectTest_TeamComment::get();
703
		$nocaseList = $list->filter('Name:nocase', 'bob');
704
		$this->assertEquals(1, $nocaseList->count(), 'There should be one comment');
705
		$caseList = $list->filter('Name:case', 'bob');
706
		$this->assertEquals(0, $caseList->count(), 'There should be no comments');
707
		$gtList = $list->filter('TeamID:GreaterThan:not',
708
			$this->idFromFixture('DataObjectTest_Team', 'team1'));
709
		$this->assertEquals(2, $gtList->count());
710
	}
711
712
	public function testFilterAny() {
713
		$list = DataObjectTest_TeamComment::get();
714
		$list = $list->filterAny('Name', 'Bob');
715
		$this->assertEquals(1, $list->count());
716
	}
717
718
	public function testFilterAnyMultipleArray() {
719
		$list = DataObjectTest_TeamComment::get();
720
		$list = $list->filterAny(array('Name'=>'Bob', 'Comment'=>'This is a team comment by Bob'));
721
		$this->assertEquals(1, $list->count());
722
		$this->assertEquals('Bob', $list->first()->Name, 'Only comment should be from Bob');
723
	}
724
725
	public function testFilterAnyOnFilter() {
726
		$list = DataObjectTest_TeamComment::get();
727
		$list = $list->filter(array(
728
			'TeamID'=>$this->idFromFixture('DataObjectTest_Team', 'team1')
729
		));
730
		$list = $list->filterAny(array(
731
			'Name'=>array('Phil', 'Joe'),
732
			'Comment'=>'This is a team comment by Bob'
733
		));
734
		$list = $list->sort('Name');
735
		$this->assertEquals(2, $list->count());
736
		$this->assertEquals(
737
			'Bob',
738
			$list->offsetGet(0)->Name,
739
			'Results should include comments from Bob, matched by comment and team'
740
		);
741
		$this->assertEquals(
742
			'Joe',
743
			$list->offsetGet(1)->Name,
744
			'Results should include comments by Joe, matched by name and team (not by comment)'
745
		);
746
747
		$list = DataObjectTest_TeamComment::get();
748
		$list = $list->filter(array(
749
			'TeamID'=>$this->idFromFixture('DataObjectTest_Team', 'team1')
750
		));
751
		$list = $list->filterAny(array(
752
			'Name'=>array('Phil', 'Joe'),
753
			'Comment'=>'This is a team comment by Bob'
754
		));
755
		$list = $list->sort('Name');
756
		$list = $list->filter(array('Name' => 'Bob'));
757
		$this->assertEquals(1, $list->count());
758
		$this->assertEquals(
759
			'Bob',
760
			$list->offsetGet(0)->Name,
761
			'Results should include comments from Bob, matched by name and team'
762
		);
763
	}
764
765 View Code Duplication
	public function testFilterAnyMultipleWithArrayFilter() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
766
		$list = DataObjectTest_TeamComment::get();
767
		$list = $list->filterAny(array('Name'=>array('Bob','Phil')));
768
		$this->assertEquals(2, $list->count(), 'There should be two comments');
769
		$this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
770
		$this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
771
	}
772
773
	public function testFilterAnyArrayInArray() {
774
		$list = DataObjectTest_TeamComment::get();
775
		$list = $list->filterAny(array(
776
			'Name'=>array('Bob','Phil'),
777
			'TeamID'=>array($this->idFromFixture('DataObjectTest_Team', 'team1'))))
778
			->sort('Name');
779
		$this->assertEquals(3, $list->count());
780
		$this->assertEquals(
781
			'Bob',
782
			$list->offsetGet(0)->Name,
783
			'Results should include comments from Bob, matched by name and team'
784
		);
785
		$this->assertEquals(
786
			'Joe',
787
			$list->offsetGet(1)->Name,
788
			'Results should include comments by Joe, matched by team (not by name)'
789
		);
790
		$this->assertEquals(
791
			'Phil',
792
			$list->offsetGet(2)->Name,
793
			'Results should include comments from Phil, matched by name (even if he\'s not in Team1)'
794
		);
795
	}
796
797 View Code Duplication
	public function testFilterOnJoin() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
798
		$list = DataObjectTest_TeamComment::get()
799
			->leftJoin('DataObjectTest_Team',
800
				'"DataObjectTest_Team"."ID" = "DataObjectTest_TeamComment"."TeamID"'
801
			)->filter(array(
802
				'Title' => 'Team 1'
803
			));
804
805
		$this->assertEquals(2, $list->count());
806
		$values = $list->column('Name');
807
		$this->assertEquals(array_intersect($values, array('Joe', 'Bob')), $values);
808
	}
809
810
	public function testFilterOnImplicitJoin() {
811
		// Many to many
812
		$list = DataObjectTest_Team::get()
813
			->filter('Players.FirstName', array('Captain', 'Captain 2'));
814
815
		$this->assertEquals(2, $list->count());
816
817
		// Has many
818
		$list = DataObjectTest_Team::get()
819
			->filter('Comments.Name', array('Joe', 'Phil'));
820
821
		$this->assertEquals(2, $list->count());
822
823
		// Has one
824
		$list = DataObjectTest_Player::get()
825
			->filter('FavouriteTeam.Title', 'Team 1');
826
827
		$this->assertEquals(1, $list->count());
828
		$this->assertEquals('007', $list->first()->ShirtNumber);
829
	}
830
831
	public function testFilterAndExcludeById() {
832
		$id = $this->idFromFixture('DataObjectTest_SubTeam', 'subteam1');
833
		$list = DataObjectTest_SubTeam::get()->filter('ID', $id);
834
		$this->assertEquals($id, $list->first()->ID);
835
836
		$list = DataObjectTest_SubTeam::get();
837
		$this->assertEquals(3, count($list));
838
		$this->assertEquals(2, count($list->exclude('ID', $id)));
839
840
		// Check that classes with namespaces work.
841
		$obj = new DataObjectTest\NamespacedClass();
842
		$obj->Name = "Test";
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<DataObjectTest\NamespacedClass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
843
		$obj->write();
844
845
		$list = DataObjectTest\NamespacedClass::get()->filter('ID', $obj->ID);
846
		$this->assertEquals('Test', $list->First()->Name);
847
		$this->assertEquals(0, $list->exclude('ID', $obj->ID)->count());
848
	}
849
850
	public function testFilterByNull() {
851
		$list = DataObjectTest_Fan::get();
852
		// Force DataObjectTest_Fan/fan5::Email to empty string
853
		$fan5id = $this->idFromFixture('DataObjectTest_Fan', 'fan5');
854
		DB::prepared_query("UPDATE \"DataObjectTest_Fan\" SET \"Email\" = '' WHERE \"ID\" = ?", array($fan5id));
855
856
		// Filter by null email
857
		$nullEmails = $list->filter('Email', null);
858
		$this->assertDOSEquals(array(
859
			array(
860
				'Name' => 'Stephen',
861
			),
862
			array(
863
				'Name' => 'Mitch',
864
			)
865
		), $nullEmails);
866
867
		// Filter by non-null
868
		$nonNullEmails = $list->filter('Email:not', null);
869
		$this->assertDOSEquals(array(
870
			array(
871
				'Name' => 'Damian',
872
				'Email' => '[email protected]',
873
			),
874
			array(
875
				'Name' => 'Richard',
876
				'Email' => '[email protected]',
877
			),
878
			array(
879
				'Name' => 'Hamish',
880
			)
881
		), $nonNullEmails);
882
883
		// Filter by empty only
884
		$emptyOnly = $list->filter('Email', '');
885
		$this->assertDOSEquals(array(
886
			array(
887
				'Name' => 'Hamish',
888
			)
889
		), $emptyOnly);
890
891
		// Non-empty only. This should include null values, since ExactMatchFilter works around
892
		// the caveat that != '' also excludes null values in ANSI SQL-92 behaviour.
893
		$nonEmptyOnly = $list->filter('Email:not', '');
894
		$this->assertDOSEquals(array(
895
			array(
896
				'Name' => 'Damian',
897
				'Email' => '[email protected]',
898
			),
899
			array(
900
				'Name' => 'Richard',
901
				'Email' => '[email protected]',
902
			),
903
			array(
904
				'Name' => 'Stephen',
905
			),
906
			array(
907
				'Name' => 'Mitch',
908
			)
909
		), $nonEmptyOnly);
910
911
		// Filter by many including null, empty string, and non-empty
912
		$items1 = $list->filter('Email', array(null, '', '[email protected]'));
913
		$this->assertDOSEquals(array(
914
			array(
915
				'Name' => 'Damian',
916
				'Email' => '[email protected]',
917
			),
918
			array(
919
				'Name' => 'Stephen',
920
			),
921
			array(
922
				'Name' => 'Mitch',
923
			),
924
			array(
925
				'Name' => 'Hamish',
926
			)
927
		), $items1);
928
929
		// Filter exclusion of above list
930
		$items2 = $list->filter('Email:not', array(null, '', '[email protected]'));
931
		$this->assertDOSEquals(array(
932
			array(
933
				'Name' => 'Richard',
934
				'Email' => '[email protected]',
935
			),
936
		), $items2);
937
938
		// Filter by many including empty string and non-empty
939
		$items3 = $list->filter('Email', array('', '[email protected]'));
940
		$this->assertDOSEquals(array(
941
			array(
942
				'Name' => 'Damian',
943
				'Email' => '[email protected]',
944
			),
945
			array(
946
				'Name' => 'Hamish',
947
			)
948
		), $items3);
949
950
		// Filter by many including empty string and non-empty
951
		// This also relies no the workaround for null comparison as in the $nonEmptyOnly test
952
		$items4 = $list->filter('Email:not', array('', '[email protected]'));
953
		$this->assertDOSEquals(array(
954
			array(
955
				'Name' => 'Richard',
956
				'Email' => '[email protected]',
957
			),
958
			array(
959
				'Name' => 'Stephen',
960
			),
961
			array(
962
				'Name' => 'Mitch',
963
			)
964
		), $items4);
965
966
		// Filter by many including empty string and non-empty
967
		// The extra null check isn't necessary, but check that this doesn't fail
968
		$items5 = $list->filterAny(array(
969
			'Email:not' => array('', '[email protected]'),
970
			'Email' => null
971
		));
972
		$this->assertDOSEquals(array(
973
			array(
974
				'Name' => 'Richard',
975
				'Email' => '[email protected]',
976
			),
977
			array(
978
				'Name' => 'Stephen',
979
			),
980
			array(
981
				'Name' => 'Mitch',
982
			)
983
		), $items5);
984
985
		// Filter by null or empty values
986
		$items6 = $list->filter('Email', array(null, ''));
987
		$this->assertDOSEquals(array(
988
			array(
989
				'Name' => 'Stephen',
990
			),
991
			array(
992
				'Name' => 'Mitch',
993
			),
994
			array(
995
				'Name' => 'Hamish',
996
			)
997
		), $items6);
998
	}
999
1000
	/**
1001
	 * Test null checks with case modifiers
1002
	 */
1003
	public function testFilterByNullCase() {
1004
		// Test with case (case/nocase both use same code path)
1005
		// Test with and without null, and with inclusion/exclusion permutations
1006
		$list = DataObjectTest_Fan::get();
1007
1008
		// Only an explicit NOT NULL should include null values
1009
		$items6 = $list->filter('Email:not:case', array(null, '', '[email protected]'));
1010
		$this->assertSQLContains(' AND "DataObjectTest_Fan"."Email" IS NOT NULL', $items6->sql());
1011
1012
		// These should all include values where Email IS NULL
1013
		$items7 = $list->filter('Email:nocase', array(null, '', '[email protected]'));
1014
		$this->assertSQLContains(' OR "DataObjectTest_Fan"."Email" IS NULL', $items7->sql());
1015
		$items8 = $list->filter('Email:not:case', array('', '[email protected]'));
1016
		$this->assertSQLContains(' OR "DataObjectTest_Fan"."Email" IS NULL', $items8->sql());
1017
1018
		// These should not contain any null checks at all
1019
		$items9 = $list->filter('Email:nocase', array('', '[email protected]'));
1020
		$this->assertSQLNotContains('"DataObjectTest_Fan"."Email" IS NULL', $items9->sql());
1021
		$this->assertSQLNotContains('"DataObjectTest_Fan"."Email" IS NOT NULL', $items9->sql());
1022
	}
1023
1024
	/**
1025
	 * $list = $list->filterByCallback(function($item, $list) { return $item->Age == 21; })
1026
	 */
1027
	public function testFilterByCallback() {
1028
		$team1ID = $this->idFromFixture('DataObjectTest_Team', 'team1');
1029
		$list = DataObjectTest_TeamComment::get();
1030
		$list = $list->filterByCallback(function ($item, $list) use ($team1ID) {
0 ignored issues
show
Unused Code introduced by
The parameter $list is not used and could be removed.

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

Loading history...
1031
			return $item->TeamID == $team1ID;
1032
		});
1033
1034
		$result = $list->column('Name');
1035
		$expected = array_intersect($result, array('Joe', 'Bob'));
1036
1037
		$this->assertEquals(2, $list->count());
1038
		$this->assertEquals($expected, $result, 'List should only contain comments from Team 1 (Joe and Bob)');
1039
		$this->assertTrue($list instanceof Filterable, 'The List should be of type SS_Filterable');
1040
	}
1041
1042
	/**
1043
	 * $list->exclude('Name', 'bob'); // exclude bob from list
1044
	 */
1045
	public function testSimpleExclude() {
1046
		$list = DataObjectTest_TeamComment::get();
1047
		$list = $list->exclude('Name', 'Bob');
1048
		$list = $list->sort('Name');
1049
		$this->assertEquals(2, $list->count());
1050
		$this->assertEquals('Joe', $list->first()->Name, 'First comment should be from Joe');
1051
		$this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
1052
	}
1053
//
1054
	/**
1055
	 * $list->exclude('Name', array('aziz', 'bob'); // exclude aziz and bob from list
1056
	 */
1057
	public function testSimpleExcludeWithMultiple() {
1058
		$list = DataObjectTest_TeamComment::get();
1059
		$list = $list->exclude('Name', array('Joe','Phil'));
1060
		$this->assertEquals(1, $list->count());
1061
		$this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob');
1062
	}
1063
1064
	/**
1065
	 * $list->exclude(array('Name'=>'bob, 'Age'=>21)); // negative version
1066
	 */
1067
	public function testMultipleExcludeWithMiss() {
1068
		$list = DataObjectTest_TeamComment::get();
1069
		$list = $list->exclude(array('Name'=>'Bob', 'Comment'=>'Does not match any comments'));
1070
		$this->assertEquals(3, $list->count());
1071
	}
1072
1073
	/**
1074
	 * $list->exclude(array('Name'=>'bob, 'Age'=>21)); // exclude bob that has Age 21
1075
	 */
1076
	public function testMultipleExclude() {
1077
		$list = DataObjectTest_TeamComment::get();
1078
		$list = $list->exclude(array('Name'=>'Bob', 'Comment'=>'This is a team comment by Bob'));
1079
		$this->assertEquals(2, $list->count());
1080
	}
1081
1082
	/**
1083
	 * Test that if an exclude() is applied to a filter(), the filter() is still preserved.
1084
	 */
1085
	public function testExcludeOnFilter() {
1086
		$list = DataObjectTest_TeamComment::get();
1087
		$list = $list->filter('Comment', 'Phil is a unique guy, and comments on team2');
1088
		$list = $list->exclude('Name', 'Bob');
1089
1090
		$sql = $list->sql($parameters);
1091
		$this->assertSQLContains(
1092
			'WHERE ("DataObjectTest_TeamComment"."Comment" = ?) AND (("DataObjectTest_TeamComment"."Name" != ? '
1093
			. 'OR "DataObjectTest_TeamComment"."Name" IS NULL))',
1094
			$sql);
1095
		$this->assertEquals(array('Phil is a unique guy, and comments on team2', 'Bob'), $parameters);
1096
	}
1097
1098
	public function testExcludeWithSearchFilter() {
1099
		$list = DataObjectTest_TeamComment::get();
1100
		$list = $list->exclude('Name:LessThan', 'Bob');
1101
1102
		$sql = $list->sql($parameters);
1103
		$this->assertSQLContains('WHERE (("DataObjectTest_TeamComment"."Name" >= ?))', $sql);
1104
		$this->assertEquals(array('Bob'), $parameters);
1105
	}
1106
1107
	/**
1108
	 * Test exact match filter with empty array items
1109
	 */
1110
	public function testEmptyFilter() {
1111
		$this->setExpectedException("InvalidArgumentException", 'Cannot filter "DataObjectTest_TeamComment"."Name" against an empty set');
1112
		$list = DataObjectTest_TeamComment::get();
1113
		$list->exclude('Name', array());
1114
	}
1115
1116
	/**
1117
	 * $list->exclude(array('Name'=>'bob, 'Age'=>array(21, 43))); // exclude bob with Age 21 or 43
1118
	 */
1119 View Code Duplication
	public function testMultipleExcludeWithMultipleThatCheersEitherTeam() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1120
		$list = DataObjectTest_TeamComment::get();
1121
		$list = $list->exclude(array('Name'=>'Bob', 'TeamID'=>array(
1122
			$this->idFromFixture('DataObjectTest_Team', 'team1'),
1123
			$this->idFromFixture('DataObjectTest_Team', 'team2')
1124
		)));
1125
		$list = $list->sort('Name');
1126
		$this->assertEquals(2, $list->count());
1127
		$this->assertEquals('Joe', $list->first()->Name, 'First comment should be from Phil');
1128
		$this->assertEquals('Phil', $list->last()->Name, 'First comment should be from Phil');
1129
	}
1130
1131
	/**
1132
	 * $list->exclude(array('Name'=>'bob, 'Age'=>array(21, 43))); // negative version
1133
	 */
1134
	public function testMultipleExcludeWithMultipleThatCheersOnNonExistingTeam() {
1135
		$list = DataObjectTest_TeamComment::get();
1136
		$list = $list->exclude(array('Name'=>'Bob', 'TeamID'=>array(3)));
1137
		$this->assertEquals(3, $list->count());
1138
	}
1139
1140
	/**
1141
	 * $list->exclude(array('Name'=>array('bob','phil'), 'Age'=>array(21, 43))); //negative version
1142
	 */
1143 View Code Duplication
	public function testMultipleExcludeWithNoExclusion() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1144
		$list = DataObjectTest_TeamComment::get();
1145
		$list = $list->exclude(array(
1146
			'Name'=>array('Bob','Joe'),
1147
			'Comment' => 'Phil is a unique guy, and comments on team2'));
1148
		$this->assertEquals(3, $list->count());
1149
	}
1150
1151
	/**
1152
	 *  $list->exclude(array('Name'=>array('bob','phil'), 'Age'=>array(21, 43)));
1153
	 */
1154
	public function testMultipleExcludeWithTwoArray() {
1155
		$list = DataObjectTest_TeamComment::get();
1156
		$list = $list->exclude(array('Name' => array('Bob','Joe'), 'TeamID' => array(
1157
			$this->idFromFixture('DataObjectTest_Team', 'team1'),
1158
			$this->idFromFixture('DataObjectTest_Team', 'team2')
1159
		)));
1160
		$this->assertEquals(1, $list->count());
1161
		$this->assertEquals('Phil', $list->last()->Name, 'Only comment should be from Phil');
1162
	}
1163
1164
	/**
1165
	 *  $list->exclude(array('Name'=>array('bob','phil'), 'Age'=>array(21, 43)));
1166
	 */
1167 View Code Duplication
	public function testMultipleExcludeWithTwoArrayOneTeam() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1168
		$list = DataObjectTest_TeamComment::get();
1169
		$list = $list->exclude(array(
1170
			'Name' => array('Bob', 'Phil'),
1171
			'TeamID' => array($this->idFromFixture('DataObjectTest_Team', 'team1'))));
1172
		$list = $list->sort('Name');
1173
		$this->assertEquals(2, $list->count());
1174
		$this->assertEquals('Joe', $list->first()->Name, 'First comment should be from Joe');
1175
		$this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil');
1176
	}
1177
1178
	/**
1179
	 *
1180
	 */
1181
	public function testSortByRelation() {
1182
		$list = DataObjectTest_TeamComment::get();
1183
		$list = $list->sort(array('Team.Title' => 'DESC'));
1184
		$this->assertEquals(3, $list->count());
1185
		$this->assertEquals($this->idFromFixture('DataObjectTest_Team', 'team2'), $list->first()->TeamID,
1186
			'First comment should be for Team 2');
1187
		$this->assertEquals($this->idFromFixture('DataObjectTest_Team', 'team1'), $list->last()->TeamID,
1188
			'Last comment should be for Team 1');
1189
	}
1190
1191
	public function testReverse() {
1192
		$list = DataObjectTest_TeamComment::get();
1193
		$list = $list->sort('Name');
1194
		$list = $list->reverse();
1195
1196
		$this->assertEquals('Bob', $list->last()->Name, 'Last comment should be from Bob');
1197
		$this->assertEquals('Phil', $list->first()->Name, 'First comment should be from Phil');
1198
	}
1199
1200 View Code Duplication
	public function testSortByComplexExpression() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1201
		// Test an expression with both spaces and commas. This test also tests that column() can be called
1202
		// with a complex sort expression, so keep using column() below
1203
		$list = DataObjectTest_Team::get()->sort(
1204
			'CASE WHEN "DataObjectTest_Team"."ClassName" = \'DataObjectTest_SubTeam\' THEN 0 ELSE 1 END, "Title" DESC'
1205
		);
1206
		$this->assertEquals(array(
1207
			'Subteam 3',
1208
			'Subteam 2',
1209
			'Subteam 1',
1210
			'Team 3',
1211
			'Team 2',
1212
			'Team 1',
1213
		), $list->column("Title"));
1214
	}
1215
}
1216