Completed
Push — master ( 33496d...9e3f76 )
by Daniel
12:54
created

DataQueryTest   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 317
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 10

Importance

Changes 2
Bugs 1 Features 0
Metric Value
dl 0
loc 317
rs 10
c 2
b 1
f 0
wmc 21
lcom 2
cbo 10

21 Methods

Rating   Name   Duplication   Size   Complexity  
B testApplyReplationDeepInheretence() 0 35 1
A testSortByJoinedFieldRetainsSourceInformation() 0 19 1
A testJoins() 0 11 1
A testApplyRelation() 0 12 1
A testRelationReturn() 0 19 1
A testRelationOrderWithCustomJoin() 0 5 1
A testDisjunctiveGroup() 0 13 1
A testConjunctiveGroup() 0 13 1
A testNestedGroups() 0 17 1
A testEmptySubgroup() 0 7 1
A testSubgroupHandoff() 0 16 1
A testOrderByMultiple() 0 8 1
A testDefaultSort() 0 5 1
A testDistinct() 0 10 1
A testComparisonClauseInt() 0 7 1
A testComparisonClauseDateFull() 0 7 1
A testComparisonClauseDateStartsWith() 0 7 1
A testComparisonClauseDateStartsPartial() 0 7 1
A testComparisonClauseTextCaseInsensitive() 0 7 1
A testComparisonClauseTextCaseSensitive() 0 11 1
B testConditionsIncludeTables() 0 35 1
1
<?php
2
3
class DataQueryTest extends SapphireTest {
4
5
	protected static $fixture_file = 'DataQueryTest.yml';
6
7
	protected $extraDataObjects = array(
8
		'DataQueryTest_A',
9
		'DataQueryTest_B',
10
		'DataQueryTest_C',
11
		'DataQueryTest_D',
12
		'DataQueryTest_E',
13
		'DataQueryTest_F',
14
		'DataQueryTest_G',
15
	);
16
17
18
	public function testSortByJoinedFieldRetainsSourceInformation() {
19
		$bar = new DataQueryTest_C();
20
		$bar->Title = "Bar";
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<DataQueryTest_C>. 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...
21
		$bar->write();
22
23
		$foo = new DataQueryTest_B();
24
		$foo->Title = "Foo";
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<DataQueryTest_B>. 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...
25
		$foo->TestC = $bar->ID;
0 ignored issues
show
Documentation introduced by
The property TestC does not exist on object<DataQueryTest_B>. 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...
26
		$foo->write();
27
28
		$query = new DataQuery('DataQueryTest_B');
29
		$result = $query->leftJoin(
30
			'DataQueryTest_C',
31
			"\"DataQueryTest_B\".\"TestCID\" = \"DataQueryTest_B\".\"ID\""
32
		)->sort('"DataQueryTest_B"."Title"', 'ASC');
33
34
		$result = $result->execute()->record();
35
		$this->assertEquals('Foo', $result['Title']);
36
	}
37
38
	/**
39
	 * Test the leftJoin() and innerJoin method of the DataQuery object
40
	 */
41
	public function testJoins() {
42
		$dq = new DataQuery('Member');
43
		$dq->innerJoin("Group_Members", "\"Group_Members\".\"MemberID\" = \"Member\".\"ID\"");
44
		$this->assertSQLContains("INNER JOIN \"Group_Members\" ON \"Group_Members\".\"MemberID\" = \"Member\".\"ID\"",
45
			$dq->sql($parameters));
46
47
		$dq = new DataQuery('Member');
48
		$dq->leftJoin("Group_Members", "\"Group_Members\".\"MemberID\" = \"Member\".\"ID\"");
49
		$this->assertSQLContains("LEFT JOIN \"Group_Members\" ON \"Group_Members\".\"MemberID\" = \"Member\".\"ID\"",
50
			$dq->sql($parameters));
51
	}
52
53
	public function testApplyRelation() {
54
		// Test applyRelation with two has_ones pointing to the same class
55
		$dq = new DataQuery('DataQueryTest_B');
56
		$dq->applyRelation('TestC');
57
		$this->assertTrue($dq->query()->isJoinedTo('DataQueryTest_C'));
58
		$this->assertContains('"DataQueryTest_C"."ID" = "DataQueryTest_B"."TestCID"', $dq->sql());
59
60
		$dq = new DataQuery('DataQueryTest_B');
61
		$dq->applyRelation('TestCTwo');
62
		$this->assertTrue($dq->query()->isJoinedTo('DataQueryTest_C'));
63
		$this->assertContains('"DataQueryTest_C"."ID" = "DataQueryTest_B"."TestCTwoID"', $dq->sql());
64
	}
65
66
	public function testApplyReplationDeepInheretence() {
67
		//test has_one relation
68
		$newDQ = new DataQuery('DataQueryTest_E');
69
		//apply a relation to a relation from an ancestor class
70
		$newDQ->applyRelation('TestA');
71
		$this->assertTrue($newDQ->query()->isJoinedTo('DataQueryTest_C'));
72
		$this->assertContains('"DataQueryTest_A"."ID" = "DataQueryTest_C"."TestAID"', $newDQ->sql($params));
73
74
		//test many_many relation
75
76
		//test many_many with separate inheritance
77
		$newDQ = new DataQuery('DataQueryTest_C');
78
		$baseDBTable = ClassInfo::baseDataClass('DataQueryTest_C');
79
		$newDQ->applyRelation('ManyTestAs');
80
		//check we are "joined" to the DataObject's table (there is no distinction between FROM or JOIN clauses)
81
		$this->assertTrue($newDQ->query()->isJoinedTo($baseDBTable));
82
		//check we are explicitly selecting "FROM" the DO's table
83
		$this->assertContains("FROM \"$baseDBTable\"", $newDQ->sql());
84
85
		//test many_many with shared inheritance
86
		$newDQ = new DataQuery('DataQueryTest_E');
87
		$baseDBTable = ClassInfo::baseDataClass('DataQueryTest_E');
88
		//check we are "joined" to the DataObject's table (there is no distinction between FROM or JOIN clauses)
89
		$this->assertTrue($newDQ->query()->isJoinedTo($baseDBTable));
90
		//check we are explicitly selecting "FROM" the DO's table
91
		$this->assertContains("FROM \"$baseDBTable\"", $newDQ->sql(), 'The FROM clause is missing from the query');
92
		$newDQ->applyRelation('ManyTestGs');
93
		//confirm we are still joined to the base table
94
		$this->assertTrue($newDQ->query()->isJoinedTo($baseDBTable));
95
		//double check it is the "FROM" clause
96
		$this->assertContains("FROM \"$baseDBTable\"", $newDQ->sql(), 'The FROM clause has been removed from the query');
97
		//another (potentially less crude check) for checking "FROM" clause
98
		$fromTables = $newDQ->query()->getFrom();
99
		$this->assertEquals('"' . $baseDBTable . '"', $fromTables[$baseDBTable]);
100
	}
101
102
	public function testRelationReturn() {
103
		$dq = new DataQuery('DataQueryTest_C');
104
		$this->assertEquals('DataQueryTest_A', $dq->applyRelation('TestA'),
105
			'DataQuery::applyRelation should return the name of the related object.');
106
		$this->assertEquals('DataQueryTest_A', $dq->applyRelation('TestAs'),
107
			'DataQuery::applyRelation should return the name of the related object.');
108
		$this->assertEquals('DataQueryTest_A', $dq->applyRelation('ManyTestAs'),
109
			'DataQuery::applyRelation should return the name of the related object.');
110
111
		$this->assertEquals('DataQueryTest_B', $dq->applyRelation('TestB'),
112
			'DataQuery::applyRelation should return the name of the related object.');
113
		$this->assertEquals('DataQueryTest_B', $dq->applyRelation('TestBs'),
114
			'DataQuery::applyRelation should return the name of the related object.');
115
		$this->assertEquals('DataQueryTest_B', $dq->applyRelation('ManyTestBs'),
116
			'DataQuery::applyRelation should return the name of the related object.');
117
		$newDQ = new DataQuery('DataQueryTest_E');
118
		$this->assertEquals('DataQueryTest_A', $newDQ->applyRelation('TestA'),
119
			'DataQuery::applyRelation should return the name of the related object.');
120
	}
121
122
	public function testRelationOrderWithCustomJoin() {
123
		$dataQuery = new DataQuery('DataQueryTest_B');
124
		$dataQuery->innerJoin('DataQueryTest_D', '"DataQueryTest_D"."RelationID" = "DataQueryTest_B"."ID"');
125
		$dataQuery->execute();
126
	}
127
128
	public function testDisjunctiveGroup() {
129
		$dq = new DataQuery('DataQueryTest_A');
130
131
		$dq->where('DataQueryTest_A.ID = 2');
132
		$subDq = $dq->disjunctiveGroup();
133
		$subDq->where('DataQueryTest_A.Name = \'John\'');
134
		$subDq->where('DataQueryTest_A.Name = \'Bob\'');
135
136
		$this->assertSQLContains(
137
			"WHERE (DataQueryTest_A.ID = 2) AND ((DataQueryTest_A.Name = 'John') OR (DataQueryTest_A.Name = 'Bob'))",
138
			$dq->sql($parameters)
139
		);
140
	}
141
142
	public function testConjunctiveGroup() {
143
		$dq = new DataQuery('DataQueryTest_A');
144
145
		$dq->where('DataQueryTest_A.ID = 2');
146
		$subDq = $dq->conjunctiveGroup();
147
		$subDq->where('DataQueryTest_A.Name = \'John\'');
148
		$subDq->where('DataQueryTest_A.Name = \'Bob\'');
149
150
		$this->assertSQLContains(
151
			"WHERE (DataQueryTest_A.ID = 2) AND ((DataQueryTest_A.Name = 'John') AND (DataQueryTest_A.Name = 'Bob'))",
152
			$dq->sql($parameters)
153
		);
154
	}
155
156
	/**
157
	 * @todo Test paramaterised
158
	 */
159
	public function testNestedGroups() {
160
		$dq = new DataQuery('DataQueryTest_A');
161
162
		$dq->where('DataQueryTest_A.ID = 2');
163
		$subDq = $dq->disjunctiveGroup();
164
		$subDq->where('DataQueryTest_A.Name = \'John\'');
165
		$subSubDq = $subDq->conjunctiveGroup();
166
		$subSubDq->where('DataQueryTest_A.Age = 18');
167
		$subSubDq->where('DataQueryTest_A.Age = 50');
168
		$subDq->where('DataQueryTest_A.Name = \'Bob\'');
169
170
		$this->assertSQLContains(
171
			"WHERE (DataQueryTest_A.ID = 2) AND ((DataQueryTest_A.Name = 'John') OR ((DataQueryTest_A.Age = 18) "
172
				. "AND (DataQueryTest_A.Age = 50)) OR (DataQueryTest_A.Name = 'Bob'))",
173
			$dq->sql($parameters)
174
		);
175
	}
176
177
	public function testEmptySubgroup() {
178
		$dq = new DataQuery('DataQueryTest_A');
179
		$dq->conjunctiveGroup();
180
181
		// Empty groups should have no where condition at all
182
		$this->assertSQLNotContains('WHERE', $dq->sql($parameters));
183
	}
184
185
	public function testSubgroupHandoff() {
186
		$dq = new DataQuery('DataQueryTest_A');
187
		$subDq = $dq->disjunctiveGroup();
188
189
		$orgDq = clone $dq;
190
191
		$subDq->sort('"DataQueryTest_A"."Name"');
192
		$orgDq->sort('"DataQueryTest_A"."Name"');
193
194
		$this->assertSQLEquals($dq->sql($parameters), $orgDq->sql($parameters));
195
196
		$subDq->limit(5, 7);
197
		$orgDq->limit(5, 7);
198
199
		$this->assertSQLEquals($dq->sql($parameters), $orgDq->sql($parameters));
200
	}
201
202
	public function testOrderByMultiple() {
203
		$dq = new DataQuery('SQLSelectTest_DO');
204
		$dq = $dq->sort('"Name" ASC, MID("Name", 8, 1) DESC');
205
		$this->assertContains(
206
			'ORDER BY "SQLSelectTest_DO"."Name" ASC, "_SortColumn0" DESC',
207
			$dq->sql($parameters)
208
		);
209
	}
210
211
	public function testDefaultSort() {
212
		$query = new DataQuery('DataQueryTest_E');
213
		$result = $query->column('Title');
214
		$this->assertEquals(array('First', 'Second', 'Last'), $result);
215
	}
216
217
	public function testDistinct() {
218
		$query = new DataQuery('DataQueryTest_E');
219
		$this->assertContains('SELECT DISTINCT', $query->sql($params), 'Query is set as distinct by default');
220
221
		$query = $query->distinct(false);
222
		$this->assertNotContains('SELECT DISTINCT', $query->sql($params), 'Query does not contain distinct');
223
224
		$query = $query->distinct(true);
225
		$this->assertContains('SELECT DISTINCT', $query->sql($params), 'Query contains distinct');
226
 	}
227
228
	public function testComparisonClauseInt() {
229
		DB::query("INSERT INTO \"DataQueryTest_F\" (\"SortOrder\") VALUES (2)");
230
		$query = new DataQuery('DataQueryTest_F');
231
		$query->where(DB::get_conn()->comparisonClause('"SortOrder"', '2'));
232
		$this->assertGreaterThan(0, $query->count(), "Couldn't find SortOrder");
233
		$this->resetDBSchema(true);
234
	}
235
236
	public function testComparisonClauseDateFull() {
237
		DB::query("INSERT INTO \"DataQueryTest_F\" (\"MyDate\") VALUES ('1988-03-04 06:30')");
238
		$query = new DataQuery('DataQueryTest_F');
239
		$query->where(DB::get_conn()->comparisonClause('"MyDate"', '1988-03-04%'));
240
		$this->assertGreaterThan(0, $query->count(), "Couldn't find MyDate");
241
		$this->resetDBSchema(true);
242
	}
243
244
	public function testComparisonClauseDateStartsWith() {
245
		DB::query("INSERT INTO \"DataQueryTest_F\" (\"MyDate\") VALUES ('1988-03-04 06:30')");
246
		$query = new DataQuery('DataQueryTest_F');
247
		$query->where(DB::get_conn()->comparisonClause('"MyDate"', '1988%'));
248
		$this->assertGreaterThan(0, $query->count(), "Couldn't find MyDate");
249
		$this->resetDBSchema(true);
250
	}
251
252
	public function testComparisonClauseDateStartsPartial() {
253
		DB::query("INSERT INTO \"DataQueryTest_F\" (\"MyDate\") VALUES ('1988-03-04 06:30')");
254
		$query = new DataQuery('DataQueryTest_F');
255
		$query->where(DB::get_conn()->comparisonClause('"MyDate"', '%03-04%'));
256
		$this->assertGreaterThan(0, $query->count(), "Couldn't find MyDate");
257
		$this->resetDBSchema(true);
258
	}
259
260
	public function testComparisonClauseTextCaseInsensitive() {
261
		DB::query("INSERT INTO \"DataQueryTest_F\" (\"MyString\") VALUES ('HelloWorld')");
262
		$query = new DataQuery('DataQueryTest_F');
263
		$query->where(DB::get_conn()->comparisonClause('"MyString"', 'helloworld'));
264
		$this->assertGreaterThan(0, $query->count(), "Couldn't find MyString");
265
		$this->resetDBSchema(true);
266
	}
267
268
	public function testComparisonClauseTextCaseSensitive() {
269
		DB::query("INSERT INTO \"DataQueryTest_F\" (\"MyString\") VALUES ('HelloWorld')");
270
		$query = new DataQuery('DataQueryTest_F');
271
		$query->where(DB::get_conn()->comparisonClause('"MyString"', 'HelloWorld', false, false, true));
272
		$this->assertGreaterThan(0, $query->count(), "Couldn't find MyString");
273
274
		$query2 = new DataQuery('DataQueryTest_F');
275
		$query2->where(DB::get_conn()->comparisonClause('"MyString"', 'helloworld', false, false, true));
276
		$this->assertEquals(0, $query2->count(), "Found mystring. Shouldn't be able too.");
277
		$this->resetDBSchema(true);
278
	}
279
280
	/**
281
	 * Tests that getFinalisedQuery can include all tables
282
	 */
283
	public function testConditionsIncludeTables() {
284
		// Including filter on parent table only doesn't pull in second
285
		$query = new DataQuery('DataQueryTest_C');
286
		$query->sort('"SortOrder"');
287
		$query->where(array(
288
			'"DataQueryTest_C"."Title" = ?' => array('First')
289
		));
290
		$result = $query->getFinalisedQuery(array('Title'));
291
		$from = $result->getFrom();
292
		$this->assertContains('DataQueryTest_C', array_keys($from));
293
		$this->assertNotContains('DataQueryTest_E', array_keys($from));
294
295
		// Including filter on sub-table requires it
296
		$query = new DataQuery('DataQueryTest_C');
297
		$query->sort('"SortOrder"');
298
		$query->where(array(
299
			'"DataQueryTest_C"."Title" = ? OR "DataQueryTest_E"."SortOrder" > ?' => array(
300
				'First', 2
301
			)
302
		));
303
		$result = $query->getFinalisedQuery(array('Title'));
304
		$from = $result->getFrom();
305
306
		// Check that including "SortOrder" prompted inclusion of DataQueryTest_E table
307
		$this->assertContains('DataQueryTest_C', array_keys($from));
308
		$this->assertContains('DataQueryTest_E', array_keys($from));
309
		$arrayResult = iterator_to_array($result->execute());
310
		$first = array_shift($arrayResult);
311
		$this->assertNotNull($first);
312
		$this->assertEquals('First', $first['Title']);
313
		$second = array_shift($arrayResult);
314
		$this->assertNotNull($second);
315
		$this->assertEquals('Last', $second['Title']);
316
		$this->assertEmpty(array_shift($arrayResult));
317
	}
318
319
}
320
321
322
class DataQueryTest_A extends DataObject implements TestOnly {
323
324
	private static $db = array(
325
		'Name' => 'Varchar',
326
	);
327
328
	private static $has_one = array(
329
		'TestC' => 'DataQueryTest_C',
330
	);
331
}
332
333
class DataQueryTest_B extends DataObject implements TestOnly {
334
335
	private static $db = array(
336
		'Title' => 'Varchar',
337
	);
338
339
	private static $has_one = array(
340
		'TestC' => 'DataQueryTest_C',
341
		'TestCTwo' => 'DataQueryTest_C',
342
	);
343
}
344
345
class DataQueryTest_C extends DataObject implements TestOnly {
346
347
	private static $db = array(
348
		'Title' => 'Varchar'
349
	);
350
351
	private static $has_one = array(
352
		'TestA' => 'DataQueryTest_A',
353
		'TestB' => 'DataQueryTest_B',
354
	);
355
356
	private static $has_many = array(
357
		'TestAs' => 'DataQueryTest_A',
358
		'TestBs' => 'DataQueryTest_B.TestC',
359
		'TestBsTwo' => 'DataQueryTest_B.TestCTwo',
360
	);
361
362
	private static $many_many = array(
363
		'ManyTestAs' => 'DataQueryTest_A',
364
		'ManyTestBs' => 'DataQueryTest_B',
365
	);
366
}
367
368
class DataQueryTest_D extends DataObject implements TestOnly {
369
370
	private static $has_one = array(
371
		'Relation' => 'DataQueryTest_B',
372
	);
373
}
374
375
class DataQueryTest_E extends DataQueryTest_C implements TestOnly {
376
377
	private static $db = array(
378
		'SortOrder' => 'Int'
379
	);
380
381
	private static $many_many = array(
382
		'ManyTestGs' => 'DataQueryTest_G',
383
	);
384
385
	private static $default_sort = '"DataQueryTest_E"."SortOrder" ASC';
386
}
387
388
class DataQueryTest_F extends DataObject implements TestOnly {
389
390
	private static $db = array(
391
		'SortOrder' => 'Int',
392
		'MyDate' => 'SS_Datetime',
393
		'MyString' => 'Text'
394
	);
395
}
396
397
class DataQueryTest_G extends DataQueryTest_C implements TestOnly {
398
399
	private static $belongs_many_many = array(
400
		'ManyTestEs' => 'DataQueryTest_E',
401
	);
402
403
}
404