Completed
Push — 3.7 ( 53f5c3...014c99 )
by
unknown
05:16 queued 11s
created

testWriteManipulationWithNonScalarValuesDisallowed()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 11
rs 9.9
c 0
b 0
f 0
1
<?php
2
/**
3
 * @package framework
4
 * @subpackage tests
5
 */
6
class DataObjectTest extends SapphireTest {
7
8
	protected static $fixture_file = 'DataObjectTest.yml';
9
10
	protected $extraDataObjects = array(
11
		'DataObjectTest_Team',
12
		'DataObjectTest_Fixture',
13
		'DataObjectTest_SubTeam',
14
		'OtherSubclassWithSameField',
15
		'DataObjectTest_FieldlessTable',
16
		'DataObjectTest_FieldlessSubTable',
17
		'DataObjectTest_ValidatedObject',
18
		'DataObjectTest_Player',
19
		'DataObjectTest_TeamComment',
20
		'DataObjectTest_EquipmentCompany',
21
		'DataObjectTest_SubEquipmentCompany',
22
		'DataObjectTest\NamespacedClass',
23
		'DataObjectTest\RelationClass',
24
		'DataObjectTest_ExtendedTeamComment',
25
		'DataObjectTest_Company',
26
		'DataObjectTest_Staff',
27
		'DataObjectTest_CEO',
28
		'DataObjectTest_Fan',
29
		'DataObjectTest_Play',
30
		'DataObjectTest_Ploy',
31
		'DataObjectTest_Bogey',
32
		'DataObjectTest_Sortable',
33
		'ManyManyListTest_Product',
34
		'ManyManyListTest_Category',
35
        'MockDynamicAssignmentDataObject'
36
	);
37
38
	/**
39
	 * @dataProvider provideSingletons
40
	 */
41
	public function testSingleton($inst, $defaultValue, $altDefaultValue)
42
	{
43
		// Calls to scaffold the test database may have cached service specs for DataObjects
44
		// with the incorrect 'type' set (singleton instead of prototype)
45
		Injector::nest();
46
		$reflectionProp = new ReflectionProperty('Injector', 'specs');
47
		$reflectionProp->setAccessible(true);
48
		$reflectionProp->setValue(Injector::inst(), array());
49
50
		$inst = $inst();
51
		// Test that populateDefaults() isn't called on singletons
52
		// which can lead to SQL errors during build, and endless loops
53
		if ($defaultValue) {
54
			$this->assertEquals($defaultValue, $inst->MyFieldWithDefault);
55
		} else {
56
			$this->assertEmpty($inst->MyFieldWithDefault);
57
		}
58
59
		if ($altDefaultValue) {
60
			$this->assertEquals($altDefaultValue, $inst->MyFieldWithAltDefault);
61
		} else {
62
			$this->assertEmpty($inst->MyFieldWithAltDefault);
63
		}
64
65
		Injector::unnest();
66
	}
67
68
	public function provideSingletons()
69
	{
70
		// because PHPUnit evalutes test providers *before* setUp methods
71
		// any extensions added in the setUp methods won't be available
72
		// we must return closures to generate the arguments at run time
73
		return array(
74
			array(function () {
75
				return DataObjectTest_Fixture::create();
76
			}, 'Default Value', 'Default Value'),
77
			array(function () {
78
				return new DataObjectTest_Fixture();
79
			}, 'Default Value', 'Default Value'),
80
			array(function () {
81
				return singleton('DataObjectTest_Fixture');
82
			}, null, null),
83
			array(function () {
84
				return DataObjectTest_Fixture::singleton();
85
			}, null, null),
86
			array(function () {
87
				return new DataObjectTest_Fixture(null, true);
88
			}, null, null),
89
		);
90
	}
91
92
	public function testDb() {
93
		$obj = new DataObjectTest_TeamComment();
94
		$dbFields = $obj->db();
95
96
		// Assert fields are included
97
		$this->assertArrayHasKey('Name', $dbFields);
98
99
		// Assert the base fields are excluded
100
		$this->assertArrayNotHasKey('Created', $dbFields);
101
		$this->assertArrayNotHasKey('LastEdited', $dbFields);
102
		$this->assertArrayNotHasKey('ClassName', $dbFields);
103
		$this->assertArrayNotHasKey('ID', $dbFields);
104
105
		// Assert that the correct field type is returned when passing a field
106
		$this->assertEquals('Varchar', $obj->db('Name'));
107
		$this->assertEquals('Text', $obj->db('Comment'));
108
109
		$obj = new DataObjectTest_ExtendedTeamComment();
110
		$dbFields = $obj->db();
111
112
		// Assert overloaded fields have correct data type
113
		$this->assertEquals('HTMLText', $obj->db('Comment'));
114
		$this->assertEquals('HTMLText', $dbFields['Comment'],
115
			'Calls to DataObject::db without a field specified return correct data types');
116
117
		// assertEquals doesn't verify the order of array elements, so access keys manually to check order:
118
		// expected: array('Name' => 'Varchar', 'Comment' => 'HTMLText')
119
		reset($dbFields);
120
		$this->assertEquals('Name', key($dbFields), 'DataObject::db returns fields in correct order');
121
		next($dbFields);
122
		$this->assertEquals('Comment', key($dbFields), 'DataObject::db returns fields in correct order');
123
	}
124
125
	public function testConstructAcceptsValues() {
126
		// Values can be an array...
127
		$player = new DataObjectTest_Player(array(
128
			'FirstName' => 'James',
129
			'Surname' => 'Smith'
130
		));
131
132
		$this->assertEquals('James', $player->FirstName);
133
		$this->assertEquals('Smith', $player->Surname);
134
135
		// ... or a stdClass inst
136
		$data = new stdClass();
137
		$data->FirstName = 'John';
138
		$data->Surname = 'Doe';
139
		$player = new DataObjectTest_Player($data);
140
141
		$this->assertEquals('John', $player->FirstName);
142
		$this->assertEquals('Doe', $player->Surname);
143
144
		// IDs should be stored as integers, not strings
145
		$player = new DataObjectTest_Player(array('ID' => '5'));
146
		$this->assertSame(5, $player->ID);
147
	}
148
149
	public function testValidObjectsForBaseFields() {
150
		$obj = new DataObjectTest_ValidatedObject();
151
152
		foreach (array('Created', 'LastEdited', 'ClassName', 'ID') as $field) {
153
			$helper = $obj->dbObject($field);
154
			$this->assertTrue(
155
				($helper instanceof DBField),
156
				"for {$field} expected helper to be DBField, but was " .
157
				(is_object($helper) ? get_class($helper) : "null")
158
			);
159
		}
160
	}
161
162
	public function testDataIntegrityWhenTwoSubclassesHaveSameField() {
163
		// Save data into DataObjectTest_SubTeam.SubclassDatabaseField
164
		$obj = new DataObjectTest_SubTeam();
165
		$obj->SubclassDatabaseField = "obj-SubTeam";
0 ignored issues
show
Documentation introduced by
The property SubclassDatabaseField does not exist on object<DataObjectTest_SubTeam>. 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...
166
		$obj->write();
167
168
		// Change the class
169
		$obj->ClassName = 'OtherSubclassWithSameField';
170
		$obj->write();
171
		$obj->flushCache();
172
173
		// Re-fetch from the database and confirm that the data is sourced from
174
		// OtherSubclassWithSameField.SubclassDatabaseField
175
		$obj = DataObject::get_by_id('DataObjectTest_Team', $obj->ID);
176
		$this->assertNull($obj->SubclassDatabaseField);
177
178
		// Confirm that save the object in the other direction.
179
		$obj->SubclassDatabaseField = 'obj-Other';
0 ignored issues
show
Documentation introduced by
The property SubclassDatabaseField does not exist on object<DataObject>. 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...
180
		$obj->write();
181
182
		$obj->ClassName = 'DataObjectTest_SubTeam';
183
		$obj->write();
184
		$obj->flushCache();
185
186
		// If we restore the class, the old value has been lying dormant and will be available again.
187
		// NOTE: This behaviour is volatile; we may change this in the future to clear fields that
188
		// are no longer relevant when changing ClassName
189
		$obj = DataObject::get_by_id('DataObjectTest_Team', $obj->ID);
190
		$this->assertEquals('obj-SubTeam', $obj->SubclassDatabaseField);
191
	}
192
193
	/**
194
	 * Test deletion of DataObjects
195
	 *   - Deleting using delete() on the DataObject
196
	 *   - Deleting using DataObject::delete_by_id()
197
	 */
198
	public function testDelete() {
199
		// Test deleting using delete() on the DataObject
200
		// Get the first page
201
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain1');
202
		$objID = $obj->ID;
203
		// Check the page exists before deleting
204
		$this->assertTrue(is_object($obj) && $obj->exists());
205
		// Delete the page
206
		$obj->delete();
207
		// Check that page does not exist after deleting
208
		$obj = DataObject::get_by_id('DataObjectTest_Player', $objID);
209
		$this->assertTrue(!$obj || !$obj->exists());
210
211
212
		// Test deleting using DataObject::delete_by_id()
213
		// Get the second page
214
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain2');
215
		$objID = $obj->ID;
216
		// Check the page exists before deleting
217
		$this->assertTrue(is_object($obj) && $obj->exists());
218
		// Delete the page
219
		DataObject::delete_by_id('DataObjectTest_Player', $obj->ID);
220
		// Check that page does not exist after deleting
221
		$obj = DataObject::get_by_id('DataObjectTest_Player', $objID);
222
		$this->assertTrue(!$obj || !$obj->exists());
223
	}
224
225
	/**
226
	 * Test methods that get DataObjects
227
	 *   - DataObject::get()
228
	 *       - All records of a DataObject
229
	 *       - Filtering
230
	 *       - Sorting
231
	 *       - Joins
232
	 *       - Limit
233
	 *       - Container class
234
	 *   - DataObject::get_by_id()
235
	 *   - DataObject::get_one()
236
	 *        - With and without caching
237
	 *        - With and without ordering
238
	 */
239
	public function testGet() {
240
		// Test getting all records of a DataObject
241
		$comments = DataObject::get('DataObjectTest_TeamComment');
242
		$this->assertEquals(3, $comments->Count());
243
244
		// Test WHERE clause
245
		$comments = DataObject::get('DataObjectTest_TeamComment', "\"Name\"='Bob'");
246
		$this->assertEquals(1, $comments->Count());
247
		foreach($comments as $comment) {
248
			$this->assertEquals('Bob', $comment->Name);
249
		}
250
251
		// Test sorting
252
		$comments = DataObject::get('DataObjectTest_TeamComment', '', "\"Name\" ASC");
253
		$this->assertEquals(3, $comments->Count());
254
		$this->assertEquals('Bob', $comments->First()->Name);
255
		$comments = DataObject::get('DataObjectTest_TeamComment', '', "\"Name\" DESC");
256
		$this->assertEquals(3, $comments->Count());
257
		$this->assertEquals('Phil', $comments->First()->Name);
258
259
		// Test limit
260
		$comments = DataObject::get('DataObjectTest_TeamComment', '', "\"Name\" ASC", '', '1,2');
261
		$this->assertEquals(2, $comments->Count());
262
		$this->assertEquals('Joe', $comments->First()->Name);
263
		$this->assertEquals('Phil', $comments->Last()->Name);
264
265
		// Test get_by_id()
266
		$captain1ID = $this->idFromFixture('DataObjectTest_Player', 'captain1');
267
		$captain1 = DataObject::get_by_id('DataObjectTest_Player', $captain1ID);
268
		$this->assertEquals('Captain', $captain1->FirstName);
269
270
		// Test get_one() without caching
271
		$comment1 = DataObject::get_one('DataObjectTest_TeamComment', array(
272
			'"DataObjectTest_TeamComment"."Name"' => 'Joe'
273
		), false);
274
		$comment1->Comment = "Something Else";
0 ignored issues
show
Documentation introduced by
The property Comment does not exist on object<DataObject>. 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...
275
276
		$comment2 = DataObject::get_one('DataObjectTest_TeamComment', array(
277
			'"DataObjectTest_TeamComment"."Name"' => 'Joe'
278
		), false);
279
		$this->assertNotEquals($comment1->Comment, $comment2->Comment);
280
281
		// Test get_one() with caching
282
		$comment1 = DataObject::get_one('DataObjectTest_TeamComment', array(
283
			'"DataObjectTest_TeamComment"."Name"' => 'Bob'
284
		), true);
285
		$comment1->Comment = "Something Else";
0 ignored issues
show
Documentation introduced by
The property Comment does not exist on object<DataObject>. 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...
286
287
		$comment2 = DataObject::get_one('DataObjectTest_TeamComment', array(
288
			'"DataObjectTest_TeamComment"."Name"' => 'Bob'
289
		), true);
290
		$this->assertEquals((string)$comment1->Comment, (string)$comment2->Comment);
291
292
		// Test get_one() with order by without caching
293
		$comment = DataObject::get_one('DataObjectTest_TeamComment', '', false, "\"Name\" ASC");
294
		$this->assertEquals('Bob', $comment->Name);
295
296
		$comment = DataObject::get_one('DataObjectTest_TeamComment', '', false, "\"Name\" DESC");
297
		$this->assertEquals('Phil', $comment->Name);
298
299
		// Test get_one() with order by with caching
300
		$comment = DataObject::get_one('DataObjectTest_TeamComment', '', true, '"Name" ASC');
301
		$this->assertEquals('Bob', $comment->Name);
302
		$comment = DataObject::get_one('DataObjectTest_TeamComment', '', true, '"Name" DESC');
303
		$this->assertEquals('Phil', $comment->Name);
304
	}
305
306
	public function testGetCaseInsensitive() {
307
		// Test get_one() with bad case on the classname
308
		// Note: This will succeed only if the underlying DB server supports case-insensitive
309
		// table names (e.g. such as MySQL, but not SQLite3)
310
		if(!(DB::get_conn() instanceof MySQLDatabase)) {
311
			$this->markTestSkipped('MySQL only');
312
		}
313
314
		$subteam1 = DataObject::get_one('dataobjecttest_subteam', array(
315
			'"DataObjectTest_Team"."Title"' => 'Subteam 1'
316
		), true);
317
		$this->assertNotEmpty($subteam1);
318
		$this->assertEquals($subteam1->Title, "Subteam 1");
319
	}
320
321
	public function testGetSubclassFields() {
322
		/* Test that fields / has_one relations from the parent table and the subclass tables are extracted */
323
		$captain1 = $this->objFromFixture("DataObjectTest_Player", "captain1");
324
		// Base field
325
		$this->assertEquals('Captain', $captain1->FirstName);
326
		// Subclass field
327
		$this->assertEquals('007', $captain1->ShirtNumber);
328
		// Subclass has_one relation
329
		$this->assertEquals($this->idFromFixture('DataObjectTest_Team', 'team1'), $captain1->FavouriteTeamID);
330
	}
331
332
	public function testGetRelationClass() {
333
		$obj = new DataObjectTest_Player();
334
		$this->assertEquals(singleton('DataObjectTest_Player')->getRelationClass('FavouriteTeam'),
335
			'DataObjectTest_Team', 'has_one is properly inspected');
336
		$this->assertEquals(singleton('DataObjectTest_Company')->getRelationClass('CurrentStaff'),
337
			'DataObjectTest_Staff', 'has_many is properly inspected');
338
		$this->assertEquals(singleton('DataObjectTest_Team')->getRelationClass('Players'), 'DataObjectTest_Player',
339
			'many_many is properly inspected');
340
		$this->assertEquals(singleton('DataObjectTest_Player')->getRelationClass('Teams'), 'DataObjectTest_Team',
341
			'belongs_many_many is properly inspected');
342
		$this->assertEquals(singleton('DataObjectTest_CEO')->getRelationClass('Company'), 'DataObjectTest_Company',
343
			'belongs_to is properly inspected');
344
		$this->assertEquals(singleton('DataObjectTest_Fan')->getRelationClass('Favourite'), 'DataObject',
345
			'polymorphic has_one is properly inspected');
346
	}
347
348
	/**
349
	 * Test that has_one relations can be retrieved
350
	 */
351
	public function testGetHasOneRelations() {
352
		$captain1 = $this->objFromFixture("DataObjectTest_Player", "captain1");
353
		$team1ID = $this->idFromFixture('DataObjectTest_Team', 'team1');
354
355
		// There will be a field called (relname)ID that contains the ID of the
356
		// object linked to via the has_one relation
357
		$this->assertEquals($team1ID, $captain1->FavouriteTeamID);
358
359
		// There will be a method called $obj->relname() that returns the object itself
360
		$this->assertEquals($team1ID, $captain1->FavouriteTeam()->ID);
361
362
		// Check entity with polymorphic has-one
363
		$fan1 = $this->objFromFixture("DataObjectTest_Fan", "fan1");
364
		$this->assertTrue((bool)$fan1->hasValue('Favourite'));
365
366
		// There will be fields named (relname)ID and (relname)Class for polymorphic
367
		// entities
368
		$this->assertEquals($team1ID, $fan1->FavouriteID);
369
		$this->assertEquals('DataObjectTest_Team', $fan1->FavouriteClass);
370
371
		// There will be a method called $obj->relname() that returns the object itself
372
		$favourite = $fan1->Favourite();
373
		$this->assertEquals($team1ID, $favourite->ID);
374
		$this->assertInstanceOf('DataObjectTest_Team', $favourite);
375
376
		// check behaviour of dbObject with polymorphic relations
377
		$favouriteDBObject = $fan1->dbObject('Favourite');
378
		$favouriteValue = $favouriteDBObject->getValue();
379
		$this->assertInstanceOf('PolymorphicForeignKey', $favouriteDBObject);
380
		$this->assertEquals($favourite->ID, $favouriteValue->ID);
381
		$this->assertEquals($favourite->ClassName, $favouriteValue->ClassName);
382
	}
383
384
	/**
385
	 * Simple test to ensure that namespaced classes and polymorphic relations work together
386
	 */
387
	public function testPolymorphicNamespacedRelations() {
388
		$parent = new \DataObjectTest\NamespacedClass();
389
		$parent->Name = 'New Parent';
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...
390
		$parent->write();
391
392
		$child = new \DataObjectTest\RelationClass();
393
		$child->Title = 'New Child';
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<DataObjectTest\RelationClass>. 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...
394
		$child->write();
395
		$parent->Relations()->add($child);
0 ignored issues
show
Bug introduced by
The method Relations() does not exist on DataObjectTest\NamespacedClass. Did you maybe mean duplicateManyManyRelations()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
396
397
		$this->assertEquals(1, $parent->Relations()->count());
0 ignored issues
show
Bug introduced by
The method Relations() does not exist on DataObjectTest\NamespacedClass. Did you maybe mean duplicateManyManyRelations()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
398
		$this->assertEquals(array('New Child'), $parent->Relations()->column('Title'));
0 ignored issues
show
Bug introduced by
The method Relations() does not exist on DataObjectTest\NamespacedClass. Did you maybe mean duplicateManyManyRelations()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
399
		$this->assertEquals('New Parent', $child->Parent()->Name);
0 ignored issues
show
Bug introduced by
The method Parent() does not exist on DataObjectTest\RelationClass. Did you maybe mean parentClass()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
400
	}
401
402
	public function testLimitAndCount() {
403
		$players = DataObject::get("DataObjectTest_Player");
404
405
		// There's 4 records in total
406
		$this->assertEquals(4, $players->count());
407
408
		// Testing "##, ##" syntax
409
		$this->assertEquals(4, $players->limit(20)->count());
410
		$this->assertEquals(4, $players->limit(20, 0)->count());
411
		$this->assertEquals(0, $players->limit(20, 20)->count());
412
		$this->assertEquals(2, $players->limit(2, 0)->count());
413
		$this->assertEquals(1, $players->limit(5, 3)->count());
414
	}
415
416
	public function testWriteNoChangesDoesntUpdateLastEdited() {
417
		// set mock now so we can be certain of LastEdited time for our test
418
		SS_Datetime::set_mock_now('2017-01-01 00:00:00');
419
		$obj = new DataObjectTest_Player();
420
		$obj->FirstName = 'Test';
421
		$obj->Surname = 'Plater';
422
		$obj->Email = '[email protected]';
423
		$obj->write();
424
		$writtenObj = DataObjectTest_Player::get()->byID($obj->ID);
425
		$this->assertEquals('2017-01-01 00:00:00', $writtenObj->LastEdited);
426
427
		// set mock now so we get a new LastEdited if, for some reason, it's updated
428
		SS_Datetime::set_mock_now('2017-02-01 00:00:00');
429
		$writtenObj->write();
430
		$this->assertEquals('2017-01-01 00:00:00', $writtenObj->LastEdited);
431
	}
432
433
	/**
434
	 * Test writing of database columns which don't correlate to a DBField,
435
	 * e.g. all relation fields on has_one/has_many like "ParentID".
436
	 *
437
	 */
438
	public function testWritePropertyWithoutDBField() {
439
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain1');
440
		$obj->FavouriteTeamID = 99;
0 ignored issues
show
Documentation introduced by
The property FavouriteTeamID does not exist on object<DataObject>. 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...
441
		$obj->write();
442
443
		// reload the page from the database
444
		$savedObj = DataObject::get_by_id('DataObjectTest_Player', $obj->ID);
445
		$this->assertTrue($savedObj->FavouriteTeamID == 99);
446
447
		// Test with porymorphic relation
448
		$obj2 = $this->objFromFixture("DataObjectTest_Fan", "fan1");
449
		$obj2->FavouriteID = 99;
0 ignored issues
show
Documentation introduced by
The property FavouriteID does not exist on object<DataObject>. 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...
450
		$obj2->FavouriteClass = 'DataObjectTest_Player';
0 ignored issues
show
Documentation introduced by
The property FavouriteClass does not exist on object<DataObject>. 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...
451
		$obj2->write();
452
453
		$savedObj2 = DataObject::get_by_id('DataObjectTest_Fan', $obj2->ID);
454
		$this->assertTrue($savedObj2->FavouriteID == 99);
455
		$this->assertTrue($savedObj2->FavouriteClass == 'DataObjectTest_Player');
456
	}
457
458
	/**
459
	 * Test has many relationships
460
	 *   - Test getComponents() gets the ComponentSet of the other side of the relation
461
	 *   - Test the IDs on the DataObjects are set correctly
462
	 */
463
	public function testHasManyRelationships() {
464
		$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
465
466
		// Test getComponents() gets the ComponentSet of the other side of the relation
467
		$this->assertTrue($team1->Comments()->Count() == 2);
468
469
		// Test the IDs on the DataObjects are set correctly
470
		foreach($team1->Comments() as $comment) {
471
			$this->assertEquals($team1->ID, $comment->TeamID);
472
		}
473
474
		// Test that we can add and remove items that already exist in the database
475
		$newComment = new DataObjectTest_TeamComment();
476
		$newComment->Name = "Automated commenter";
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<DataObjectTest_TeamComment>. 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...
477
		$newComment->Comment = "This is a new comment";
0 ignored issues
show
Documentation introduced by
The property Comment does not exist on object<DataObjectTest_TeamComment>. 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...
478
		$newComment->write();
479
		$team1->Comments()->add($newComment);
480
		$this->assertEquals($team1->ID, $newComment->TeamID);
481
482
		$comment1 = $this->objFromFixture('DataObjectTest_TeamComment', 'comment1');
483
		$comment2 = $this->objFromFixture('DataObjectTest_TeamComment', 'comment2');
484
		$team1->Comments()->remove($comment2);
485
486
		$team1CommentIDs = $team1->Comments()->sort('ID')->column('ID');
487
		$this->assertEquals(array($comment1->ID, $newComment->ID), $team1CommentIDs);
488
489
		// Test that removing an item from a list doesn't remove it from the same
490
		// relation belonging to a different object
491
		$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
492
		$team2 = $this->objFromFixture('DataObjectTest_Team', 'team2');
493
		$team2->Comments()->remove($comment1);
494
		$team1CommentIDs = $team1->Comments()->sort('ID')->column('ID');
495
		$this->assertEquals(array($comment1->ID, $newComment->ID), $team1CommentIDs);
496
	}
497
498
499
	/**
500
	 * Test has many relationships against polymorphic has_one fields
501
	 *   - Test getComponents() gets the ComponentSet of the other side of the relation
502
	 *   - Test the IDs on the DataObjects are set correctly
503
	 */
504
	public function testHasManyPolymorphicRelationships() {
505
		$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
506
507
		// Test getComponents() gets the ComponentSet of the other side of the relation
508
		$this->assertTrue($team1->Fans()->Count() == 2);
509
510
		// Test the IDs/Classes on the DataObjects are set correctly
511
		foreach($team1->Fans() as $fan) {
512
			$this->assertEquals($team1->ID, $fan->FavouriteID, 'Fan has the correct FavouriteID');
513
			$this->assertEquals('DataObjectTest_Team', $fan->FavouriteClass, 'Fan has the correct FavouriteClass');
514
		}
515
516
		// Test that we can add and remove items that already exist in the database
517
		$newFan = new DataObjectTest_Fan();
518
		$newFan->Name = "New fan";
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<DataObjectTest_Fan>. 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...
519
		$newFan->write();
520
		$team1->Fans()->add($newFan);
521
		$this->assertEquals($team1->ID, $newFan->FavouriteID, 'Newly created fan has the correct FavouriteID');
522
		$this->assertEquals(
523
			'DataObjectTest_Team',
524
			$newFan->FavouriteClass,
525
			'Newly created fan has the correct FavouriteClass'
526
		);
527
528
		$fan1 = $this->objFromFixture('DataObjectTest_Fan', 'fan1');
529
		$fan3 = $this->objFromFixture('DataObjectTest_Fan', 'fan3');
530
		$team1->Fans()->remove($fan3);
531
532
		$team1FanIDs = $team1->Fans()->sort('ID')->column('ID');
533
		$this->assertEquals(array($fan1->ID, $newFan->ID), $team1FanIDs);
534
535
		// Test that removing an item from a list doesn't remove it from the same
536
		// relation belonging to a different object
537
		$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
538
		$player1 = $this->objFromFixture('DataObjectTest_Player', 'player1');
539
		$player1->Fans()->remove($fan1);
540
		$team1FanIDs = $team1->Fans()->sort('ID')->column('ID');
541
		$this->assertEquals(array($fan1->ID, $newFan->ID), $team1FanIDs);
542
	}
543
544
545
	public function testHasOneRelationship() {
546
		$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
547
		$player1 = $this->objFromFixture('DataObjectTest_Player', 'player1');
548
		$player2 = $this->objFromFixture('DataObjectTest_Player', 'player2');
549
		$fan1 = $this->objFromFixture('DataObjectTest_Fan', 'fan1');
550
551
		// Test relation probing
552
		$this->assertFalse((bool)$team1->hasValue('Captain', null, false));
553
		$this->assertFalse((bool)$team1->hasValue('CaptainID', null, false));
554
555
		// Add a captain to team 1
556
		$team1->setField('CaptainID', $player1->ID);
557
		$team1->write();
558
559
		$this->assertTrue((bool)$team1->hasValue('Captain', null, false));
560
		$this->assertTrue((bool)$team1->hasValue('CaptainID', null, false));
561
562
		$this->assertEquals($player1->ID, $team1->Captain()->ID,
563
			'The captain exists for team 1');
564
		$this->assertEquals($player1->ID, $team1->getComponent('Captain')->ID,
565
			'The captain exists through the component getter');
566
567
		$this->assertEquals($team1->Captain()->FirstName, 'Player 1',
568
			'Player 1 is the captain');
569
		$this->assertEquals($team1->getComponent('Captain')->FirstName, 'Player 1',
570
			'Player 1 is the captain');
571
572
		$team1->CaptainID = $player2->ID;
0 ignored issues
show
Documentation introduced by
The property CaptainID does not exist on object<DataObject>. 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...
573
		$team1->write();
574
575
		$this->assertEquals($player2->ID, $team1->Captain()->ID);
576
		$this->assertEquals($player2->ID, $team1->getComponent('Captain')->ID);
577
		$this->assertEquals('Player 2', $team1->Captain()->FirstName);
578
		$this->assertEquals('Player 2', $team1->getComponent('Captain')->FirstName);
579
580
581
		// Set the favourite team for fan1
582
		$fan1->setField('FavouriteID', $team1->ID);
583
		$fan1->setField('FavouriteClass', $team1->class);
584
585
		$this->assertEquals($team1->ID, $fan1->Favourite()->ID, 'The team is assigned to fan 1');
586
		$this->assertInstanceOf($team1->class, $fan1->Favourite(), 'The team is assigned to fan 1');
587
		$this->assertEquals($team1->ID, $fan1->getComponent('Favourite')->ID,
588
			'The team exists through the component getter'
589
		);
590
		$this->assertInstanceOf($team1->class, $fan1->getComponent('Favourite'),
591
			'The team exists through the component getter'
592
		);
593
594
		$this->assertEquals($fan1->Favourite()->Title, 'Team 1',
595
			'Team 1 is the favourite');
596
		$this->assertEquals($fan1->getComponent('Favourite')->Title, 'Team 1',
597
			'Team 1 is the favourite');
598
	}
599
600
	/**
601
	 * @todo Extend type change tests (e.g. '0'==NULL)
602
	 */
603
	public function testChangedFields() {
604
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain1');
605
		$obj->FirstName = 'Captain-changed';
0 ignored issues
show
Documentation introduced by
The property FirstName does not exist on object<DataObject>. 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...
606
		$obj->IsRetired = true;
0 ignored issues
show
Documentation introduced by
The property IsRetired does not exist on object<DataObject>. 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...
607
608
		$this->assertEquals(
609
			$obj->getChangedFields(true, DataObject::CHANGE_STRICT),
610
			array(
611
				'FirstName' => array(
612
					'before' => 'Captain',
613
					'after' => 'Captain-changed',
614
					'level' => DataObject::CHANGE_VALUE
615
				),
616
				'IsRetired' => array(
617
					'before' => 1,
618
					'after' => true,
619
					'level' => DataObject::CHANGE_STRICT
620
				)
621
			),
622
			'Changed fields are correctly detected with strict type changes (level=1)'
623
		);
624
625
		$this->assertEquals(
626
			$obj->getChangedFields(true, DataObject::CHANGE_VALUE),
627
			array(
628
				'FirstName' => array(
629
					'before'=>'Captain',
630
					'after'=>'Captain-changed',
631
					'level' => DataObject::CHANGE_VALUE
632
				)
633
			),
634
			'Changed fields are correctly detected while ignoring type changes (level=2)'
635
		);
636
637
		$newObj = new DataObjectTest_Player();
638
		$newObj->FirstName = "New Player";
639
		$this->assertEquals(
640
			array(
641
				'FirstName' => array(
642
					'before' => null,
643
					'after' => 'New Player',
644
					'level' => DataObject::CHANGE_VALUE
645
				)
646
			),
647
			$newObj->getChangedFields(true, DataObject::CHANGE_VALUE),
648
			'Initialised fields are correctly detected as full changes'
649
		);
650
	}
651
652
	public function testIsChanged() {
653
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain1');
654
		$obj->NonDBField = 'bob';
0 ignored issues
show
Documentation introduced by
The property NonDBField does not exist on object<DataObject>. 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...
655
		$obj->FirstName = 'Captain-changed';
0 ignored issues
show
Documentation introduced by
The property FirstName does not exist on object<DataObject>. 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...
656
		$obj->IsRetired = true; // type change only, database stores "1"
0 ignored issues
show
Documentation introduced by
The property IsRetired does not exist on object<DataObject>. 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...
657
658
		// Now that DB fields are changed, isChanged is true
659
		$this->assertTrue($obj->isChanged('NonDBField'));
660
		$this->assertFalse($obj->isChanged('NonField'));
661
		$this->assertTrue($obj->isChanged('FirstName', DataObject::CHANGE_STRICT));
662
		$this->assertTrue($obj->isChanged('FirstName', DataObject::CHANGE_VALUE));
663
		$this->assertTrue($obj->isChanged('IsRetired', DataObject::CHANGE_STRICT));
664
		$this->assertFalse($obj->isChanged('IsRetired', DataObject::CHANGE_VALUE));
665
		$this->assertFalse($obj->isChanged('Email', 1), 'Doesnt change mark unchanged property');
666
		$this->assertFalse($obj->isChanged('Email', 2), 'Doesnt change mark unchanged property');
667
668
		$newObj = new DataObjectTest_Player();
669
		$newObj->FirstName = "New Player";
670
		$this->assertTrue($newObj->isChanged('FirstName', DataObject::CHANGE_STRICT));
671
		$this->assertTrue($newObj->isChanged('FirstName', DataObject::CHANGE_VALUE));
672
		$this->assertFalse($newObj->isChanged('Email', DataObject::CHANGE_STRICT));
673
		$this->assertFalse($newObj->isChanged('Email', DataObject::CHANGE_VALUE));
674
675
		$newObj->write();
676
		$this->assertFalse($newObj->ischanged());
677
		$this->assertFalse($newObj->isChanged('FirstName', DataObject::CHANGE_STRICT));
678
		$this->assertFalse($newObj->isChanged('FirstName', DataObject::CHANGE_VALUE));
679
		$this->assertFalse($newObj->isChanged('Email', DataObject::CHANGE_STRICT));
680
		$this->assertFalse($newObj->isChanged('Email', DataObject::CHANGE_VALUE));
681
682
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain1');
683
		$obj->FirstName = null;
0 ignored issues
show
Documentation introduced by
The property FirstName does not exist on object<DataObject>. 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...
684
		$this->assertTrue($obj->isChanged('FirstName', DataObject::CHANGE_STRICT));
685
		$this->assertTrue($obj->isChanged('FirstName', DataObject::CHANGE_VALUE));
686
687
		/* Test when there's not field provided */
688
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain2');
689
		$this->assertFalse($obj->isChanged());
690
		$obj->NonDBField = 'new value';
0 ignored issues
show
Documentation introduced by
The property NonDBField does not exist on object<DataObject>. 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...
691
		$this->assertFalse($obj->isChanged());
692
		$obj->FirstName = "New Player";
0 ignored issues
show
Documentation introduced by
The property FirstName does not exist on object<DataObject>. 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...
693
		$this->assertTrue($obj->isChanged());
694
695
		$obj->write();
696
		$this->assertFalse($obj->isChanged());
697
	}
698
699
	public function testRandomSort() {
700
		/* If we perform the same regularly sorted query twice, it should return the same results */
701
		$itemsA = DataObject::get("DataObjectTest_TeamComment", "", "ID");
702
		foreach($itemsA as $item) $keysA[] = $item->ID;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$keysA was never initialized. Although not strictly required by PHP, it is generally a good practice to add $keysA = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
703
704
		$itemsB = DataObject::get("DataObjectTest_TeamComment", "", "ID");
705
		foreach($itemsB as $item) $keysB[] = $item->ID;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$keysB was never initialized. Although not strictly required by PHP, it is generally a good practice to add $keysB = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
706
707
		/* Test when there's not field provided */
708
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain1');
709
		$obj->FirstName = "New Player";
0 ignored issues
show
Documentation introduced by
The property FirstName does not exist on object<DataObject>. 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...
710
		$this->assertTrue($obj->isChanged());
711
712
		$obj->write();
713
		$this->assertFalse($obj->isChanged());
714
715
		/* If we perform the same random query twice, it shouldn't return the same results */
716
		$itemsA = DataObject::get("DataObjectTest_TeamComment", "", DB::get_conn()->random());
717
		$itemsB = DataObject::get("DataObjectTest_TeamComment", "", DB::get_conn()->random());
718
		$itemsC = DataObject::get("DataObjectTest_TeamComment", "", DB::get_conn()->random());
719
		$itemsD = DataObject::get("DataObjectTest_TeamComment", "", DB::get_conn()->random());
720
		foreach($itemsA as $item) $keysA[] = $item->ID;
0 ignored issues
show
Bug introduced by
The variable $keysA does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
721
		foreach($itemsB as $item) $keysB[] = $item->ID;
0 ignored issues
show
Bug introduced by
The variable $keysB does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
722
		foreach($itemsC as $item) $keysC[] = $item->ID;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$keysC was never initialized. Although not strictly required by PHP, it is generally a good practice to add $keysC = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
723
		foreach($itemsD as $item) $keysD[] = $item->ID;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$keysD was never initialized. Although not strictly required by PHP, it is generally a good practice to add $keysD = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
724
725
		// These shouldn't all be the same (run it 4 times to minimise chance of an accidental collision)
726
		// There's about a 1 in a billion chance of an accidental collision
727
		$this->assertTrue($keysA != $keysB || $keysB != $keysC || $keysC != $keysD);
0 ignored issues
show
Bug introduced by
The variable $keysC does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $keysD does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
728
	}
729
730
	public function testWriteSavesToHasOneRelations() {
731
		/* DataObject::write() should save to a has_one relationship if you set a field called (relname)ID */
732
		$team = new DataObjectTest_Team();
733
		$captainID = $this->idFromFixture('DataObjectTest_Player', 'player1');
734
		$team->CaptainID = $captainID;
0 ignored issues
show
Documentation introduced by
The property CaptainID does not exist on object<DataObjectTest_Team>. 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...
735
		$team->write();
736
		$this->assertEquals($captainID,
737
			DB::query("SELECT \"CaptainID\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $team->ID")->value());
738
739
		/* After giving it a value, you should also be able to set it back to null */
740
		$team->CaptainID = '';
0 ignored issues
show
Documentation introduced by
The property CaptainID does not exist on object<DataObjectTest_Team>. 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...
741
		$team->write();
742
		$this->assertEquals(0,
743
			DB::query("SELECT \"CaptainID\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $team->ID")->value());
744
745
		/* You should also be able to save a blank to it when it's first created */
746
		$team = new DataObjectTest_Team();
747
		$team->CaptainID = '';
0 ignored issues
show
Documentation introduced by
The property CaptainID does not exist on object<DataObjectTest_Team>. 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...
748
		$team->write();
749
		$this->assertEquals(0,
750
			DB::query("SELECT \"CaptainID\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $team->ID")->value());
751
752
		/* Ditto for existing records without a value */
753
		$existingTeam = $this->objFromFixture('DataObjectTest_Team', 'team1');
754
		$existingTeam->CaptainID = '';
0 ignored issues
show
Documentation introduced by
The property CaptainID does not exist on object<DataObject>. 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...
755
		$existingTeam->write();
756
		$this->assertEquals(0,
757
			DB::query("SELECT \"CaptainID\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $existingTeam->ID")->value());
758
	}
759
760
	public function testCanAccessHasOneObjectsAsMethods() {
761
		/* If you have a has_one relation 'Captain' on $obj, and you set the $obj->CaptainID = (ID), then the
762
		 * object itself should be accessible as $obj->Captain() */
763
		$team = $this->objFromFixture('DataObjectTest_Team', 'team1');
764
		$captainID = $this->idFromFixture('DataObjectTest_Player', 'captain1');
765
766
		$team->CaptainID = $captainID;
0 ignored issues
show
Documentation introduced by
The property CaptainID does not exist on object<DataObject>. 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...
767
		$this->assertNotNull($team->Captain());
768
		$this->assertEquals($captainID, $team->Captain()->ID);
769
770
		// Test for polymorphic has_one relations
771
		$fan = $this->objFromFixture('DataObjectTest_Fan', 'fan1');
772
		$fan->FavouriteID = $team->ID;
0 ignored issues
show
Documentation introduced by
The property FavouriteID does not exist on object<DataObject>. 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...
773
		$fan->FavouriteClass = $team->class;
0 ignored issues
show
Documentation introduced by
The property FavouriteClass does not exist on object<DataObject>. 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...
774
		$this->assertNotNull($fan->Favourite());
775
		$this->assertEquals($team->ID, $fan->Favourite()->ID);
776
		$this->assertInstanceOf($team->class, $fan->Favourite());
777
	}
778
779
	public function testFieldNamesThatMatchMethodNamesWork() {
780
		/* Check that a field name that corresponds to a method on DataObject will still work */
781
		$obj = new DataObjectTest_Fixture();
782
		$obj->Data = "value1";
0 ignored issues
show
Documentation introduced by
The property Data does not exist on object<DataObjectTest_Fixture>. 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...
783
		$obj->DbObject = "value2";
0 ignored issues
show
Documentation introduced by
The property DbObject does not exist on object<DataObjectTest_Fixture>. 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...
784
		$obj->Duplicate = "value3";
0 ignored issues
show
Documentation introduced by
The property Duplicate does not exist on object<DataObjectTest_Fixture>. 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...
785
		$obj->write();
786
787
		$this->assertNotNull($obj->ID);
788
		$this->assertEquals('value1',
789
			DB::query("SELECT \"Data\" FROM \"DataObjectTest_Fixture\" WHERE \"ID\" = $obj->ID")->value());
790
		$this->assertEquals('value2',
791
			DB::query("SELECT \"DbObject\" FROM \"DataObjectTest_Fixture\" WHERE \"ID\" = $obj->ID")->value());
792
		$this->assertEquals('value3',
793
			DB::query("SELECT \"Duplicate\" FROM \"DataObjectTest_Fixture\" WHERE \"ID\" = $obj->ID")->value());
794
	}
795
796
	/**
797
	 * @todo Re-enable all test cases for field existence after behaviour has been fixed
798
	 */
799
	public function testFieldExistence() {
800
		$teamInstance = $this->objFromFixture('DataObjectTest_Team', 'team1');
801
		$teamSingleton = singleton('DataObjectTest_Team');
802
803
		$subteamInstance = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam1');
804
		$subteamSingleton = singleton('DataObjectTest_SubTeam');
805
806
		/* hasField() singleton checks */
807
		$this->assertTrue($teamSingleton->hasField('ID'),
808
			'hasField() finds built-in fields in singletons');
809
		$this->assertTrue($teamSingleton->hasField('Title'),
810
			'hasField() finds custom fields in singletons');
811
812
		/* hasField() instance checks */
813
		$this->assertFalse($teamInstance->hasField('NonExistingField'),
814
			'hasField() doesnt find non-existing fields in instances');
815
		$this->assertTrue($teamInstance->hasField('ID'),
816
			'hasField() finds built-in fields in instances');
817
		$this->assertTrue($teamInstance->hasField('Created'),
818
			'hasField() finds built-in fields in instances');
819
		$this->assertTrue($teamInstance->hasField('DatabaseField'),
820
			'hasField() finds custom fields in instances');
821
		//$this->assertFalse($teamInstance->hasField('SubclassDatabaseField'),
822
		//'hasField() doesnt find subclass fields in parentclass instances');
823
		$this->assertTrue($teamInstance->hasField('DynamicField'),
824
			'hasField() finds dynamic getters in instances');
825
		$this->assertTrue($teamInstance->hasField('HasOneRelationshipID'),
826
			'hasField() finds foreign keys in instances');
827
		$this->assertTrue($teamInstance->hasField('ExtendedDatabaseField'),
828
			'hasField() finds extended fields in instances');
829
		$this->assertTrue($teamInstance->hasField('ExtendedHasOneRelationshipID'),
830
			'hasField() finds extended foreign keys in instances');
831
		//$this->assertTrue($teamInstance->hasField('ExtendedDynamicField'),
832
		//'hasField() includes extended dynamic getters in instances');
833
834
		/* hasField() subclass checks */
835
		$this->assertTrue($subteamInstance->hasField('ID'),
836
			'hasField() finds built-in fields in subclass instances');
837
		$this->assertTrue($subteamInstance->hasField('Created'),
838
			'hasField() finds built-in fields in subclass instances');
839
		$this->assertTrue($subteamInstance->hasField('DatabaseField'),
840
			'hasField() finds custom fields in subclass instances');
841
		$this->assertTrue($subteamInstance->hasField('SubclassDatabaseField'),
842
			'hasField() finds custom fields in subclass instances');
843
		$this->assertTrue($subteamInstance->hasField('DynamicField'),
844
			'hasField() finds dynamic getters in subclass instances');
845
		$this->assertTrue($subteamInstance->hasField('HasOneRelationshipID'),
846
			'hasField() finds foreign keys in subclass instances');
847
		$this->assertTrue($subteamInstance->hasField('ExtendedDatabaseField'),
848
			'hasField() finds extended fields in subclass instances');
849
		$this->assertTrue($subteamInstance->hasField('ExtendedHasOneRelationshipID'),
850
			'hasField() finds extended foreign keys in subclass instances');
851
852
		/* hasDatabaseField() singleton checks */
853
		//$this->assertTrue($teamSingleton->hasDatabaseField('ID'),
854
		//'hasDatabaseField() finds built-in fields in singletons');
855
		$this->assertTrue($teamSingleton->hasDatabaseField('Title'),
856
			'hasDatabaseField() finds custom fields in singletons');
857
858
		/* hasDatabaseField() instance checks */
859
		$this->assertFalse($teamInstance->hasDatabaseField('NonExistingField'),
860
			'hasDatabaseField() doesnt find non-existing fields in instances');
861
		//$this->assertTrue($teamInstance->hasDatabaseField('ID'),
862
		//'hasDatabaseField() finds built-in fields in instances');
863
		$this->assertTrue($teamInstance->hasDatabaseField('Created'),
864
			'hasDatabaseField() finds built-in fields in instances');
865
		$this->assertTrue($teamInstance->hasDatabaseField('DatabaseField'),
866
			'hasDatabaseField() finds custom fields in instances');
867
		$this->assertFalse($teamInstance->hasDatabaseField('SubclassDatabaseField'),
868
			'hasDatabaseField() doesnt find subclass fields in parentclass instances');
869
		//$this->assertFalse($teamInstance->hasDatabaseField('DynamicField'),
870
		//'hasDatabaseField() doesnt dynamic getters in instances');
871
		$this->assertTrue($teamInstance->hasDatabaseField('HasOneRelationshipID'),
872
			'hasDatabaseField() finds foreign keys in instances');
873
		$this->assertTrue($teamInstance->hasDatabaseField('ExtendedDatabaseField'),
874
			'hasDatabaseField() finds extended fields in instances');
875
		$this->assertTrue($teamInstance->hasDatabaseField('ExtendedHasOneRelationshipID'),
876
			'hasDatabaseField() finds extended foreign keys in instances');
877
		$this->assertFalse($teamInstance->hasDatabaseField('ExtendedDynamicField'),
878
			'hasDatabaseField() doesnt include extended dynamic getters in instances');
879
880
		/* hasDatabaseField() subclass checks */
881
		$this->assertTrue($subteamInstance->hasDatabaseField('DatabaseField'),
882
			'hasField() finds custom fields in subclass instances');
883
		$this->assertTrue($subteamInstance->hasDatabaseField('SubclassDatabaseField'),
884
			'hasField() finds custom fields in subclass instances');
885
886
	}
887
888
	/**
889
	 * @todo Re-enable all test cases for field inheritance aggregation after behaviour has been fixed
890
	 */
891
	public function testFieldInheritance() {
892
		$teamInstance = $this->objFromFixture('DataObjectTest_Team', 'team1');
893
		$subteamInstance = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam1');
894
895
		$this->assertEquals(
896
			array_keys($teamInstance->inheritedDatabaseFields()),
897
			array(
898
				//'ID',
899
				//'ClassName',
900
				//'Created',
901
				//'LastEdited',
902
				'Title',
903
				'DatabaseField',
904
				'ExtendedDatabaseField',
905
				'CaptainID',
906
				'HasOneRelationshipID',
907
				'ExtendedHasOneRelationshipID'
908
			),
909
			'inheritedDatabaseFields() contains all fields defined on instance: base, extended and foreign keys'
910
		);
911
912
		$this->assertEquals(
913
			array_keys(DataObject::database_fields('DataObjectTest_Team', false)),
914
			array(
915
				//'ID',
916
				'ClassName',
917
				'LastEdited',
918
				'Created',
919
				'Title',
920
				'DatabaseField',
921
				'ExtendedDatabaseField',
922
				'CaptainID',
923
				'HasOneRelationshipID',
924
				'ExtendedHasOneRelationshipID'
925
			),
926
			'databaseFields() contains only fields defined on instance, including base, extended and foreign keys'
927
		);
928
929
		$this->assertEquals(
930
			array_keys($subteamInstance->inheritedDatabaseFields()),
931
			array(
932
				//'ID',
933
				//'ClassName',
934
				//'Created',
935
				//'LastEdited',
936
				'SubclassDatabaseField',
937
				'ParentTeamID',
938
				'Title',
939
				'DatabaseField',
940
				'ExtendedDatabaseField',
941
				'CaptainID',
942
				'HasOneRelationshipID',
943
				'ExtendedHasOneRelationshipID',
944
			),
945
			'inheritedDatabaseFields() on subclass contains all fields, including base, extended  and foreign keys'
946
		);
947
948
		$this->assertEquals(
949
			array_keys(DataObject::database_fields('DataObjectTest_SubTeam', false)),
950
			array(
951
				'SubclassDatabaseField',
952
				'ParentTeamID',
953
			),
954
			'databaseFields() on subclass contains only fields defined on instance'
955
		);
956
	}
957
958
	public function testSearchableFields() {
959
		$player = $this->objFromFixture('DataObjectTest_Player', 'captain1');
960
		$fields = $player->searchableFields();
961
		$this->assertArrayHasKey(
962
			'IsRetired',
963
			$fields,
964
			'Fields defined by $searchable_fields static are correctly detected'
965
		);
966
		$this->assertArrayHasKey(
967
			'ShirtNumber',
968
			$fields,
969
			'Fields defined by $searchable_fields static are correctly detected'
970
		);
971
972
		$team = $this->objFromFixture('DataObjectTest_Team', 'team1');
973
		$fields = $team->searchableFields();
974
		$this->assertArrayHasKey(
975
			'Title',
976
			$fields,
977
			'Fields can be inherited from the $summary_fields static, including methods called on fields'
978
		);
979
		$this->assertArrayHasKey(
980
			'Captain.ShirtNumber',
981
			$fields,
982
			'Fields on related objects can be inherited from the $summary_fields static'
983
		);
984
		$this->assertArrayHasKey(
985
			'Captain.FavouriteTeam.Title',
986
			$fields,
987
			'Fields on related objects can be inherited from the $summary_fields static'
988
		);
989
990
		$testObj = new DataObjectTest_Fixture();
991
		$fields = $testObj->searchableFields();
992
		$this->assertEmpty($fields);
993
	}
994
995
	public function testCastingHelper() {
996
		$team = $this->objFromFixture('DataObjectTest_Team', 'team1');
997
998
		$this->assertEquals('Varchar', $team->castingHelper('Title'), 'db field wasn\'t casted correctly');
999
		$this->assertEquals('HTMLVarchar', $team->castingHelper('DatabaseField'), 'db field wasn\'t casted correctly');
1000
1001
		$sponsor = $team->Sponsors()->first();
1002
		$this->assertEquals('Int', $sponsor->castingHelper('SponsorFee'), 'many_many_extraFields not casted correctly');
1003
	}
1004
1005
	public function testSummaryFieldsCustomLabels() {
1006
		$team = $this->objFromFixture('DataObjectTest_Team', 'team1');
1007
		$summaryFields = $team->summaryFields();
1008
1009
		$this->assertEquals(
1010
			'Custom Title',
1011
			$summaryFields['Title'],
1012
			'Custom title is preserved'
1013
		);
1014
1015
		$this->assertEquals(
1016
			'Captain\'s shirt number',
1017
			$summaryFields['Captain.ShirtNumber'],
1018
			'Custom title on relation is preserved'
1019
		);
1020
	}
1021
1022
	public function testDataObjectUpdate() {
1023
		/* update() calls can use the dot syntax to reference has_one relations and other methods that return
1024
		 * objects */
1025
		$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
1026
		$team1->CaptainID = $this->idFromFixture('DataObjectTest_Player', 'captain1');
0 ignored issues
show
Documentation introduced by
The property CaptainID does not exist on object<DataObject>. 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...
1027
1028
		$team1->update(array(
1029
			'DatabaseField' => 'Something',
1030
			'Captain.FirstName' => 'Jim',
1031
			'Captain.Email' => '[email protected]',
1032
			'Captain.FavouriteTeam.Title' => 'New and improved team 1',
1033
		));
1034
1035
		/* Test the simple case of updating fields on the object itself */
1036
		$this->assertEquals('Something', $team1->DatabaseField);
1037
1038
		/* Setting Captain.Email and Captain.FirstName will have updated DataObjectTest_Captain.captain1 in
1039
		 * the database.  Although update() doesn't usually write, it does write related records automatically. */
1040
		$captain1 = $this->objFromFixture('DataObjectTest_Player', 'captain1');
1041
		$this->assertEquals('Jim', $captain1->FirstName);
1042
		$this->assertEquals('[email protected]', $captain1->Email);
1043
1044
		/* Jim's favourite team is team 1; we need to reload the object to the the change that setting Captain.
1045
		 * FavouriteTeam.Title made */
1046
		$reloadedTeam1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
1047
		$this->assertEquals('New and improved team 1', $reloadedTeam1->Title);
1048
	}
1049
1050
	public function testDataObjectUpdateNew() {
1051
		/* update() calls can use the dot syntax to reference has_one relations and other methods that return
1052
		 * objects */
1053
		$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
1054
		$team1->CaptainID = 0;
0 ignored issues
show
Documentation introduced by
The property CaptainID does not exist on object<DataObject>. 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...
1055
1056
		$team1->update(array(
1057
			'Captain.FirstName' => 'Jim',
1058
			'Captain.FavouriteTeam.Title' => 'New and improved team 1',
1059
		));
1060
		/* Test that the captain ID has been updated */
1061
		$this->assertGreaterThan(0, $team1->CaptainID);
1062
1063
		/* Fetch the newly created captain */
1064
		$captain1 = DataObjectTest_Player::get()->byID($team1->CaptainID);
1065
		$this->assertEquals('Jim', $captain1->FirstName);
1066
1067
		/* Grab the favourite team and make sure it has the correct values */
1068
		$reloadedTeam1 = $captain1->FavouriteTeam();
1069
		$this->assertEquals($reloadedTeam1->ID, $captain1->FavouriteTeamID);
1070
		$this->assertEquals('New and improved team 1', $reloadedTeam1->Title);
1071
	}
1072
1073
	public function testWritingInvalidDataObjectThrowsException() {
1074
		$validatedObject = new DataObjectTest_ValidatedObject();
1075
1076
		$this->setExpectedException('ValidationException');
1077
		$validatedObject->write();
1078
	}
1079
1080
	public function testWritingValidDataObjectDoesntThrowException() {
1081
		$validatedObject = new DataObjectTest_ValidatedObject();
1082
		$validatedObject->Name = "Mr. Jones";
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...
1083
1084
		$validatedObject->write();
1085
		$this->assertTrue($validatedObject->isInDB(), "Validated object was not saved to database");
1086
	}
1087
1088
	public function testSubclassCreation() {
1089
		/* Creating a new object of a subclass should set the ClassName field correctly */
1090
		$obj = new DataObjectTest_SubTeam();
1091
		$obj->write();
1092
		$this->assertEquals("DataObjectTest_SubTeam",
1093
			DB::query("SELECT \"ClassName\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $obj->ID")->value());
1094
	}
1095
1096
	public function testForceInsert() {
1097
		/* If you set an ID on an object and pass forceInsert = true, then the object should be correctly created */
1098
		$conn = DB::get_conn();
1099
		if(method_exists($conn, 'allowPrimaryKeyEditing')) $conn->allowPrimaryKeyEditing('DataObjectTest_Team', true);
1100
		$obj = new DataObjectTest_SubTeam();
1101
		$obj->ID = 1001;
1102
		$obj->Title = 'asdfasdf';
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<DataObjectTest_SubTeam>. 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...
1103
		$obj->SubclassDatabaseField = 'asdfasdf';
0 ignored issues
show
Documentation introduced by
The property SubclassDatabaseField does not exist on object<DataObjectTest_SubTeam>. 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...
1104
		$obj->write(false, true);
1105
		if(method_exists($conn, 'allowPrimaryKeyEditing')) $conn->allowPrimaryKeyEditing('DataObjectTest_Team', false);
1106
1107
		$this->assertEquals("DataObjectTest_SubTeam",
1108
			DB::query("SELECT \"ClassName\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $obj->ID")->value());
1109
1110
		/* Check that it actually saves to the database with the correct ID */
1111
		$this->assertEquals("1001", DB::query(
1112
			"SELECT \"ID\" FROM \"DataObjectTest_SubTeam\" WHERE \"SubclassDatabaseField\" = 'asdfasdf'")->value());
1113
		$this->assertEquals("1001",
1114
			DB::query("SELECT \"ID\" FROM \"DataObjectTest_Team\" WHERE \"Title\" = 'asdfasdf'")->value());
1115
	}
1116
1117
	public function TestHasOwnTable() {
1118
		/* Test DataObject::has_own_table() returns true if the object has $has_one or $db values */
1119
		$this->assertTrue(DataObject::has_own_table("DataObjectTest_Player"));
1120
		$this->assertTrue(DataObject::has_own_table("DataObjectTest_Team"));
1121
		$this->assertTrue(DataObject::has_own_table("DataObjectTest_Fixture"));
1122
1123
		/* Root DataObject that always have a table, even if they lack both $db and $has_one */
1124
		$this->assertTrue(DataObject::has_own_table("DataObjectTest_FieldlessTable"));
1125
1126
		/* Subclasses without $db or $has_one don't have a table */
1127
		$this->assertFalse(DataObject::has_own_table("DataObjectTest_FieldlessSubTable"));
1128
1129
		/* Return false if you don't pass it a subclass of DataObject */
1130
		$this->assertFalse(DataObject::has_own_table("DataObject"));
1131
		$this->assertFalse(DataObject::has_own_table("ViewableData"));
1132
		$this->assertFalse(DataObject::has_own_table("ThisIsntADataObject"));
1133
	}
1134
1135
	public function testMerge() {
1136
		// test right merge of subclasses
1137
		$left = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam1');
1138
		$right = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam2_with_player_relation');
1139
		$leftOrigID = $left->ID;
1140
		$left->merge($right, 'right', false, false);
1141
		$this->assertEquals(
1142
			$left->Title,
1143
			'Subteam 2',
1144
			'merge() with "right" priority overwrites fields with existing values on subclasses'
1145
		);
1146
		$this->assertEquals(
1147
			$left->ID,
1148
			$leftOrigID,
1149
			'merge() with "right" priority doesnt overwrite database ID'
1150
		);
1151
1152
		// test overwriteWithEmpty flag on existing left values
1153
		$left = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam2_with_player_relation');
1154
		$right = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam3_with_empty_fields');
1155
		$left->merge($right, 'right', false, true);
1156
		$this->assertEquals(
1157
			$left->Title,
1158
			'Subteam 3',
1159
			'merge() with $overwriteWithEmpty overwrites non-empty fields on left object'
1160
		);
1161
1162
		// test overwriteWithEmpty flag on empty left values
1163
		$left = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam1');
1164
		// $SubclassDatabaseField is empty on here
1165
		$right = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam2_with_player_relation');
1166
		$left->merge($right, 'right', false, true);
1167
		$this->assertEquals(
1168
			$left->SubclassDatabaseField,
1169
			NULL,
1170
			'merge() with $overwriteWithEmpty overwrites empty fields on left object'
1171
		);
1172
1173
		// @todo test "left" priority flag
1174
		// @todo test includeRelations flag
1175
		// @todo test includeRelations in combination with overwriteWithEmpty
1176
		// @todo test has_one relations
1177
		// @todo test has_many and many_many relations
1178
	}
1179
1180
	public function testPopulateDefaults() {
1181
		$obj = new DataObjectTest_Fixture();
1182
		$this->assertEquals(
1183
			$obj->MyFieldWithDefault,
1184
			'Default Value',
1185
			'Defaults are populated for in-memory object from $defaults array'
1186
		);
1187
1188
		$this->assertEquals(
1189
			$obj->MyFieldWithAltDefault,
1190
			'Default Value',
1191
			'Defaults are populated from overloaded populateDefaults() method'
1192
		);
1193
	}
1194
1195
	protected function makeAccessible($object, $method) {
1196
		$reflectionMethod = new ReflectionMethod($object, $method);
1197
		$reflectionMethod->setAccessible(true);
1198
		return $reflectionMethod;
1199
	}
1200
1201
	public function testValidateModelDefinitionsFailsWithArray() {
1202
1203
		$object = new DataObjectTest_Team;
1204
		$method = $this->makeAccessible($object, 'validateModelDefinitions');
1205
1206
		Config::inst()->update('DataObjectTest_Team', 'has_one', array('NotValid' => array('NoArraysAllowed')));
1207
		$this->setExpectedException('LogicException');
1208
1209
		$method->invoke($object);
1210
	}
1211
1212
	public function testValidateModelDefinitionsFailsWithIntKey() {
1213
		$object = new DataObjectTest_Team;
1214
		$method = $this->makeAccessible($object, 'validateModelDefinitions');
1215
1216
		Config::inst()->update('DataObjectTest_Team', 'has_many', array(12 => 'DataObjectTest_Player'));
1217
		$this->setExpectedException('LogicException');
1218
1219
		$method->invoke($object);
1220
	}
1221
1222
	public function testValidateModelDefinitionsFailsWithIntValue() {
1223
		$object = new DataObjectTest_Team;
1224
		$method = $this->makeAccessible($object, 'validateModelDefinitions');
1225
1226
		Config::inst()->update('DataObjectTest_Team', 'many_many', array('Players' => 12));
1227
		$this->setExpectedException('LogicException');
1228
1229
		$method->invoke($object);
1230
	}
1231
1232
	/**
1233
	 * many_many_extraFields is allowed to have an array value, so shouldn't throw an exception
1234
	 */
1235
	public function testValidateModelDefinitionsPassesWithExtraFields() {
1236
		$object = new DataObjectTest_Team;
1237
		$method = $this->makeAccessible($object, 'validateModelDefinitions');
1238
1239
		Config::inst()->update('DataObjectTest_Team', 'many_many_extraFields',
1240
			array('Relations' => array('Price' => 'Int')));
1241
1242
		try {
1243
			$method->invoke($object);
1244
		} catch(Exception $e) {
1245
			$this->fail('Exception should not be thrown');
1246
			throw $e;
1247
		}
1248
	}
1249
1250
	public function testNewClassInstance() {
1251
		$dataObject = $this->objFromFixture('DataObjectTest_Team', 'team1');
1252
		$changedDO = $dataObject->newClassInstance('DataObjectTest_SubTeam');
1253
		$changedFields = $changedDO->getChangedFields();
1254
1255
		// Don't write the record, it will reset changed fields
1256
		$this->assertInstanceOf('DataObjectTest_SubTeam', $changedDO);
1257
		$this->assertEquals($changedDO->ClassName, 'DataObjectTest_SubTeam');
1258
		$this->assertContains('ClassName', array_keys($changedFields));
1259
		$this->assertEquals($changedFields['ClassName']['before'], 'DataObjectTest_Team');
1260
		$this->assertEquals($changedFields['ClassName']['after'], 'DataObjectTest_SubTeam');
1261
1262
		$changedDO->write();
1263
1264
		$this->assertInstanceOf('DataObjectTest_SubTeam', $changedDO);
1265
		$this->assertEquals($changedDO->ClassName, 'DataObjectTest_SubTeam');
1266
	}
1267
1268
	public function testMultipleManyManyWithSameClass() {
1269
		$team = $this->objFromFixture('DataObjectTest_Team', 'team1');
1270
		$sponsors = $team->Sponsors();
1271
		$equipmentSuppliers = $team->EquipmentSuppliers();
1272
1273
		// Check that DataObject::many_many() works as expected
1274
		list($class, $targetClass, $parentField, $childField, $joinTable) = $team->manyManyComponent('Sponsors');
0 ignored issues
show
Unused Code introduced by
The assignment to $parentField is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
Unused Code introduced by
The assignment to $childField is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
1275
		$this->assertEquals('DataObjectTest_Team', $class,
1276
			'DataObject::many_many() didn\'t find the correct base class');
1277
		$this->assertEquals('DataObjectTest_EquipmentCompany', $targetClass,
1278
			'DataObject::many_many() didn\'t find the correct target class for the relation');
1279
		$this->assertEquals('DataObjectTest_EquipmentCompany_SponsoredTeams', $joinTable,
1280
			'DataObject::many_many() didn\'t find the correct relation table');
1281
1282
		// Check that ManyManyList still works
1283
		$this->assertEquals(2, $sponsors->count(), 'Rows are missing from relation');
1284
		$this->assertEquals(1, $equipmentSuppliers->count(), 'Rows are missing from relation');
1285
1286
		// Check everything works when no relation is present
1287
		$teamWithoutSponsor = $this->objFromFixture('DataObjectTest_Team', 'team3');
1288
		$this->assertInstanceOf('ManyManyList', $teamWithoutSponsor->Sponsors());
1289
		$this->assertEquals(0, $teamWithoutSponsor->Sponsors()->count());
1290
1291
		// Check many_many_extraFields still works
1292
		$equipmentCompany = $this->objFromFixture('DataObjectTest_EquipmentCompany', 'equipmentcompany1');
1293
		$equipmentCompany->SponsoredTeams()->add($teamWithoutSponsor, array('SponsorFee' => 1000));
1294
		$sponsoredTeams = $equipmentCompany->SponsoredTeams();
1295
		$this->assertEquals(1000, $sponsoredTeams->byID($teamWithoutSponsor->ID)->SponsorFee,
1296
			'Data from many_many_extraFields was not stored/extracted correctly');
1297
1298
		// Check subclasses correctly inherit multiple many_manys
1299
		$subTeam = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam1');
1300
		$this->assertEquals(2, $subTeam->Sponsors()->count(),
1301
			'Child class did not inherit multiple many_manys');
1302
		$this->assertEquals(1, $subTeam->EquipmentSuppliers()->count(),
1303
			'Child class did not inherit multiple many_manys');
1304
		// Team 2 has one EquipmentCompany sponsor and one SubEquipmentCompany
1305
		$team2 = $this->objFromFixture('DataObjectTest_Team', 'team2');
1306
		$this->assertEquals(2, $team2->Sponsors()->count(),
1307
			'Child class did not inherit multiple belongs_many_manys');
1308
1309
		// Check many_many_extraFields also works from the belongs_many_many side
1310
		$sponsors = $team2->Sponsors();
1311
		$sponsors->add($equipmentCompany, array('SponsorFee' => 750));
1312
		$this->assertEquals(750, $sponsors->byID($equipmentCompany->ID)->SponsorFee,
1313
			'Data from many_many_extraFields was not stored/extracted correctly');
1314
1315
		$subEquipmentCompany = $this->objFromFixture('DataObjectTest_SubEquipmentCompany', 'subequipmentcompany1');
1316
		$subTeam->Sponsors()->add($subEquipmentCompany, array('SponsorFee' => 1200));
1317
		$this->assertEquals(1200, $subTeam->Sponsors()->byID($subEquipmentCompany->ID)->SponsorFee,
1318
			'Data from inherited many_many_extraFields was not stored/extracted correctly');
1319
	}
1320
1321
	public function testManyManyExtraFields() {
1322
		$player = $this->objFromFixture('DataObjectTest_Player', 'player1');
1323
		$team = $this->objFromFixture('DataObjectTest_Team', 'team1');
1324
1325
		// Get all extra fields
1326
		$teamExtraFields = $team->manyManyExtraFields();
1327
		$this->assertEquals(array(
1328
			'Players' => array('Position' => 'Varchar(100)')
1329
		), $teamExtraFields);
1330
1331
		// Ensure fields from parent classes are included
1332
		$subTeam = singleton('DataObjectTest_SubTeam');
1333
		$teamExtraFields = $subTeam->manyManyExtraFields();
1334
		$this->assertEquals(array(
1335
			'Players' => array('Position' => 'Varchar(100)'),
1336
			'FormerPlayers' => array('Position' => 'Varchar(100)')
1337
		), $teamExtraFields);
1338
1339
		// Extra fields are immediately available on the Team class (defined in $many_many_extraFields)
1340
		$teamExtraFields = $team->manyManyExtraFieldsForComponent('Players');
1341
		$this->assertEquals($teamExtraFields, array(
1342
			'Position' => 'Varchar(100)'
1343
		));
1344
1345
		// We'll have to go through the relation to get the extra fields on Player
1346
		$playerExtraFields = $player->manyManyExtraFieldsForComponent('Teams');
1347
		$this->assertEquals($playerExtraFields, array(
1348
			'Position' => 'Varchar(100)'
1349
		));
1350
1351
		// Iterate through a many-many relationship and confirm that extra fields are included
1352
		$newTeam = new DataObjectTest_Team();
1353
		$newTeam->Title = "New team";
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<DataObjectTest_Team>. 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...
1354
		$newTeam->write();
1355
		$newTeamID = $newTeam->ID;
1356
1357
		$newPlayer = new DataObjectTest_Player();
1358
		$newPlayer->FirstName = "Sam";
1359
		$newPlayer->Surname = "Minnee";
1360
		$newPlayer->write();
1361
1362
		// The idea of Sam as a prop is essentially humourous.
1363
		$newTeam->Players()->add($newPlayer, array("Position" => "Prop"));
1364
1365
		// Requery and uncache everything
1366
		$newTeam->flushCache();
1367
		$newTeam = DataObject::get_by_id('DataObjectTest_Team', $newTeamID);
1368
1369
		// Check that the Position many_many_extraField is extracted.
1370
		$player = $newTeam->Players()->First();
1371
		$this->assertEquals('Sam', $player->FirstName);
1372
		$this->assertEquals("Prop", $player->Position);
1373
1374
		// Check that ordering a many-many relation by an aggregate column doesn't fail
1375
		$player = $this->objFromFixture('DataObjectTest_Player', 'player2');
1376
		$player->Teams()->sort("count(DISTINCT \"DataObjectTest_Team_Players\".\"DataObjectTest_PlayerID\") DESC");
1377
	}
1378
1379
	/**
1380
	 * Check that the queries generated for many-many relation queries can have unlimitedRowCount
1381
	 * called on them.
1382
	 */
1383
	public function testManyManyUnlimitedRowCount() {
1384
		$player = $this->objFromFixture('DataObjectTest_Player', 'player2');
1385
		// TODO: What's going on here?
1386
		$this->assertEquals(2, $player->Teams()->dataQuery()->query()->unlimitedRowCount());
1387
	}
1388
1389
	/**
1390
	 * Tests that singular_name() generates sensible defaults.
1391
	 */
1392
	public function testSingularName() {
1393
		$assertions = array(
1394
			'DataObjectTest_Player'       => 'Data Object Test Player',
1395
			'DataObjectTest_Team'         => 'Data Object Test Team',
1396
			'DataObjectTest_Fixture'      => 'Data Object Test Fixture'
1397
		);
1398
1399
		foreach($assertions as $class => $expectedSingularName) {
1400
			$this->assertEquals(
1401
				$expectedSingularName,
1402
				singleton($class)->singular_name(),
1403
				"Assert that the singular_name for '$class' is correct."
1404
			);
1405
		}
1406
	}
1407
1408
	/**
1409
	 * Tests that plural_name() generates sensible defaults.
1410
	 */
1411
	public function testPluralName() {
1412
		$assertions = array(
1413
			'DataObjectTest_Player'       => 'Data Object Test Players',
1414
			'DataObjectTest_Team'         => 'Data Object Test Teams',
1415
			'DataObjectTest_Fixture'      => 'Data Object Test Fixtures',
1416
			'DataObjectTest_Play'         => 'Data Object Test Plays',
1417
			'DataObjectTest_Bogey'        => 'Data Object Test Bogeys',
1418
			'DataObjectTest_Ploy'         => 'Data Object Test Ploys',
1419
		);
1420
1421
		foreach($assertions as $class => $expectedPluralName) {
1422
			$this->assertEquals(
1423
				$expectedPluralName,
1424
				singleton($class)->plural_name(),
1425
				"Assert that the plural_name for '$class' is correct."
1426
			);
1427
		}
1428
	}
1429
1430
	public function testHasDatabaseField() {
1431
		$team = singleton('DataObjectTest_Team');
1432
		$subteam = singleton('DataObjectTest_SubTeam');
1433
1434
		$this->assertTrue(
1435
			$team->hasDatabaseField('Title'),
1436
			"hasOwnDatabaseField() works with \$db fields"
1437
		);
1438
		$this->assertTrue(
1439
			$team->hasDatabaseField('CaptainID'),
1440
			"hasOwnDatabaseField() works with \$has_one fields"
1441
		);
1442
		$this->assertFalse(
1443
			$team->hasDatabaseField('NonExistentField'),
1444
			"hasOwnDatabaseField() doesn't detect non-existend fields"
1445
		);
1446
		$this->assertTrue(
1447
			$team->hasDatabaseField('ExtendedDatabaseField'),
1448
			"hasOwnDatabaseField() works with extended fields"
1449
		);
1450
		$this->assertFalse(
1451
			$team->hasDatabaseField('SubclassDatabaseField'),
1452
			"hasOwnDatabaseField() doesn't pick up fields in subclasses on parent class"
1453
		);
1454
1455
		$this->assertTrue(
1456
			$subteam->hasDatabaseField('SubclassDatabaseField'),
1457
			"hasOwnDatabaseField() picks up fields in subclasses"
1458
		);
1459
1460
	}
1461
1462
	public function testFieldTypes() {
1463
		$obj = new DataObjectTest_Fixture();
1464
		$obj->DateField = '1988-01-02';
0 ignored issues
show
Documentation introduced by
The property DateField does not exist on object<DataObjectTest_Fixture>. 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...
1465
		$obj->DatetimeField = '1988-03-04 06:30';
0 ignored issues
show
Documentation introduced by
The property DatetimeField does not exist on object<DataObjectTest_Fixture>. 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...
1466
		$obj->write();
1467
		$obj->flushCache();
1468
1469
		$obj = DataObject::get_by_id('DataObjectTest_Fixture', $obj->ID);
1470
		$this->assertEquals('1988-01-02', $obj->DateField);
1471
		$this->assertEquals('1988-03-04 06:30:00', $obj->DatetimeField);
1472
	}
1473
1474
	public function testTwoSubclassesWithTheSameFieldNameWork() {
1475
		// Create two objects of different subclasses, setting the values of fields that are
1476
		// defined separately in each subclass
1477
		$obj1 = new DataObjectTest_SubTeam();
1478
		$obj1->SubclassDatabaseField = "obj1";
0 ignored issues
show
Documentation introduced by
The property SubclassDatabaseField does not exist on object<DataObjectTest_SubTeam>. 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...
1479
		$obj2 = new OtherSubclassWithSameField();
1480
		$obj2->SubclassDatabaseField = "obj2";
0 ignored issues
show
Documentation introduced by
The property SubclassDatabaseField does not exist on object<OtherSubclassWithSameField>. 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...
1481
1482
		// Write them to the database
1483
		$obj1->write();
1484
		$obj2->write();
1485
1486
		// Check that the values of those fields are properly read from the database
1487
		$values = DataObject::get("DataObjectTest_Team", "\"DataObjectTest_Team\".\"ID\" IN
1488
			($obj1->ID, $obj2->ID)")->column("SubclassDatabaseField");
1489
		$this->assertEquals(array_intersect($values, array('obj1', 'obj2')), $values);
1490
	}
1491
1492
	public function testClassNameSetForNewObjects() {
1493
		$d = new DataObjectTest_Player();
1494
		$this->assertEquals('DataObjectTest_Player', $d->ClassName);
1495
	}
1496
1497
	public function testHasValue() {
1498
		$team = new DataObjectTest_Team();
1499
		$this->assertFalse($team->hasValue('Title', null, false));
1500
		$this->assertFalse($team->hasValue('DatabaseField', null, false));
1501
1502
		$team->Title = 'hasValue';
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<DataObjectTest_Team>. 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...
1503
		$this->assertTrue($team->hasValue('Title', null, false));
1504
		$this->assertFalse($team->hasValue('DatabaseField', null, false));
1505
1506
		$team->DatabaseField = '<p></p>';
0 ignored issues
show
Documentation introduced by
The property DatabaseField does not exist on object<DataObjectTest_Team>. 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...
1507
		$this->assertTrue($team->hasValue('Title', null, false));
1508
		$this->assertFalse (
1509
			$team->hasValue('DatabaseField', null, false),
1510
			'Test that a blank paragraph on a HTML field is not a valid value.'
1511
		);
1512
1513
		$team->Title = '<p></p>';
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<DataObjectTest_Team>. 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...
1514
		$this->assertTrue (
1515
			$team->hasValue('Title', null, false),
1516
			'Test that an empty paragraph is a value for non-HTML fields.'
1517
		);
1518
1519
		$team->DatabaseField = 'hasValue';
0 ignored issues
show
Documentation introduced by
The property DatabaseField does not exist on object<DataObjectTest_Team>. 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...
1520
		$this->assertTrue($team->hasValue('Title', null, false));
1521
		$this->assertTrue($team->hasValue('DatabaseField', null, false));
1522
	}
1523
1524
	public function testHasMany() {
1525
		$company = new DataObjectTest_Company();
1526
1527
		$this->assertEquals (
1528
			array (
1529
				'CurrentStaff'     => 'DataObjectTest_Staff',
1530
				'PreviousStaff'    => 'DataObjectTest_Staff'
1531
			),
1532
			$company->hasMany(),
1533
			'has_many strips field name data by default.'
1534
		);
1535
1536
		$this->assertEquals (
1537
			'DataObjectTest_Staff',
1538
			$company->hasManyComponent('CurrentStaff'),
1539
			'has_many strips field name data by default on single relationships.'
1540
		);
1541
1542
		$this->assertEquals (
1543
			array (
1544
				'CurrentStaff'     => 'DataObjectTest_Staff.CurrentCompany',
1545
				'PreviousStaff'    => 'DataObjectTest_Staff.PreviousCompany'
1546
			),
1547
			$company->hasMany(null, false),
1548
			'has_many returns field name data when $classOnly is false.'
1549
		);
1550
1551
		$this->assertEquals (
1552
			'DataObjectTest_Staff.CurrentCompany',
1553
			$company->hasManyComponent('CurrentStaff', false),
1554
			'has_many returns field name data on single records when $classOnly is false.'
1555
		);
1556
	}
1557
1558
	public function testGetRemoteJoinField() {
1559
		$company = new DataObjectTest_Company();
1560
1561
		$staffJoinField = $company->getRemoteJoinField('CurrentStaff', 'has_many', $polymorphic);
1562
		$this->assertEquals('CurrentCompanyID', $staffJoinField);
1563
		$this->assertFalse($polymorphic, 'DataObjectTest_Company->CurrentStaff is not polymorphic');
1564
		$previousStaffJoinField = $company->getRemoteJoinField('PreviousStaff', 'has_many', $polymorphic);
1565
		$this->assertEquals('PreviousCompanyID', $previousStaffJoinField);
1566
		$this->assertFalse($polymorphic, 'DataObjectTest_Company->PreviousStaff is not polymorphic');
1567
1568
		$ceo = new DataObjectTest_CEO();
1569
1570
		$this->assertEquals('CEOID', $ceo->getRemoteJoinField('Company', 'belongs_to', $polymorphic));
1571
		$this->assertFalse($polymorphic, 'DataObjectTest_CEO->Company is not polymorphic');
1572
		$this->assertEquals('PreviousCEOID', $ceo->getRemoteJoinField('PreviousCompany', 'belongs_to', $polymorphic));
1573
		$this->assertFalse($polymorphic, 'DataObjectTest_CEO->PreviousCompany is not polymorphic');
1574
1575
		$team = new DataObjectTest_Team();
1576
1577
		$this->assertEquals('Favourite', $team->getRemoteJoinField('Fans', 'has_many', $polymorphic));
1578
		$this->assertTrue($polymorphic, 'DataObjectTest_Team->Fans is polymorphic');
1579
		$this->assertEquals('TeamID', $team->getRemoteJoinField('Comments', 'has_many', $polymorphic));
1580
		$this->assertFalse($polymorphic, 'DataObjectTest_Team->Comments is not polymorphic');
1581
	}
1582
1583
	public function testBelongsTo() {
1584
		$company = new DataObjectTest_Company();
1585
		$ceo     = new DataObjectTest_CEO();
1586
1587
		$company->write();
1588
		$ceo->write();
1589
1590
		// Test belongs_to assignment
1591
		$company->CEOID = $ceo->ID;
0 ignored issues
show
Documentation introduced by
The property CEOID does not exist on object<DataObjectTest_Company>. 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...
1592
		$company->write();
1593
1594
		$this->assertEquals($company->ID, $ceo->Company()->ID, 'belongs_to returns the right results.');
1595
1596
		// Test automatic creation of class where no assigment exists
1597
		$ceo = new DataObjectTest_CEO();
1598
		$ceo->write();
1599
1600
		$this->assertTrue (
1601
			$ceo->Company() instanceof DataObjectTest_Company,
1602
			'DataObjects across belongs_to relations are automatically created.'
1603
		);
1604
		$this->assertEquals($ceo->ID, $ceo->Company()->CEOID, 'Remote IDs are automatically set.');
1605
1606
		// Write object with components
1607
		$ceo->Name = 'Edward Scissorhands';
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<DataObjectTest_CEO>. 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...
1608
		$ceo->write(false, false, false, true);
1609
		$this->assertTrue($ceo->Company()->isInDB(), 'write() writes belongs_to components to the database.');
1610
1611
		$newCEO = DataObject::get_by_id('DataObjectTest_CEO', $ceo->ID);
1612
		$this->assertEquals (
1613
			$ceo->Company()->ID, $newCEO->Company()->ID, 'belongs_to can be retrieved from the database.'
1614
		);
1615
	}
1616
1617
	public function testBelongsToPolymorphic() {
1618
		$company = new DataObjectTest_Company();
1619
		$ceo     = new DataObjectTest_CEO();
1620
1621
		$company->write();
1622
		$ceo->write();
1623
1624
		// Test belongs_to assignment
1625
		$company->OwnerID = $ceo->ID;
0 ignored issues
show
Documentation introduced by
The property OwnerID does not exist on object<DataObjectTest_Company>. 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...
1626
		$company->OwnerClass = $ceo->class;
0 ignored issues
show
Documentation introduced by
The property OwnerClass does not exist on object<DataObjectTest_Company>. 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...
1627
		$company->write();
1628
1629
		$this->assertEquals($company->ID, $ceo->CompanyOwned()->ID, 'belongs_to returns the right results.');
1630
		$this->assertEquals($company->class, $ceo->CompanyOwned()->class, 'belongs_to returns the right results.');
1631
1632
		// Test automatic creation of class where no assigment exists
1633
		$ceo = new DataObjectTest_CEO();
1634
		$ceo->write();
1635
1636
		$this->assertTrue (
1637
			$ceo->CompanyOwned() instanceof DataObjectTest_Company,
1638
			'DataObjects across polymorphic belongs_to relations are automatically created.'
1639
		);
1640
		$this->assertEquals($ceo->ID, $ceo->CompanyOwned()->OwnerID, 'Remote IDs are automatically set.');
1641
		$this->assertInstanceOf($ceo->CompanyOwned()->OwnerClass, $ceo, 'Remote class is automatically  set');
1642
1643
		// Write object with components
1644
		$ceo->write(false, false, false, true);
1645
		$this->assertTrue($ceo->CompanyOwned()->isInDB(), 'write() writes belongs_to components to the database.');
1646
1647
		$newCEO = DataObject::get_by_id('DataObjectTest_CEO', $ceo->ID);
1648
		$this->assertEquals (
1649
			$ceo->CompanyOwned()->ID,
1650
			$newCEO->CompanyOwned()->ID,
1651
			'polymorphic belongs_to can be retrieved from the database.'
1652
		);
1653
	}
1654
1655
	/**
1656
	 * @expectedException LogicException
1657
	 */
1658
	public function testInvalidate() {
1659
		$do = new DataObjectTest_Fixture();
1660
		$do->write();
1661
1662
		$do->delete();
1663
1664
		$do->delete(); // Prohibit invalid object manipulation
1665
		$do->write();
1666
		$do->duplicate();
1667
	}
1668
1669
	public function testToMap() {
1670
		$obj = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam1');
1671
1672
		$map = $obj->toMap();
1673
1674
		$this->assertArrayHasKey('ID', $map, 'Contains base fields');
1675
		$this->assertArrayHasKey('Title', $map, 'Contains fields from parent class');
1676
		$this->assertArrayHasKey('SubclassDatabaseField', $map, 'Contains fields from concrete class');
1677
1678
		$this->assertEquals($obj->ID, $map['ID'],
1679
			'Contains values from base fields');
1680
		$this->assertEquals($obj->Title, $map['Title'],
1681
			'Contains values from parent class fields');
1682
		$this->assertEquals($obj->SubclassDatabaseField, $map['SubclassDatabaseField'],
1683
			'Contains values from concrete class fields');
1684
1685
		$newObj = new DataObjectTest_SubTeam();
1686
		$this->assertArrayHasKey('Title', $map, 'Contains null fields');
1687
	}
1688
1689
	public function testIsEmpty() {
1690
		$objEmpty = new DataObjectTest_Team();
1691
		$this->assertTrue($objEmpty->isEmpty(), 'New instance without populated defaults is empty');
1692
1693
		$objEmpty->Title = '0'; //
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<DataObjectTest_Team>. 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...
1694
		$this->assertFalse($objEmpty->isEmpty(), 'Zero value in attribute considered non-empty');
1695
	}
1696
1697
	public function testRelField() {
1698
		$captain = $this->objFromFixture('DataObjectTest_Player', 'captain1');
1699
		// Test traversal of a single has_one
1700
		$this->assertEquals("Team 1", $captain->relField('FavouriteTeam.Title'));
1701
		// Test direct field access
1702
		$this->assertEquals("Captain", $captain->relField('FirstName'));
1703
1704
		$player = $this->objFromFixture('DataObjectTest_Player', 'player2');
1705
		// Test that we can traverse more than once, and that arbitrary methods are okay
1706
		$this->assertEquals("Team 1", $player->relField('Teams.First.Title'));
1707
1708
		$newPlayer = new DataObjectTest_Player();
1709
		$this->assertNull($newPlayer->relField('Teams.First.Title'));
1710
1711
		// Test that relField works on db field manipulations
1712
		$comment = $this->objFromFixture('DataObjectTest_TeamComment', 'comment3');
1713
		$this->assertEquals("PHIL IS A UNIQUE GUY, AND COMMENTS ON TEAM2" , $comment->relField('Comment.UpperCase'));
1714
	}
1715
1716
	public function testRelObject() {
1717
		$captain = $this->objFromFixture('DataObjectTest_Player', 'captain1');
1718
1719
		// Test traversal of a single has_one
1720
		$this->assertInstanceOf("Varchar", $captain->relObject('FavouriteTeam.Title'));
1721
		$this->assertEquals("Team 1", $captain->relObject('FavouriteTeam.Title')->getValue());
1722
1723
		// Test direct field access
1724
		$this->assertInstanceOf("Boolean", $captain->relObject('IsRetired'));
1725
		$this->assertEquals(1, $captain->relObject('IsRetired')->getValue());
1726
1727
		$player = $this->objFromFixture('DataObjectTest_Player', 'player2');
1728
		// Test that we can traverse more than once, and that arbitrary methods are okay
1729
		$this->assertInstanceOf("Varchar", $player->relObject('Teams.First.Title'));
1730
		$this->assertEquals("Team 1", $player->relObject('Teams.First.Title')->getValue());
1731
	}
1732
1733
	public function testLateStaticBindingStyle() {
1734
		// Confirm that DataObjectTest_Player::get() operates as excepted
1735
		$this->assertEquals(4, DataObjectTest_Player::get()->Count());
1736
		$this->assertInstanceOf('DataObjectTest_Player', DataObjectTest_Player::get()->First());
1737
1738
		// You can't pass arguments to LSB syntax - use the DataList methods instead.
1739
		$this->setExpectedException('InvalidArgumentException');
1740
		DataObjectTest_Player::get(null, "\"ID\" = 1");
1741
1742
	}
1743
1744
	public function testBrokenLateStaticBindingStyle() {
1745
		// If you call DataObject::get() you have to pass a first argument
1746
		$this->setExpectedException('InvalidArgumentException');
1747
		DataObject::get();
1748
1749
	}
1750
1751
	public function testBigIntField() {
1752
		$staff = new DataObjectTest_Staff();
1753
		$staff->Salary = PHP_INT_MAX;
0 ignored issues
show
Documentation introduced by
The property Salary does not exist on object<DataObjectTest_Staff>. 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...
1754
		$staff->write();
1755
		$this->assertEquals(PHP_INT_MAX, DataObjectTest_Staff::get()->byID($staff->ID)->Salary);
1756
	}
1757
1758
1759
    /**
1760
     * @expectedException PHPUnit_Framework_Error_Warning
1761
     */
1762
	public function testSetFieldWithArrayOnScalarOnlyField()
1763
    {
1764
        $do = singleton('DataObjectTest_CompositeDBField');
1765
        $do->NonCompositeField = 'Some Value';
0 ignored issues
show
Bug introduced by
The property NonCompositeField does not seem to exist in SS_Object.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1766
        $do->NonCompositeField = array('Amount' => 123, 'Currency' => 'CAD');
1767
        $this->assertEmpty($do->NonCompositeField);
1768
    }
1769
1770
    public function testSetFieldWithArrayOnCompositeField()
1771
    {
1772
        $do = singleton('DataObjectTest_CompositeDBField');
1773
        $do->CompositeMoneyField = array('Amount' => 123, 'Currency' => 'CAD');
0 ignored issues
show
Bug introduced by
The property CompositeMoneyField does not seem to exist in SS_Object.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1774
        $this->assertNotEmpty($do->CompositeMoneyField);
1775
    }
1776
1777
1778
    public function testWriteManipulationWithNonScalarValuesAllowed()
1779
    {
1780
        $do = MockDynamicAssignmentDataObject::create();
1781
        $do->write();
1782
        $do->StaticScalarOnlyField = true;
1783
        $do->DynamicScalarOnlyField = false;
1784
        $do->DynamicField = true;
1785
        $do->write();
1786
        $this->assertEquals(1, $do->StaticScalarOnlyField);
1787
        $this->assertEquals(0, $do->DynamicScalarOnlyField);
1788
        $this->assertEquals(1, $do->DynamicField);
1789
    }
1790
1791
    /**
1792
     * @expectedException PHPUnit_Framework_Error
1793
     * @expectedExceptionMessageRegExp /parameterised field assignments are disallowed/
1794
     */
1795
    public function testWriteManipulationWithNonScalarValuesDisallowed()
1796
    {
1797
1798
        $do = MockDynamicAssignmentDataObject::create();
1799
        $do->write();
1800
        $do->StaticScalarOnlyField = false;
1801
        $do->DynamicScalarOnlyField = true;
1802
        $do->DynamicField = false;
1803
1804
        $do->write();
1805
    }
1806
}
1807
1808
class DataObjectTest_Sortable extends DataObject implements TestOnly {
1809
	private static $db = array(
1810
		'Sort' => 'Int',
1811
		'Name' => 'Varchar',
1812
	);
1813
}
1814
1815
class DataObjectTest_Player extends Member implements TestOnly {
1816
	private static $db = array(
1817
		'IsRetired' => 'Boolean',
1818
		'ShirtNumber' => 'Varchar',
1819
	);
1820
1821
	private static $has_one = array(
1822
		'FavouriteTeam' => 'DataObjectTest_Team',
1823
	);
1824
1825
	private static $belongs_many_many = array(
1826
		'Teams' => 'DataObjectTest_Team'
1827
	);
1828
1829
	private static $has_many = array(
1830
		'Fans' => 'DataObjectTest_Fan.Favourite' // Polymorphic - Player fans
1831
	);
1832
1833
	private static $belongs_to = array (
1834
		'CompanyOwned'    => 'DataObjectTest_Company.Owner'
1835
	);
1836
1837
	private static $searchable_fields = array(
1838
		'IsRetired',
1839
		'ShirtNumber'
1840
	);
1841
}
1842
1843
class DataObjectTest_Team extends DataObject implements TestOnly {
1844
1845
	private static $db = array(
1846
		'Title' => 'Varchar',
1847
		'DatabaseField' => 'HTMLVarchar'
1848
	);
1849
1850
	private static $has_one = array(
1851
		"Captain" => 'DataObjectTest_Player',
1852
		'HasOneRelationship' => 'DataObjectTest_Player',
1853
	);
1854
1855
	private static $has_many = array(
1856
		'SubTeams' => 'DataObjectTest_SubTeam',
1857
		'Comments' => 'DataObjectTest_TeamComment',
1858
		'Fans' => 'DataObjectTest_Fan.Favourite' // Polymorphic - Team fans
1859
	);
1860
1861
	private static $many_many = array(
1862
		'Players' => 'DataObjectTest_Player'
1863
	);
1864
1865
	private static $many_many_extraFields = array(
1866
		'Players' => array(
1867
			'Position' => 'Varchar(100)'
1868
		)
1869
	);
1870
1871
	private static $belongs_many_many = array(
1872
		'Sponsors' => 'DataObjectTest_EquipmentCompany.SponsoredTeams',
1873
		'EquipmentSuppliers' => 'DataObjectTest_EquipmentCompany.EquipmentCustomers'
1874
	);
1875
1876
	private static $summary_fields = array(
1877
		'Title' => 'Custom Title',
1878
		'Title.UpperCase' => 'Title',
1879
		'Captain.ShirtNumber' => 'Captain\'s shirt number',
1880
		'Captain.FavouriteTeam.Title' => 'Captain\'s favourite team'
1881
	);
1882
1883
	private static $default_sort = '"Title"';
1884
1885
	public function MyTitle() {
1886
		return 'Team ' . $this->Title;
1887
	}
1888
1889
	public function getDynamicField() {
1890
		return 'dynamicfield';
1891
	}
1892
1893
}
1894
1895
class DataObjectTest_Fixture extends DataObject implements TestOnly {
1896
	private static $db = array(
1897
		// Funny field names
1898
		'Data' => 'Varchar',
1899
		'Duplicate' => 'Varchar',
1900
		'DbObject' => 'Varchar',
1901
1902
		// Field types
1903
		'DateField' => 'Date',
1904
		'DatetimeField' => 'Datetime',
1905
1906
		'MyFieldWithDefault' => 'Varchar',
1907
		'MyFieldWithAltDefault' => 'Varchar'
1908
	);
1909
1910
	private static $defaults = array(
1911
		'MyFieldWithDefault' => 'Default Value',
1912
	);
1913
1914
	private static $summary_fields = array(
1915
		'Data' => 'Data',
1916
		'DateField.Nice' => 'Date'
1917
	);
1918
1919
	private static $default_sort = '"DataObjectTest_Fixture"."ID" ASC';
1920
1921
	private static $searchable_fields = array();
1922
1923
	public function populateDefaults() {
1924
		parent::populateDefaults();
1925
1926
		$this->MyFieldWithAltDefault = 'Default Value';
0 ignored issues
show
Documentation introduced by
The property MyFieldWithAltDefault does not exist on object<DataObjectTest_Fixture>. 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...
1927
	}
1928
1929
}
1930
1931
class DataObjectTest_SubTeam extends DataObjectTest_Team implements TestOnly {
1932
	private static $db = array(
1933
		'SubclassDatabaseField' => 'Varchar'
1934
	);
1935
1936
	private static $has_one = array(
1937
		"ParentTeam" => 'DataObjectTest_Team',
1938
	);
1939
1940
	private static $many_many = array(
1941
		'FormerPlayers' => 'DataObjectTest_Player'
1942
	);
1943
1944
	private static $many_many_extraFields = array(
1945
		'FormerPlayers' => array(
1946
			'Position' => 'Varchar(100)'
1947
		)
1948
	);
1949
}
1950
class OtherSubclassWithSameField extends DataObjectTest_Team implements TestOnly {
1951
	private static $db = array(
1952
		'SubclassDatabaseField' => 'Varchar',
1953
	);
1954
}
1955
1956
1957
class DataObjectTest_FieldlessTable extends DataObject implements TestOnly {
1958
}
1959
1960
class DataObjectTest_FieldlessSubTable extends DataObjectTest_Team implements TestOnly {
1961
}
1962
1963
1964
class DataObjectTest_Team_Extension extends DataExtension implements TestOnly {
1965
1966
	private static $db = array(
1967
		'ExtendedDatabaseField' => 'Varchar'
1968
	);
1969
1970
	private static $has_one = array(
1971
		'ExtendedHasOneRelationship' => 'DataObjectTest_Player'
1972
	);
1973
1974
	public function getExtendedDynamicField() {
1975
		return "extended dynamic field";
1976
	}
1977
1978
}
1979
1980
class DataObjectTest_ValidatedObject extends DataObject implements TestOnly {
1981
1982
	private static $db = array(
1983
		'Name' => 'Varchar(50)'
1984
	);
1985
1986
	protected function validate() {
1987
		if(!empty($this->Name)) {
1988
			return new ValidationResult();
1989
		} else {
1990
			return new ValidationResult(false, "This object needs a name. Otherwise it will have an identity crisis!");
1991
		}
1992
	}
1993
}
1994
1995
class DataObjectTest_Company extends DataObject implements TestOnly {
1996
1997
	private static $db = array(
1998
		'Name' => 'Varchar'
1999
	);
2000
2001
	private static $has_one = array (
2002
		'CEO'         => 'DataObjectTest_CEO',
2003
		'PreviousCEO' => 'DataObjectTest_CEO',
2004
		'Owner'       => 'DataObject' // polymorphic
2005
	);
2006
2007
	private static $has_many = array (
2008
		'CurrentStaff'     => 'DataObjectTest_Staff.CurrentCompany',
2009
		'PreviousStaff'    => 'DataObjectTest_Staff.PreviousCompany'
2010
	);
2011
}
2012
2013
class DataObjectTest_EquipmentCompany extends DataObjectTest_Company implements TestOnly {
2014
	private static $many_many = array(
2015
		'SponsoredTeams' => 'DataObjectTest_Team',
2016
		'EquipmentCustomers' => 'DataObjectTest_Team'
2017
	);
2018
2019
	private static $many_many_extraFields = array(
2020
		'SponsoredTeams' => array(
2021
			'SponsorFee' => 'Int'
2022
		)
2023
	);
2024
}
2025
2026
class DataObjectTest_SubEquipmentCompany extends DataObjectTest_EquipmentCompany implements TestOnly {
2027
	private static $db = array(
2028
		'SubclassDatabaseField' => 'Varchar',
2029
	);
2030
}
2031
2032
class DataObjectTest_Staff extends DataObject implements TestOnly {
2033
	private static $db = array(
2034
		'Salary' => 'BigInt',
2035
	);
2036
	private static $has_one = array (
2037
		'CurrentCompany'  => 'DataObjectTest_Company',
2038
		'PreviousCompany' => 'DataObjectTest_Company'
2039
	);
2040
}
2041
2042
class DataObjectTest_CEO extends DataObjectTest_Staff {
2043
	private static $belongs_to = array (
2044
		'Company'         => 'DataObjectTest_Company.CEO',
2045
		'PreviousCompany' => 'DataObjectTest_Company.PreviousCEO',
2046
		'CompanyOwned'    => 'DataObjectTest_Company.Owner'
2047
	);
2048
}
2049
2050
class DataObjectTest_TeamComment extends DataObject implements TestOnly {
2051
	private static $db = array(
2052
		'Name' => 'Varchar',
2053
		'Comment' => 'Text'
2054
	);
2055
2056
	private static $has_one = array(
2057
		'Team' => 'DataObjectTest_Team'
2058
	);
2059
2060
	private static $default_sort = '"Name" ASC';
2061
}
2062
2063
class DataObjectTest_Fan extends DataObject implements TestOnly {
2064
2065
	private static $db = array(
2066
		'Name' => 'Varchar(255)'
2067
	);
2068
2069
	private static $has_one = array(
2070
		'Favourite' => 'DataObject', // Polymorphic relation
2071
		'SecondFavourite' => 'DataObject'
2072
	);
2073
}
2074
2075
class DataObjectTest_ExtendedTeamComment extends DataObjectTest_TeamComment {
2076
	private static $db = array(
2077
		'Comment' => 'HTMLText'
2078
	);
2079
}
2080
2081
class DataObjectTest_Play extends DataObject implements TestOnly {}
2082
class DataObjectTest_Ploy extends DataObject implements TestOnly {}
2083
class DataObjectTest_Bogey extends DataObject implements TestOnly {}
2084
2085
DataObjectTest_Team::add_extension('DataObjectTest_Team_Extension');
2086
2087
class DataObjectTest_CompositeDBField extends DataObject implements TestOnly {
2088
    private static $db = array(
2089
        'NonCompositeField' => 'Varchar',
2090
        'CompositeMoneyField' => 'Money',
2091
    );
2092
}