Completed
Push — master ( 2d07f9...059454 )
by Daniel
11:44
created

DataQueryTest::testApplyReplationDeepInheretence()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 35
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 19
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 35
rs 8.8571
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
282
283
class DataQueryTest_A extends DataObject implements TestOnly {
284
285
	private static $db = array(
286
		'Name' => 'Varchar',
287
	);
288
289
	private static $has_one = array(
290
		'TestC' => 'DataQueryTest_C',
291
	);
292
}
293
294
class DataQueryTest_B extends DataObject implements TestOnly {
295
296
	private static $db = array(
297
		'Title' => 'Varchar',
298
	);
299
300
	private static $has_one = array(
301
		'TestC' => 'DataQueryTest_C',
302
		'TestCTwo' => 'DataQueryTest_C',
303
	);
304
}
305
306
class DataQueryTest_C extends DataObject implements TestOnly {
307
308
	private static $db = array(
309
		'Title' => 'Varchar'
310
	);
311
312
	private static $has_one = array(
313
		'TestA' => 'DataQueryTest_A',
314
		'TestB' => 'DataQueryTest_B',
315
	);
316
317
	private static $has_many = array(
318
		'TestAs' => 'DataQueryTest_A',
319
		'TestBs' => 'DataQueryTest_B.TestC',
320
		'TestBsTwo' => 'DataQueryTest_B.TestCTwo',
321
	);
322
323
	private static $many_many = array(
324
		'ManyTestAs' => 'DataQueryTest_A',
325
		'ManyTestBs' => 'DataQueryTest_B',
326
	);
327
}
328
329
class DataQueryTest_D extends DataObject implements TestOnly {
330
331
	private static $has_one = array(
332
		'Relation' => 'DataQueryTest_B',
333
	);
334
}
335
336
class DataQueryTest_E extends DataQueryTest_C implements TestOnly {
337
338
	private static $db = array(
339
		'SortOrder' => 'Int'
340
	);
341
342
	private static $many_many = array(
343
		'ManyTestGs' => 'DataQueryTest_G',
344
	);
345
346
	private static $default_sort = '"DataQueryTest_E"."SortOrder" ASC';
347
}
348
349
class DataQueryTest_F extends DataObject implements TestOnly {
350
351
	private static $db = array(
352
		'SortOrder' => 'Int',
353
		'MyDate' => 'SS_Datetime',
354
		'MyString' => 'Text'
355
	);
356
}
357
358
class DataQueryTest_G extends DataQueryTest_C implements TestOnly {
359
360
	private static $belongs_many_many = array(
361
		'ManyTestEs' => 'DataQueryTest_E',
362
	);
363
364
}
365