Completed
Push — master ( c6c71f...1e53f2 )
by Hamish
11:24 queued 33s
created

DataObjectTest::testBelongsTo()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 47
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 47
rs 9.0303
cc 1
eloc 27
nc 1
nop 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 9 and the first side effect is on line 2026.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
3
use SilverStripe\Model\FieldType\DBField;
4
5
/**
6
 * @package framework
7
 * @subpackage tests
8
 */
9
class DataObjectTest extends SapphireTest {
10
11
	protected static $fixture_file = 'DataObjectTest.yml';
12
13
	protected $extraDataObjects = array(
14
		'DataObjectTest_Team',
15
		'DataObjectTest_Fixture',
16
		'DataObjectTest_SubTeam',
17
		'OtherSubclassWithSameField',
18
		'DataObjectTest_FieldlessTable',
19
		'DataObjectTest_FieldlessSubTable',
20
		'DataObjectTest_ValidatedObject',
21
		'DataObjectTest_Player',
22
		'DataObjectTest_TeamComment',
23
		'DataObjectTest_EquipmentCompany',
24
		'DataObjectTest_SubEquipmentCompany',
25
		'DataObjectTest\NamespacedClass',
26
		'DataObjectTest\RelationClass',
27
		'DataObjectTest_ExtendedTeamComment',
28
		'DataObjectTest_Company',
29
		'DataObjectTest_Staff',
30
		'DataObjectTest_CEO',
31
		'DataObjectTest_Fan',
32
		'DataObjectTest_Play',
33
		'DataObjectTest_Ploy',
34
		'DataObjectTest_Bogey',
35
	);
36
37
	public function testDb() {
38
		$obj = new DataObjectTest_TeamComment();
39
		$dbFields = $obj->db();
40
41
		// Assert fields are included
42
		$this->assertArrayHasKey('Name', $dbFields);
43
44
		// Assert the base fields are included
45
		$this->assertArrayHasKey('Created', $dbFields);
46
		$this->assertArrayHasKey('LastEdited', $dbFields);
47
		$this->assertArrayHasKey('ClassName', $dbFields);
48
		$this->assertArrayHasKey('ID', $dbFields);
49
50
		// Assert that the correct field type is returned when passing a field
51
		$this->assertEquals('Varchar', $obj->db('Name'));
52
		$this->assertEquals('Text', $obj->db('Comment'));
53
54
		// Test with table required
55
		$this->assertEquals('DataObjectTest_TeamComment.Varchar', $obj->db('Name', true));
56
		$this->assertEquals('DataObjectTest_TeamComment.Text', $obj->db('Comment', true));
57
58
		$obj = new DataObjectTest_ExtendedTeamComment();
59
		$dbFields = $obj->db();
60
61
		// fixed fields are still included in extended classes
62
		$this->assertArrayHasKey('Created', $dbFields);
63
		$this->assertArrayHasKey('LastEdited', $dbFields);
64
		$this->assertArrayHasKey('ClassName', $dbFields);
65
		$this->assertArrayHasKey('ID', $dbFields);
66
67
		// Assert overloaded fields have correct data type
68
		$this->assertEquals('HTMLText', $obj->db('Comment'));
69
		$this->assertEquals('HTMLText', $dbFields['Comment'],
70
			'Calls to DataObject::db without a field specified return correct data types');
71
72
		// assertEquals doesn't verify the order of array elements, so access keys manually to check order:
73
		// expected: array('Name' => 'Varchar', 'Comment' => 'HTMLText')
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
74
		$this->assertEquals(
75
			array(
76
				'Name',
77
				'Comment'
78
			),
79
			array_slice(array_keys($dbFields), 4, 2),
80
			'DataObject::db returns fields in correct order'
81
		);
82
	}
83
84
	public function testConstructAcceptsValues() {
85
		// Values can be an array...
86
		$player = new DataObjectTest_Player(array(
87
			'FirstName' => 'James',
88
			'Surname' => 'Smith'
89
		));
90
91
		$this->assertEquals('James', $player->FirstName);
92
		$this->assertEquals('Smith', $player->Surname);
93
94
		// ... or a stdClass inst
95
		$data = new stdClass();
96
		$data->FirstName = 'John';
97
		$data->Surname = 'Doe';
98
		$player = new DataObjectTest_Player($data);
99
100
		$this->assertEquals('John', $player->FirstName);
101
		$this->assertEquals('Doe', $player->Surname);
102
103
		// IDs should be stored as integers, not strings
104
		$player = new DataObjectTest_Player(array('ID' => '5'));
105
		$this->assertSame(5, $player->ID);
106
	}
107
108
	public function testValidObjectsForBaseFields() {
109
		$obj = new DataObjectTest_ValidatedObject();
110
111
		foreach (array('Created', 'LastEdited', 'ClassName', 'ID') as $field) {
112
			$helper = $obj->dbObject($field);
113
			$this->assertTrue(
114
				($helper instanceof DBField),
115
				"for {$field} expected helper to be DBField, but was " .
116
				(is_object($helper) ? get_class($helper) : "null")
117
			);
118
		}
119
	}
120
121
	public function testDataIntegrityWhenTwoSubclassesHaveSameField() {
122
		// Save data into DataObjectTest_SubTeam.SubclassDatabaseField
123
		$obj = new DataObjectTest_SubTeam();
124
		$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...
125
		$obj->write();
126
127
		// Change the class
128
		$obj->ClassName = 'OtherSubclassWithSameField';
129
		$obj->write();
130
		$obj->flushCache();
131
132
		// Re-fetch from the database and confirm that the data is sourced from
133
		// OtherSubclassWithSameField.SubclassDatabaseField
134
		$obj = DataObject::get_by_id('DataObjectTest_Team', $obj->ID);
135
		$this->assertNull($obj->SubclassDatabaseField);
136
137
		// Confirm that save the object in the other direction.
138
		$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...
139
		$obj->write();
140
141
		$obj->ClassName = 'DataObjectTest_SubTeam';
142
		$obj->write();
143
		$obj->flushCache();
144
145
		// If we restore the class, the old value has been lying dormant and will be available again.
146
		// NOTE: This behaviour is volatile; we may change this in the future to clear fields that
147
		// are no longer relevant when changing ClassName
148
		$obj = DataObject::get_by_id('DataObjectTest_Team', $obj->ID);
149
		$this->assertEquals('obj-SubTeam', $obj->SubclassDatabaseField);
150
	}
151
152
	/**
153
	 * Test deletion of DataObjects
154
	 *   - Deleting using delete() on the DataObject
155
	 *   - Deleting using DataObject::delete_by_id()
156
	 */
157
	public function testDelete() {
158
		// Test deleting using delete() on the DataObject
159
		// Get the first page
160
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain1');
161
		$objID = $obj->ID;
162
		// Check the page exists before deleting
163
		$this->assertTrue(is_object($obj) && $obj->exists());
164
		// Delete the page
165
		$obj->delete();
166
		// Check that page does not exist after deleting
167
		$obj = DataObject::get_by_id('DataObjectTest_Player', $objID);
168
		$this->assertTrue(!$obj || !$obj->exists());
169
170
171
		// Test deleting using DataObject::delete_by_id()
172
		// Get the second page
173
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain2');
174
		$objID = $obj->ID;
175
		// Check the page exists before deleting
176
		$this->assertTrue(is_object($obj) && $obj->exists());
177
		// Delete the page
178
		DataObject::delete_by_id('DataObjectTest_Player', $obj->ID);
179
		// Check that page does not exist after deleting
180
		$obj = DataObject::get_by_id('DataObjectTest_Player', $objID);
181
		$this->assertTrue(!$obj || !$obj->exists());
182
	}
183
184
	/**
185
	 * Test methods that get DataObjects
186
	 *   - DataObject::get()
187
	 *       - All records of a DataObject
188
	 *       - Filtering
189
	 *       - Sorting
190
	 *       - Joins
191
	 *       - Limit
192
	 *       - Container class
193
	 *   - DataObject::get_by_id()
194
	 *   - DataObject::get_one()
195
	 *        - With and without caching
196
	 *        - With and without ordering
197
	 */
198
	public function testGet() {
199
		// Test getting all records of a DataObject
200
		$comments = DataObject::get('DataObjectTest_TeamComment');
201
		$this->assertEquals(3, $comments->Count());
202
203
		// Test WHERE clause
204
		$comments = DataObject::get('DataObjectTest_TeamComment', "\"Name\"='Bob'");
205
		$this->assertEquals(1, $comments->Count());
206
		foreach($comments as $comment) {
207
			$this->assertEquals('Bob', $comment->Name);
208
		}
209
210
		// Test sorting
211
		$comments = DataObject::get('DataObjectTest_TeamComment', '', "\"Name\" ASC");
212
		$this->assertEquals(3, $comments->Count());
213
		$this->assertEquals('Bob', $comments->First()->Name);
214
		$comments = DataObject::get('DataObjectTest_TeamComment', '', "\"Name\" DESC");
215
		$this->assertEquals(3, $comments->Count());
216
		$this->assertEquals('Phil', $comments->First()->Name);
217
218
		// Test limit
219
		$comments = DataObject::get('DataObjectTest_TeamComment', '', "\"Name\" ASC", '', '1,2');
220
		$this->assertEquals(2, $comments->Count());
221
		$this->assertEquals('Joe', $comments->First()->Name);
222
		$this->assertEquals('Phil', $comments->Last()->Name);
223
224
		// Test get_by_id()
225
		$captain1ID = $this->idFromFixture('DataObjectTest_Player', 'captain1');
226
		$captain1 = DataObject::get_by_id('DataObjectTest_Player', $captain1ID);
227
		$this->assertEquals('Captain', $captain1->FirstName);
228
229
		// Test get_one() without caching
230
		$comment1 = DataObject::get_one('DataObjectTest_TeamComment', array(
231
			'"DataObjectTest_TeamComment"."Name"' => 'Joe'
232
		), false);
233
		$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...
234
235
		$comment2 = DataObject::get_one('DataObjectTest_TeamComment', array(
236
			'"DataObjectTest_TeamComment"."Name"' => 'Joe'
237
		), false);
238
		$this->assertNotEquals($comment1->Comment, $comment2->Comment);
239
240
		// Test get_one() with caching
241
		$comment1 = DataObject::get_one('DataObjectTest_TeamComment', array(
242
			'"DataObjectTest_TeamComment"."Name"' => 'Bob'
243
		), true);
244
		$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...
245
246
		$comment2 = DataObject::get_one('DataObjectTest_TeamComment', array(
247
			'"DataObjectTest_TeamComment"."Name"' => 'Bob'
248
		), true);
249
		$this->assertEquals((string)$comment1->Comment, (string)$comment2->Comment);
250
251
		// Test get_one() with order by without caching
252
		$comment = DataObject::get_one('DataObjectTest_TeamComment', '', false, "\"Name\" ASC");
253
		$this->assertEquals('Bob', $comment->Name);
254
255
		$comment = DataObject::get_one('DataObjectTest_TeamComment', '', false, "\"Name\" DESC");
256
		$this->assertEquals('Phil', $comment->Name);
257
258
		// Test get_one() with order by with caching
259
		$comment = DataObject::get_one('DataObjectTest_TeamComment', '', true, '"Name" ASC');
260
		$this->assertEquals('Bob', $comment->Name);
261
		$comment = DataObject::get_one('DataObjectTest_TeamComment', '', true, '"Name" DESC');
262
		$this->assertEquals('Phil', $comment->Name);
263
	}
264
265
	public function testGetCaseInsensitive() {
266
		// Test get_one() with bad case on the classname
267
		// Note: This will succeed only if the underlying DB server supports case-insensitive
268
		// table names (e.g. such as MySQL, but not SQLite3)
269
		if(!(DB::get_conn() instanceof MySQLDatabase)) {
270
			$this->markTestSkipped('MySQL only');
271
		}
272
273
		$subteam1 = DataObject::get_one('dataobjecttest_subteam', array(
274
			'"DataObjectTest_Team"."Title"' => 'Subteam 1'
275
		), true);
276
		$this->assertNotEmpty($subteam1);
277
		$this->assertEquals($subteam1->Title, "Subteam 1");
278
	}
279
280
	public function testGetSubclassFields() {
281
		/* Test that fields / has_one relations from the parent table and the subclass tables are extracted */
282
		$captain1 = $this->objFromFixture("DataObjectTest_Player", "captain1");
283
		// Base field
284
		$this->assertEquals('Captain', $captain1->FirstName);
285
		// Subclass field
286
		$this->assertEquals('007', $captain1->ShirtNumber);
287
		// Subclass has_one relation
288
		$this->assertEquals($this->idFromFixture('DataObjectTest_Team', 'team1'), $captain1->FavouriteTeamID);
289
	}
290
291
	public function testGetRelationClass() {
292
		$obj = new DataObjectTest_Player();
293
		$this->assertEquals(singleton('DataObjectTest_Player')->getRelationClass('FavouriteTeam'),
294
			'DataObjectTest_Team', 'has_one is properly inspected');
295
		$this->assertEquals(singleton('DataObjectTest_Company')->getRelationClass('CurrentStaff'),
296
			'DataObjectTest_Staff', 'has_many is properly inspected');
297
		$this->assertEquals(singleton('DataObjectTest_Team')->getRelationClass('Players'), 'DataObjectTest_Player',
298
			'many_many is properly inspected');
299
		$this->assertEquals(singleton('DataObjectTest_Player')->getRelationClass('Teams'), 'DataObjectTest_Team',
300
			'belongs_many_many is properly inspected');
301
		$this->assertEquals(singleton('DataObjectTest_CEO')->getRelationClass('Company'), 'DataObjectTest_Company',
302
			'belongs_to is properly inspected');
303
		$this->assertEquals(singleton('DataObjectTest_Fan')->getRelationClass('Favourite'), 'DataObject',
304
			'polymorphic has_one is properly inspected');
305
	}
306
307
	/**
308
	 * Test that has_one relations can be retrieved
309
	 */
310
	public function testGetHasOneRelations() {
311
		$captain1 = $this->objFromFixture("DataObjectTest_Player", "captain1");
312
		$team1ID = $this->idFromFixture('DataObjectTest_Team', 'team1');
313
314
		// There will be a field called (relname)ID that contains the ID of the
315
		// object linked to via the has_one relation
316
		$this->assertEquals($team1ID, $captain1->FavouriteTeamID);
317
318
		// There will be a method called $obj->relname() that returns the object itself
319
		$this->assertEquals($team1ID, $captain1->FavouriteTeam()->ID);
320
321
		// Test that getNonReciprocalComponent can find has_one from the has_many end
322
		$this->assertEquals(
323
			$team1ID,
324
			$captain1->inferReciprocalComponent('DataObjectTest_Team', 'PlayerFans')->ID
325
		);
326
327
		// Check entity with polymorphic has-one
328
		$fan1 = $this->objFromFixture("DataObjectTest_Fan", "fan1");
329
		$this->assertTrue((bool)$fan1->hasValue('Favourite'));
330
331
		// There will be fields named (relname)ID and (relname)Class for polymorphic
332
		// entities
333
		$this->assertEquals($team1ID, $fan1->FavouriteID);
334
		$this->assertEquals('DataObjectTest_Team', $fan1->FavouriteClass);
335
336
		// There will be a method called $obj->relname() that returns the object itself
337
		$favourite = $fan1->Favourite();
338
		$this->assertEquals($team1ID, $favourite->ID);
339
		$this->assertInstanceOf('DataObjectTest_Team', $favourite);
340
341
		// check behaviour of dbObject with polymorphic relations
342
		$favouriteDBObject = $fan1->dbObject('Favourite');
343
		$favouriteValue = $favouriteDBObject->getValue();
344
		$this->assertInstanceOf('SilverStripe\Model\FieldType\DBPolymorphicForeignKey', $favouriteDBObject);
345
		$this->assertEquals($favourite->ID, $favouriteValue->ID);
346
		$this->assertEquals($favourite->ClassName, $favouriteValue->ClassName);
347
	}
348
349
	/**
350
	 * Simple test to ensure that namespaced classes and polymorphic relations work together
351
	 */
352
	public function testPolymorphicNamespacedRelations() {
353
		$parent = new \DataObjectTest\NamespacedClass();
354
		$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...
355
		$parent->write();
356
357
		$child = new \DataObjectTest\RelationClass();
358
		$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...
359
		$child->write();
360
		$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...
361
362
		$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...
363
		$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...
364
		$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...
365
	}
366
367
	public function testLimitAndCount() {
368
		$players = DataObject::get("DataObjectTest_Player");
369
370
		// There's 4 records in total
371
		$this->assertEquals(4, $players->count());
372
373
		// Testing "##, ##" syntax
374
		$this->assertEquals(4, $players->limit(20)->count());
375
		$this->assertEquals(4, $players->limit(20, 0)->count());
376
		$this->assertEquals(0, $players->limit(20, 20)->count());
377
		$this->assertEquals(2, $players->limit(2, 0)->count());
378
		$this->assertEquals(1, $players->limit(5, 3)->count());
379
	}
380
381
	/**
382
	 * Test writing of database columns which don't correlate to a DBField,
383
	 * e.g. all relation fields on has_one/has_many like "ParentID".
384
	 *
385
	 */
386
	public function testWritePropertyWithoutDBField() {
387
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain1');
388
		$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...
389
		$obj->write();
390
391
		// reload the page from the database
392
		$savedObj = DataObject::get_by_id('DataObjectTest_Player', $obj->ID);
393
		$this->assertTrue($savedObj->FavouriteTeamID == 99);
394
395
		// Test with porymorphic relation
396
		$obj2 = $this->objFromFixture("DataObjectTest_Fan", "fan1");
397
		$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...
398
		$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...
399
		$obj2->write();
400
401
		$savedObj2 = DataObject::get_by_id('DataObjectTest_Fan', $obj2->ID);
402
		$this->assertTrue($savedObj2->FavouriteID == 99);
403
		$this->assertTrue($savedObj2->FavouriteClass == 'DataObjectTest_Player');
404
	}
405
406
	/**
407
	 * Test has many relationships
408
	 *   - Test getComponents() gets the ComponentSet of the other side of the relation
409
	 *   - Test the IDs on the DataObjects are set correctly
410
	 */
411
	public function testHasManyRelationships() {
412
		$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
413
414
		// Test getComponents() gets the ComponentSet of the other side of the relation
415
		$this->assertTrue($team1->Comments()->Count() == 2);
416
417
		$team1Comments = [
418
			['Comment' => 'This is a team comment by Joe'],
419
			['Comment' => 'This is a team comment by Bob'],
420
		];
421
422
		// Test the IDs on the DataObjects are set correctly
423
		$this->assertDOSEquals($team1Comments, $team1->Comments());
424
425
		// Test that has_many can be infered from the has_one via getNonReciprocalComponent
426
		$this->assertDOSEquals(
427
			$team1Comments,
428
			$team1->inferReciprocalComponent('DataObjectTest_TeamComment', 'Team')
429
		);
430
431
		// Test that we can add and remove items that already exist in the database
432
		$newComment = new DataObjectTest_TeamComment();
433
		$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...
434
		$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...
435
		$newComment->write();
436
		$team1->Comments()->add($newComment);
437
		$this->assertEquals($team1->ID, $newComment->TeamID);
438
439
		$comment1 = $this->objFromFixture('DataObjectTest_TeamComment', 'comment1');
440
		$comment2 = $this->objFromFixture('DataObjectTest_TeamComment', 'comment2');
441
		$team1->Comments()->remove($comment2);
442
443
		$team1CommentIDs = $team1->Comments()->sort('ID')->column('ID');
444
		$this->assertEquals(array($comment1->ID, $newComment->ID), $team1CommentIDs);
445
446
		// Test that removing an item from a list doesn't remove it from the same
447
		// relation belonging to a different object
448
		$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
449
		$team2 = $this->objFromFixture('DataObjectTest_Team', 'team2');
450
		$team2->Comments()->remove($comment1);
451
		$team1CommentIDs = $team1->Comments()->sort('ID')->column('ID');
452
		$this->assertEquals(array($comment1->ID, $newComment->ID), $team1CommentIDs);
453
	}
454
455
456
	/**
457
	 * Test has many relationships against polymorphic has_one fields
458
	 *   - Test getComponents() gets the ComponentSet of the other side of the relation
459
	 *   - Test the IDs on the DataObjects are set correctly
460
	 */
461
	public function testHasManyPolymorphicRelationships() {
462
		$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
463
464
		// Test getComponents() gets the ComponentSet of the other side of the relation
465
		$this->assertTrue($team1->Fans()->Count() == 2);
466
467
		// Test the IDs/Classes on the DataObjects are set correctly
468
		foreach($team1->Fans() as $fan) {
469
			$this->assertEquals($team1->ID, $fan->FavouriteID, 'Fan has the correct FavouriteID');
470
			$this->assertEquals('DataObjectTest_Team', $fan->FavouriteClass, 'Fan has the correct FavouriteClass');
471
		}
472
473
		// Test that we can add and remove items that already exist in the database
474
		$newFan = new DataObjectTest_Fan();
475
		$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...
476
		$newFan->write();
477
		$team1->Fans()->add($newFan);
478
		$this->assertEquals($team1->ID, $newFan->FavouriteID, 'Newly created fan has the correct FavouriteID');
479
		$this->assertEquals(
480
			'DataObjectTest_Team',
481
			$newFan->FavouriteClass,
482
			'Newly created fan has the correct FavouriteClass'
483
		);
484
485
		$fan1 = $this->objFromFixture('DataObjectTest_Fan', 'fan1');
486
		$fan3 = $this->objFromFixture('DataObjectTest_Fan', 'fan3');
487
		$team1->Fans()->remove($fan3);
488
489
		$team1FanIDs = $team1->Fans()->sort('ID')->column('ID');
490
		$this->assertEquals(array($fan1->ID, $newFan->ID), $team1FanIDs);
491
492
		// Test that removing an item from a list doesn't remove it from the same
493
		// relation belonging to a different object
494
		$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
495
		$player1 = $this->objFromFixture('DataObjectTest_Player', 'player1');
496
		$player1->Fans()->remove($fan1);
497
		$team1FanIDs = $team1->Fans()->sort('ID')->column('ID');
498
		$this->assertEquals(array($fan1->ID, $newFan->ID), $team1FanIDs);
499
	}
500
501
502
	public function testHasOneRelationship() {
503
		$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
504
		$player1 = $this->objFromFixture('DataObjectTest_Player', 'player1');
505
		$player2 = $this->objFromFixture('DataObjectTest_Player', 'player2');
506
		$fan1 = $this->objFromFixture('DataObjectTest_Fan', 'fan1');
507
508
		// Test relation probing
509
		$this->assertFalse((bool)$team1->hasValue('Captain', null, false));
510
		$this->assertFalse((bool)$team1->hasValue('CaptainID', null, false));
511
512
		// Add a captain to team 1
513
		$team1->setField('CaptainID', $player1->ID);
514
		$team1->write();
515
516
		$this->assertTrue((bool)$team1->hasValue('Captain', null, false));
517
		$this->assertTrue((bool)$team1->hasValue('CaptainID', null, false));
518
519
		$this->assertEquals($player1->ID, $team1->Captain()->ID,
520
			'The captain exists for team 1');
521
		$this->assertEquals($player1->ID, $team1->getComponent('Captain')->ID,
522
			'The captain exists through the component getter');
523
524
		$this->assertEquals($team1->Captain()->FirstName, 'Player 1',
525
			'Player 1 is the captain');
526
		$this->assertEquals($team1->getComponent('Captain')->FirstName, 'Player 1',
527
			'Player 1 is the captain');
528
529
		$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...
530
		$team1->write();
531
532
		$this->assertEquals($player2->ID, $team1->Captain()->ID);
533
		$this->assertEquals($player2->ID, $team1->getComponent('Captain')->ID);
534
		$this->assertEquals('Player 2', $team1->Captain()->FirstName);
535
		$this->assertEquals('Player 2', $team1->getComponent('Captain')->FirstName);
536
537
538
		// Set the favourite team for fan1
539
		$fan1->setField('FavouriteID', $team1->ID);
540
		$fan1->setField('FavouriteClass', $team1->class);
541
542
		$this->assertEquals($team1->ID, $fan1->Favourite()->ID, 'The team is assigned to fan 1');
543
		$this->assertInstanceOf($team1->class, $fan1->Favourite(), 'The team is assigned to fan 1');
544
		$this->assertEquals($team1->ID, $fan1->getComponent('Favourite')->ID,
545
			'The team exists through the component getter'
546
		);
547
		$this->assertInstanceOf($team1->class, $fan1->getComponent('Favourite'),
548
			'The team exists through the component getter'
549
		);
550
551
		$this->assertEquals($fan1->Favourite()->Title, 'Team 1',
552
			'Team 1 is the favourite');
553
		$this->assertEquals($fan1->getComponent('Favourite')->Title, 'Team 1',
554
			'Team 1 is the favourite');
555
	}
556
557
	/**
558
	 * @todo Extend type change tests (e.g. '0'==NULL)
559
	 */
560
	public function testChangedFields() {
561
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain1');
562
		$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...
563
		$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...
564
565
		$this->assertEquals(
566
			$obj->getChangedFields(false, 1),
567
			array(
568
				'FirstName' => array(
569
					'before' => 'Captain',
570
					'after' => 'Captain-changed',
571
					'level' => 2
572
				),
573
				'IsRetired' => array(
574
					'before' => 1,
575
					'after' => true,
576
					'level' => 1
577
				)
578
			),
579
			'Changed fields are correctly detected with strict type changes (level=1)'
580
		);
581
582
		$this->assertEquals(
583
			$obj->getChangedFields(false, 2),
584
			array(
585
				'FirstName' => array(
586
					'before'=>'Captain',
587
					'after'=>'Captain-changed',
588
					'level' => 2
589
				)
590
			),
591
			'Changed fields are correctly detected while ignoring type changes (level=2)'
592
		);
593
594
		$newObj = new DataObjectTest_Player();
595
		$newObj->FirstName = "New Player";
596
		$this->assertEquals(
597
			$newObj->getChangedFields(false, 2),
598
			array(
599
				'FirstName' => array(
600
					'before' => null,
601
					'after' => 'New Player',
602
					'level' => 2
603
				)
604
			),
605
			'Initialised fields are correctly detected as full changes'
606
		);
607
	}
608
609
	public function testIsChanged() {
610
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain1');
611
		$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...
612
		$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...
613
614
		$this->assertTrue($obj->isChanged('FirstName', 1));
615
		$this->assertTrue($obj->isChanged('FirstName', 2));
616
		$this->assertTrue($obj->isChanged('IsRetired', 1));
617
		$this->assertFalse($obj->isChanged('IsRetired', 2));
618
		$this->assertFalse($obj->isChanged('Email', 1), 'Doesnt change mark unchanged property');
619
		$this->assertFalse($obj->isChanged('Email', 2), 'Doesnt change mark unchanged property');
620
621
		$newObj = new DataObjectTest_Player();
622
		$newObj->FirstName = "New Player";
623
		$this->assertTrue($newObj->isChanged('FirstName', 1));
624
		$this->assertTrue($newObj->isChanged('FirstName', 2));
625
		$this->assertFalse($newObj->isChanged('Email', 1));
626
		$this->assertFalse($newObj->isChanged('Email', 2));
627
628
		$newObj->write();
629
		$this->assertFalse($newObj->isChanged('FirstName', 1));
630
		$this->assertFalse($newObj->isChanged('FirstName', 2));
631
		$this->assertFalse($newObj->isChanged('Email', 1));
632
		$this->assertFalse($newObj->isChanged('Email', 2));
633
634
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain1');
635
		$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...
636
		$this->assertTrue($obj->isChanged('FirstName', 1));
637
		$this->assertTrue($obj->isChanged('FirstName', 2));
638
639
		/* Test when there's not field provided */
640
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain1');
641
		$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...
642
		$this->assertTrue($obj->isChanged());
643
644
		$obj->write();
645
		$this->assertFalse($obj->isChanged());
646
	}
647
648
	public function testRandomSort() {
649
		/* If we perform the same regularly sorted query twice, it should return the same results */
650
		$itemsA = DataObject::get("DataObjectTest_TeamComment", "", "ID");
651
		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...
652
653
		$itemsB = DataObject::get("DataObjectTest_TeamComment", "", "ID");
654
		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...
655
656
		/* Test when there's not field provided */
657
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain1');
658
		$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...
659
		$this->assertTrue($obj->isChanged());
660
661
		$obj->write();
662
		$this->assertFalse($obj->isChanged());
663
664
		/* If we perform the same random query twice, it shouldn't return the same results */
665
		$itemsA = DataObject::get("DataObjectTest_TeamComment", "", DB::get_conn()->random());
666
		$itemsB = DataObject::get("DataObjectTest_TeamComment", "", DB::get_conn()->random());
667
		$itemsC = DataObject::get("DataObjectTest_TeamComment", "", DB::get_conn()->random());
668
		$itemsD = DataObject::get("DataObjectTest_TeamComment", "", DB::get_conn()->random());
669
		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...
670
		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...
671
		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...
672
		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...
673
674
		// These shouldn't all be the same (run it 4 times to minimise chance of an accidental collision)
675
		// There's about a 1 in a billion chance of an accidental collision
676
		$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...
677
	}
678
679
	public function testWriteSavesToHasOneRelations() {
680
		/* DataObject::write() should save to a has_one relationship if you set a field called (relname)ID */
681
		$team = new DataObjectTest_Team();
682
		$captainID = $this->idFromFixture('DataObjectTest_Player', 'player1');
683
		$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...
684
		$team->write();
685
		$this->assertEquals($captainID,
686
			DB::query("SELECT \"CaptainID\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $team->ID")->value());
687
688
		/* After giving it a value, you should also be able to set it back to null */
689
		$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...
690
		$team->write();
691
		$this->assertEquals(0,
692
			DB::query("SELECT \"CaptainID\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $team->ID")->value());
693
694
		/* You should also be able to save a blank to it when it's first created */
695
		$team = new DataObjectTest_Team();
696
		$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...
697
		$team->write();
698
		$this->assertEquals(0,
699
			DB::query("SELECT \"CaptainID\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $team->ID")->value());
700
701
		/* Ditto for existing records without a value */
702
		$existingTeam = $this->objFromFixture('DataObjectTest_Team', 'team1');
703
		$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...
704
		$existingTeam->write();
705
		$this->assertEquals(0,
706
			DB::query("SELECT \"CaptainID\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $existingTeam->ID")->value());
707
	}
708
709
	public function testCanAccessHasOneObjectsAsMethods() {
710
		/* If you have a has_one relation 'Captain' on $obj, and you set the $obj->CaptainID = (ID), then the
711
		 * object itself should be accessible as $obj->Captain() */
712
		$team = $this->objFromFixture('DataObjectTest_Team', 'team1');
713
		$captainID = $this->idFromFixture('DataObjectTest_Player', 'captain1');
714
715
		$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...
716
		$this->assertNotNull($team->Captain());
717
		$this->assertEquals($captainID, $team->Captain()->ID);
718
719
		// Test for polymorphic has_one relations
720
		$fan = $this->objFromFixture('DataObjectTest_Fan', 'fan1');
721
		$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...
722
		$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...
723
		$this->assertNotNull($fan->Favourite());
724
		$this->assertEquals($team->ID, $fan->Favourite()->ID);
725
		$this->assertInstanceOf($team->class, $fan->Favourite());
726
	}
727
728
	public function testFieldNamesThatMatchMethodNamesWork() {
729
		/* Check that a field name that corresponds to a method on DataObject will still work */
730
		$obj = new DataObjectTest_Fixture();
731
		$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...
732
		$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...
733
		$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...
734
		$obj->write();
735
736
		$this->assertNotNull($obj->ID);
737
		$this->assertEquals('value1',
738
			DB::query("SELECT \"Data\" FROM \"DataObjectTest_Fixture\" WHERE \"ID\" = $obj->ID")->value());
739
		$this->assertEquals('value2',
740
			DB::query("SELECT \"DbObject\" FROM \"DataObjectTest_Fixture\" WHERE \"ID\" = $obj->ID")->value());
741
		$this->assertEquals('value3',
742
			DB::query("SELECT \"Duplicate\" FROM \"DataObjectTest_Fixture\" WHERE \"ID\" = $obj->ID")->value());
743
	}
744
745
	/**
746
	 * @todo Re-enable all test cases for field existence after behaviour has been fixed
747
	 */
748
	public function testFieldExistence() {
749
		$teamInstance = $this->objFromFixture('DataObjectTest_Team', 'team1');
750
		$teamSingleton = singleton('DataObjectTest_Team');
751
752
		$subteamInstance = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam1');
753
		$subteamSingleton = singleton('DataObjectTest_SubTeam');
754
755
		/* hasField() singleton checks */
756
		$this->assertTrue($teamSingleton->hasField('ID'),
757
			'hasField() finds built-in fields in singletons');
758
		$this->assertTrue($teamSingleton->hasField('Title'),
759
			'hasField() finds custom fields in singletons');
760
761
		/* hasField() instance checks */
762
		$this->assertFalse($teamInstance->hasField('NonExistingField'),
763
			'hasField() doesnt find non-existing fields in instances');
764
		$this->assertTrue($teamInstance->hasField('ID'),
765
			'hasField() finds built-in fields in instances');
766
		$this->assertTrue($teamInstance->hasField('Created'),
767
			'hasField() finds built-in fields in instances');
768
		$this->assertTrue($teamInstance->hasField('DatabaseField'),
769
			'hasField() finds custom fields in instances');
770
		//$this->assertFalse($teamInstance->hasField('SubclassDatabaseField'),
0 ignored issues
show
Unused Code Comprehensibility introduced by
82% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
771
		//'hasField() doesnt find subclass fields in parentclass instances');
772
		$this->assertTrue($teamInstance->hasField('DynamicField'),
773
			'hasField() finds dynamic getters in instances');
774
		$this->assertTrue($teamInstance->hasField('HasOneRelationshipID'),
775
			'hasField() finds foreign keys in instances');
776
		$this->assertTrue($teamInstance->hasField('ExtendedDatabaseField'),
777
			'hasField() finds extended fields in instances');
778
		$this->assertTrue($teamInstance->hasField('ExtendedHasOneRelationshipID'),
779
			'hasField() finds extended foreign keys in instances');
780
		//$this->assertTrue($teamInstance->hasField('ExtendedDynamicField'),
0 ignored issues
show
Unused Code Comprehensibility introduced by
82% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
781
		//'hasField() includes extended dynamic getters in instances');
782
783
		/* hasField() subclass checks */
784
		$this->assertTrue($subteamInstance->hasField('ID'),
785
			'hasField() finds built-in fields in subclass instances');
786
		$this->assertTrue($subteamInstance->hasField('Created'),
787
			'hasField() finds built-in fields in subclass instances');
788
		$this->assertTrue($subteamInstance->hasField('DatabaseField'),
789
			'hasField() finds custom fields in subclass instances');
790
		$this->assertTrue($subteamInstance->hasField('SubclassDatabaseField'),
791
			'hasField() finds custom fields in subclass instances');
792
		$this->assertTrue($subteamInstance->hasField('DynamicField'),
793
			'hasField() finds dynamic getters in subclass instances');
794
		$this->assertTrue($subteamInstance->hasField('HasOneRelationshipID'),
795
			'hasField() finds foreign keys in subclass instances');
796
		$this->assertTrue($subteamInstance->hasField('ExtendedDatabaseField'),
797
			'hasField() finds extended fields in subclass instances');
798
		$this->assertTrue($subteamInstance->hasField('ExtendedHasOneRelationshipID'),
799
			'hasField() finds extended foreign keys in subclass instances');
800
801
		/* hasDatabaseField() singleton checks */
802
		//$this->assertTrue($teamSingleton->hasDatabaseField('ID'),
0 ignored issues
show
Unused Code Comprehensibility introduced by
82% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
803
		//'hasDatabaseField() finds built-in fields in singletons');
804
		$this->assertTrue($teamSingleton->hasDatabaseField('Title'),
805
			'hasDatabaseField() finds custom fields in singletons');
806
807
		/* hasDatabaseField() instance checks */
808
		$this->assertFalse($teamInstance->hasDatabaseField('NonExistingField'),
809
			'hasDatabaseField() doesnt find non-existing fields in instances');
810
		//$this->assertTrue($teamInstance->hasDatabaseField('ID'),
0 ignored issues
show
Unused Code Comprehensibility introduced by
82% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
811
		//'hasDatabaseField() finds built-in fields in instances');
812
		$this->assertTrue($teamInstance->hasDatabaseField('Created'),
813
			'hasDatabaseField() finds built-in fields in instances');
814
		$this->assertTrue($teamInstance->hasDatabaseField('DatabaseField'),
815
			'hasDatabaseField() finds custom fields in instances');
816
		$this->assertFalse($teamInstance->hasDatabaseField('SubclassDatabaseField'),
817
			'hasDatabaseField() doesnt find subclass fields in parentclass instances');
818
		//$this->assertFalse($teamInstance->hasDatabaseField('DynamicField'),
0 ignored issues
show
Unused Code Comprehensibility introduced by
82% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
819
		//'hasDatabaseField() doesnt dynamic getters in instances');
820
		$this->assertTrue($teamInstance->hasDatabaseField('HasOneRelationshipID'),
821
			'hasDatabaseField() finds foreign keys in instances');
822
		$this->assertTrue($teamInstance->hasDatabaseField('ExtendedDatabaseField'),
823
			'hasDatabaseField() finds extended fields in instances');
824
		$this->assertTrue($teamInstance->hasDatabaseField('ExtendedHasOneRelationshipID'),
825
			'hasDatabaseField() finds extended foreign keys in instances');
826
		$this->assertFalse($teamInstance->hasDatabaseField('ExtendedDynamicField'),
827
			'hasDatabaseField() doesnt include extended dynamic getters in instances');
828
829
		/* hasDatabaseField() subclass checks */
830
		$this->assertTrue($subteamInstance->hasDatabaseField('DatabaseField'),
831
			'hasField() finds custom fields in subclass instances');
832
		$this->assertTrue($subteamInstance->hasDatabaseField('SubclassDatabaseField'),
833
			'hasField() finds custom fields in subclass instances');
834
835
	}
836
837
	/**
838
	 * @todo Re-enable all test cases for field inheritance aggregation after behaviour has been fixed
839
	 */
840
	public function testFieldInheritance() {
841
		$teamInstance = $this->objFromFixture('DataObjectTest_Team', 'team1');
842
		$subteamInstance = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam1');
843
844
		$this->assertEquals(
845
			array(
846
				'ID',
847
				'ClassName',
848
				'LastEdited',
849
				'Created',
850
				'Title',
851
				'DatabaseField',
852
				'ExtendedDatabaseField',
853
				'CaptainID',
854
				'FounderID',
855
				'HasOneRelationshipID',
856
				'ExtendedHasOneRelationshipID'
857
			),
858
			array_keys($teamInstance->db()),
859
			'inheritedDatabaseFields() contains all fields defined on instance: base, extended and foreign keys'
860
		);
861
862
		$this->assertEquals(
863
			array(
864
				'ID',
865
				'ClassName',
866
				'LastEdited',
867
				'Created',
868
				'Title',
869
				'DatabaseField',
870
				'ExtendedDatabaseField',
871
				'CaptainID',
872
				'FounderID',
873
				'HasOneRelationshipID',
874
				'ExtendedHasOneRelationshipID'
875
			),
876
			array_keys(DataObject::database_fields('DataObjectTest_Team', false)),
0 ignored issues
show
Unused Code introduced by
The call to DataObject::database_fields() has too many arguments starting with false.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
877
			'databaseFields() contains only fields defined on instance, including base, extended and foreign keys'
878
		);
879
880
		$this->assertEquals(
881
			array(
882
				'ID',
883
				'ClassName',
884
				'LastEdited',
885
				'Created',
886
				'Title',
887
				'DatabaseField',
888
				'ExtendedDatabaseField',
889
				'CaptainID',
890
				'FounderID',
891
				'HasOneRelationshipID',
892
				'ExtendedHasOneRelationshipID',
893
				'SubclassDatabaseField',
894
				'ParentTeamID',
895
			),
896
			array_keys($subteamInstance->db()),
897
			'inheritedDatabaseFields() on subclass contains all fields, including base, extended  and foreign keys'
898
		);
899
900
		$this->assertEquals(
901
			array(
902
				'ID',
903
				'SubclassDatabaseField',
904
				'ParentTeamID',
905
			),
906
			array_keys(DataObject::database_fields('DataObjectTest_SubTeam')),
907
			'databaseFields() on subclass contains only fields defined on instance'
908
		);
909
	}
910
911
	public function testSearchableFields() {
912
		$player = $this->objFromFixture('DataObjectTest_Player', 'captain1');
913
		$fields = $player->searchableFields();
914
		$this->assertArrayHasKey(
915
			'IsRetired',
916
			$fields,
917
			'Fields defined by $searchable_fields static are correctly detected'
918
		);
919
		$this->assertArrayHasKey(
920
			'ShirtNumber',
921
			$fields,
922
			'Fields defined by $searchable_fields static are correctly detected'
923
		);
924
925
		$team = $this->objFromFixture('DataObjectTest_Team', 'team1');
926
		$fields = $team->searchableFields();
927
		$this->assertArrayHasKey(
928
			'Title',
929
			$fields,
930
			'Fields can be inherited from the $summary_fields static, including methods called on fields'
931
		);
932
		$this->assertArrayHasKey(
933
			'Captain.ShirtNumber',
934
			$fields,
935
			'Fields on related objects can be inherited from the $summary_fields static'
936
		);
937
		$this->assertArrayHasKey(
938
			'Captain.FavouriteTeam.Title',
939
			$fields,
940
			'Fields on related objects can be inherited from the $summary_fields static'
941
		);
942
943
		$testObj = new DataObjectTest_Fixture();
944
		$fields = $testObj->searchableFields();
945
		$this->assertEmpty($fields);
946
	}
947
948
	public function testSummaryFieldsCustomLabels() {
949
		$team = $this->objFromFixture('DataObjectTest_Team', 'team1');
950
		$summaryFields = $team->summaryFields();
951
952
		$this->assertEquals(
953
			'Custom Title',
954
			$summaryFields['Title'],
955
			'Custom title is preserved'
956
		);
957
958
		$this->assertEquals(
959
			'Captain\'s shirt number',
960
			$summaryFields['Captain.ShirtNumber'],
961
			'Custom title on relation is preserved'
962
		);
963
	}
964
965
	public function testDataObjectUpdate() {
966
		/* update() calls can use the dot syntax to reference has_one relations and other methods that return
967
		 * objects */
968
		$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
969
		$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...
970
971
		$team1->update(array(
972
			'DatabaseField' => 'Something',
973
			'Captain.FirstName' => 'Jim',
974
			'Captain.Email' => '[email protected]',
975
			'Captain.FavouriteTeam.Title' => 'New and improved team 1',
976
		));
977
978
		/* Test the simple case of updating fields on the object itself */
979
		$this->assertEquals('Something', $team1->DatabaseField);
980
981
		/* Setting Captain.Email and Captain.FirstName will have updated DataObjectTest_Captain.captain1 in
982
		 * the database.  Although update() doesn't usually write, it does write related records automatically. */
983
		$captain1 = $this->objFromFixture('DataObjectTest_Player', 'captain1');
984
		$this->assertEquals('Jim', $captain1->FirstName);
985
		$this->assertEquals('[email protected]', $captain1->Email);
986
987
		/* Jim's favourite team is team 1; we need to reload the object to the the change that setting Captain.
988
		 * FavouriteTeam.Title made */
989
		$reloadedTeam1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
990
		$this->assertEquals('New and improved team 1', $reloadedTeam1->Title);
991
	}
992
993
	public function testDataObjectUpdateNew() {
994
		/* update() calls can use the dot syntax to reference has_one relations and other methods that return
995
		 * objects */
996
		$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
997
		$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...
998
999
		$team1->update(array(
1000
			'Captain.FirstName' => 'Jim',
1001
			'Captain.FavouriteTeam.Title' => 'New and improved team 1',
1002
		));
1003
		/* Test that the captain ID has been updated */
1004
		$this->assertGreaterThan(0, $team1->CaptainID);
1005
1006
		/* Fetch the newly created captain */
1007
		$captain1 = DataObjectTest_Player::get()->byID($team1->CaptainID);
1008
		$this->assertEquals('Jim', $captain1->FirstName);
1009
1010
		/* Grab the favourite team and make sure it has the correct values */
1011
		$reloadedTeam1 = $captain1->FavouriteTeam();
1012
		$this->assertEquals($reloadedTeam1->ID, $captain1->FavouriteTeamID);
1013
		$this->assertEquals('New and improved team 1', $reloadedTeam1->Title);
1014
	}
1015
1016
	public function testWritingInvalidDataObjectThrowsException() {
1017
		$validatedObject = new DataObjectTest_ValidatedObject();
1018
1019
		$this->setExpectedException('ValidationException');
1020
		$validatedObject->write();
1021
	}
1022
1023
	public function testWritingValidDataObjectDoesntThrowException() {
1024
		$validatedObject = new DataObjectTest_ValidatedObject();
1025
		$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...
1026
1027
		$validatedObject->write();
1028
		$this->assertTrue($validatedObject->isInDB(), "Validated object was not saved to database");
1029
	}
1030
1031
	public function testSubclassCreation() {
1032
		/* Creating a new object of a subclass should set the ClassName field correctly */
1033
		$obj = new DataObjectTest_SubTeam();
1034
		$obj->write();
1035
		$this->assertEquals("DataObjectTest_SubTeam",
1036
			DB::query("SELECT \"ClassName\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $obj->ID")->value());
1037
	}
1038
1039
	public function testForceInsert() {
1040
		/* If you set an ID on an object and pass forceInsert = true, then the object should be correctly created */
1041
		$conn = DB::get_conn();
1042
		if(method_exists($conn, 'allowPrimaryKeyEditing')) $conn->allowPrimaryKeyEditing('DataObjectTest_Team', true);
1043
		$obj = new DataObjectTest_SubTeam();
1044
		$obj->ID = 1001;
1045
		$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...
1046
		$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...
1047
		$obj->write(false, true);
1048
		if(method_exists($conn, 'allowPrimaryKeyEditing')) $conn->allowPrimaryKeyEditing('DataObjectTest_Team', false);
1049
1050
		$this->assertEquals("DataObjectTest_SubTeam",
1051
			DB::query("SELECT \"ClassName\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $obj->ID")->value());
1052
1053
		/* Check that it actually saves to the database with the correct ID */
1054
		$this->assertEquals("1001", DB::query(
1055
			"SELECT \"ID\" FROM \"DataObjectTest_SubTeam\" WHERE \"SubclassDatabaseField\" = 'asdfasdf'")->value());
1056
		$this->assertEquals("1001",
1057
			DB::query("SELECT \"ID\" FROM \"DataObjectTest_Team\" WHERE \"Title\" = 'asdfasdf'")->value());
1058
	}
1059
1060
	public function TestHasOwnTable() {
1061
		/* Test DataObject::has_own_table() returns true if the object has $has_one or $db values */
1062
		$this->assertTrue(DataObject::has_own_table("DataObjectTest_Player"));
1063
		$this->assertTrue(DataObject::has_own_table("DataObjectTest_Team"));
1064
		$this->assertTrue(DataObject::has_own_table("DataObjectTest_Fixture"));
1065
1066
		/* Root DataObject that always have a table, even if they lack both $db and $has_one */
1067
		$this->assertTrue(DataObject::has_own_table("DataObjectTest_FieldlessTable"));
1068
1069
		/* Subclasses without $db or $has_one don't have a table */
1070
		$this->assertFalse(DataObject::has_own_table("DataObjectTest_FieldlessSubTable"));
1071
1072
		/* Return false if you don't pass it a subclass of DataObject */
1073
		$this->assertFalse(DataObject::has_own_table("DataObject"));
1074
		$this->assertFalse(DataObject::has_own_table("ViewableData"));
1075
		$this->assertFalse(DataObject::has_own_table("ThisIsntADataObject"));
1076
	}
1077
1078
	public function testMerge() {
1079
		// test right merge of subclasses
1080
		$left = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam1');
1081
		$right = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam2_with_player_relation');
1082
		$leftOrigID = $left->ID;
1083
		$left->merge($right, 'right', false, false);
1084
		$this->assertEquals(
1085
			$left->Title,
1086
			'Subteam 2',
1087
			'merge() with "right" priority overwrites fields with existing values on subclasses'
1088
		);
1089
		$this->assertEquals(
1090
			$left->ID,
1091
			$leftOrigID,
1092
			'merge() with "right" priority doesnt overwrite database ID'
1093
		);
1094
1095
		// test overwriteWithEmpty flag on existing left values
1096
		$left = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam2_with_player_relation');
1097
		$right = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam3_with_empty_fields');
1098
		$left->merge($right, 'right', false, true);
1099
		$this->assertEquals(
1100
			$left->Title,
1101
			'Subteam 3',
1102
			'merge() with $overwriteWithEmpty overwrites non-empty fields on left object'
1103
		);
1104
1105
		// test overwriteWithEmpty flag on empty left values
1106
		$left = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam1');
1107
		// $SubclassDatabaseField is empty on here
1108
		$right = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam2_with_player_relation');
1109
		$left->merge($right, 'right', false, true);
1110
		$this->assertEquals(
1111
			$left->SubclassDatabaseField,
1112
			NULL,
1113
			'merge() with $overwriteWithEmpty overwrites empty fields on left object'
1114
		);
1115
1116
		// @todo test "left" priority flag
1117
		// @todo test includeRelations flag
1118
		// @todo test includeRelations in combination with overwriteWithEmpty
1119
		// @todo test has_one relations
1120
		// @todo test has_many and many_many relations
1121
	}
1122
1123
	public function testPopulateDefaults() {
1124
		$obj = new DataObjectTest_Fixture();
1125
		$this->assertEquals(
1126
			$obj->MyFieldWithDefault,
1127
			'Default Value',
1128
			'Defaults are populated for in-memory object from $defaults array'
1129
		);
1130
1131
		$this->assertEquals(
1132
			$obj->MyFieldWithAltDefault,
1133
			'Default Value',
1134
			'Defaults are populated from overloaded populateDefaults() method'
1135
		);
1136
	}
1137
1138
	protected function makeAccessible($object, $method) {
1139
		$reflectionMethod = new ReflectionMethod($object, $method);
1140
		$reflectionMethod->setAccessible(true);
1141
		return $reflectionMethod;
1142
	}
1143
1144
	public function testValidateModelDefinitionsFailsWithArray() {
1145
		Config::nest();
1146
1147
		$object = new DataObjectTest_Team;
1148
		$method = $this->makeAccessible($object, 'validateModelDefinitions');
1149
1150
		Config::inst()->update('DataObjectTest_Team', 'has_one', array('NotValid' => array('NoArraysAllowed')));
1151
		$this->setExpectedException('LogicException');
1152
1153
		try {
1154
			$method->invoke($object);
1155
		} catch(Exception $e) {
1156
			Config::unnest(); // Catch the exception so we can unnest config before failing the test
1157
			throw $e;
1158
		}
1159
	}
1160
1161
	public function testValidateModelDefinitionsFailsWithIntKey() {
1162
		Config::nest();
1163
1164
		$object = new DataObjectTest_Team;
1165
		$method = $this->makeAccessible($object, 'validateModelDefinitions');
1166
1167
		Config::inst()->update('DataObjectTest_Team', 'has_many', array(12 => 'DataObjectTest_Player'));
1168
		$this->setExpectedException('LogicException');
1169
1170
		try {
1171
			$method->invoke($object);
1172
		} catch(Exception $e) {
1173
			Config::unnest(); // Catch the exception so we can unnest config before failing the test
1174
			throw $e;
1175
		}
1176
	}
1177
1178
	public function testValidateModelDefinitionsFailsWithIntValue() {
1179
		Config::nest();
1180
1181
		$object = new DataObjectTest_Team;
1182
		$method = $this->makeAccessible($object, 'validateModelDefinitions');
1183
1184
		Config::inst()->update('DataObjectTest_Team', 'many_many', array('Players' => 12));
1185
		$this->setExpectedException('LogicException');
1186
1187
		try {
1188
			$method->invoke($object);
1189
		} catch(Exception $e) {
1190
			Config::unnest(); // Catch the exception so we can unnest config before failing the test
1191
			throw $e;
1192
		}
1193
	}
1194
1195
	/**
1196
	 * many_many_extraFields is allowed to have an array value, so shouldn't throw an exception
1197
	 */
1198
	public function testValidateModelDefinitionsPassesWithExtraFields() {
1199
		Config::nest();
1200
1201
		$object = new DataObjectTest_Team;
1202
		$method = $this->makeAccessible($object, 'validateModelDefinitions');
1203
1204
		Config::inst()->update('DataObjectTest_Team', 'many_many_extraFields',
1205
			array('Relations' => array('Price' => 'Int')));
1206
1207
		try {
1208
			$method->invoke($object);
1209
		} catch(Exception $e) {
1210
			Config::unnest();
1211
			$this->fail('Exception should not be thrown');
1212
			throw $e;
1213
		}
1214
1215
		Config::unnest();
1216
	}
1217
1218
	public function testNewClassInstance() {
1219
		$dataObject = $this->objFromFixture('DataObjectTest_Team', 'team1');
1220
		$changedDO = $dataObject->newClassInstance('DataObjectTest_SubTeam');
1221
		$changedFields = $changedDO->getChangedFields();
1222
1223
		// Don't write the record, it will reset changed fields
1224
		$this->assertInstanceOf('DataObjectTest_SubTeam', $changedDO);
1225
		$this->assertEquals($changedDO->ClassName, 'DataObjectTest_SubTeam');
1226
		$this->assertContains('ClassName', array_keys($changedFields));
1227
		$this->assertEquals($changedFields['ClassName']['before'], 'DataObjectTest_Team');
1228
		$this->assertEquals($changedFields['ClassName']['after'], 'DataObjectTest_SubTeam');
1229
1230
		$changedDO->write();
1231
1232
		$this->assertInstanceOf('DataObjectTest_SubTeam', $changedDO);
1233
		$this->assertEquals($changedDO->ClassName, 'DataObjectTest_SubTeam');
1234
	}
1235
1236
	public function testMultipleManyManyWithSameClass() {
1237
		$team = $this->objFromFixture('DataObjectTest_Team', 'team1');
1238
		$company2 = $this->objFromFixture('DataObjectTest_EquipmentCompany', 'equipmentcompany2');
1239
		$sponsors = $team->Sponsors();
1240
		$equipmentSuppliers = $team->EquipmentSuppliers();
1241
1242
		// Check that DataObject::many_many() works as expected
1243
		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...
1244
		$this->assertEquals('DataObjectTest_Team', $class,
1245
			'DataObject::many_many() didn\'t find the correct base class');
1246
		$this->assertEquals('DataObjectTest_EquipmentCompany', $targetClass,
1247
			'DataObject::many_many() didn\'t find the correct target class for the relation');
1248
		$this->assertEquals('DataObjectTest_EquipmentCompany_SponsoredTeams', $joinTable,
1249
			'DataObject::many_many() didn\'t find the correct relation table');
1250
1251
		// Check that ManyManyList still works
1252
		$this->assertEquals(2, $sponsors->count(), 'Rows are missing from relation');
1253
		$this->assertEquals(1, $equipmentSuppliers->count(), 'Rows are missing from relation');
1254
1255
		// Check everything works when no relation is present
1256
		$teamWithoutSponsor = $this->objFromFixture('DataObjectTest_Team', 'team3');
1257
		$this->assertInstanceOf('ManyManyList', $teamWithoutSponsor->Sponsors());
1258
		$this->assertEquals(0, $teamWithoutSponsor->Sponsors()->count());
1259
1260
		// Test that belongs_many_many can be infered from with getNonReciprocalComponent
1261
		$this->assertDOSEquals(
1262
			[
1263
				['Name' => 'Company corp'],
1264
				['Name' => 'Team co.'],
1265
			],
1266
			$team->inferReciprocalComponent('DataObjectTest_EquipmentCompany', 'SponsoredTeams')
1267
		);
1268
1269
		// Test that many_many can be infered from getNonReciprocalComponent
1270
		$this->assertDOSEquals(
1271
			[
1272
				['Title' => 'Team 1'],
1273
				['Title' => 'Team 2'],
1274
				['Title' => 'Subteam 1'],
1275
			],
1276
			$company2->inferReciprocalComponent('DataObjectTest_Team', 'Sponsors')
1277
		);
1278
1279
		// Check many_many_extraFields still works
1280
		$equipmentCompany = $this->objFromFixture('DataObjectTest_EquipmentCompany', 'equipmentcompany1');
1281
		$equipmentCompany->SponsoredTeams()->add($teamWithoutSponsor, array('SponsorFee' => 1000));
1282
		$sponsoredTeams = $equipmentCompany->SponsoredTeams();
1283
		$this->assertEquals(1000, $sponsoredTeams->byID($teamWithoutSponsor->ID)->SponsorFee,
1284
			'Data from many_many_extraFields was not stored/extracted correctly');
1285
1286
		// Check subclasses correctly inherit multiple many_manys
1287
		$subTeam = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam1');
1288
		$this->assertEquals(2, $subTeam->Sponsors()->count(),
1289
			'Child class did not inherit multiple many_manys');
1290
		$this->assertEquals(1, $subTeam->EquipmentSuppliers()->count(),
1291
			'Child class did not inherit multiple many_manys');
1292
		// Team 2 has one EquipmentCompany sponsor and one SubEquipmentCompany
1293
		$team2 = $this->objFromFixture('DataObjectTest_Team', 'team2');
1294
		$this->assertEquals(2, $team2->Sponsors()->count(),
1295
			'Child class did not inherit multiple belongs_many_manys');
1296
1297
		// Check many_many_extraFields also works from the belongs_many_many side
1298
		$sponsors = $team2->Sponsors();
1299
		$sponsors->add($equipmentCompany, array('SponsorFee' => 750));
1300
		$this->assertEquals(750, $sponsors->byID($equipmentCompany->ID)->SponsorFee,
1301
			'Data from many_many_extraFields was not stored/extracted correctly');
1302
1303
		$subEquipmentCompany = $this->objFromFixture('DataObjectTest_SubEquipmentCompany', 'subequipmentcompany1');
1304
		$subTeam->Sponsors()->add($subEquipmentCompany, array('SponsorFee' => 1200));
1305
		$this->assertEquals(1200, $subTeam->Sponsors()->byID($subEquipmentCompany->ID)->SponsorFee,
1306
			'Data from inherited many_many_extraFields was not stored/extracted correctly');
1307
1308
	}
1309
1310
	public function testManyManyExtraFields() {
1311
		$player = $this->objFromFixture('DataObjectTest_Player', 'player1');
1312
		$team = $this->objFromFixture('DataObjectTest_Team', 'team1');
1313
1314
		// Get all extra fields
1315
		$teamExtraFields = $team->manyManyExtraFields();
1316
		$this->assertEquals(array(
1317
			'Players' => array('Position' => 'Varchar(100)')
1318
		), $teamExtraFields);
1319
1320
		// Ensure fields from parent classes are included
1321
		$subTeam = singleton('DataObjectTest_SubTeam');
1322
		$teamExtraFields = $subTeam->manyManyExtraFields();
1323
		$this->assertEquals(array(
1324
			'Players' => array('Position' => 'Varchar(100)'),
1325
			'FormerPlayers' => array('Position' => 'Varchar(100)')
1326
		), $teamExtraFields);
1327
1328
		// Extra fields are immediately available on the Team class (defined in $many_many_extraFields)
1329
		$teamExtraFields = $team->manyManyExtraFieldsForComponent('Players');
1330
		$this->assertEquals($teamExtraFields, array(
1331
			'Position' => 'Varchar(100)'
1332
		));
1333
1334
		// We'll have to go through the relation to get the extra fields on Player
1335
		$playerExtraFields = $player->manyManyExtraFieldsForComponent('Teams');
1336
		$this->assertEquals($playerExtraFields, array(
1337
			'Position' => 'Varchar(100)'
1338
		));
1339
1340
		// Iterate through a many-many relationship and confirm that extra fields are included
1341
		$newTeam = new DataObjectTest_Team();
1342
		$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...
1343
		$newTeam->write();
1344
		$newTeamID = $newTeam->ID;
1345
1346
		$newPlayer = new DataObjectTest_Player();
1347
		$newPlayer->FirstName = "Sam";
1348
		$newPlayer->Surname = "Minnee";
1349
		$newPlayer->write();
1350
1351
		// The idea of Sam as a prop is essentially humourous.
1352
		$newTeam->Players()->add($newPlayer, array("Position" => "Prop"));
1353
1354
		// Requery and uncache everything
1355
		$newTeam->flushCache();
1356
		$newTeam = DataObject::get_by_id('DataObjectTest_Team', $newTeamID);
1357
1358
		// Check that the Position many_many_extraField is extracted.
1359
		$player = $newTeam->Players()->First();
1360
		$this->assertEquals('Sam', $player->FirstName);
1361
		$this->assertEquals("Prop", $player->Position);
1362
1363
		// Check that ordering a many-many relation by an aggregate column doesn't fail
1364
		$player = $this->objFromFixture('DataObjectTest_Player', 'player2');
1365
		$player->Teams()->sort("count(DISTINCT \"DataObjectTest_Team_Players\".\"DataObjectTest_PlayerID\") DESC");
1366
	}
1367
1368
	/**
1369
	 * Check that the queries generated for many-many relation queries can have unlimitedRowCount
1370
	 * called on them.
1371
	 */
1372
	public function testManyManyUnlimitedRowCount() {
1373
		$player = $this->objFromFixture('DataObjectTest_Player', 'player2');
1374
		// TODO: What's going on here?
1375
		$this->assertEquals(2, $player->Teams()->dataQuery()->query()->unlimitedRowCount());
1376
	}
1377
1378
	/**
1379
	 * Tests that singular_name() generates sensible defaults.
1380
	 */
1381
	public function testSingularName() {
1382
		$assertions = array(
1383
			'DataObjectTest_Player'       => 'Data Object Test Player',
1384
			'DataObjectTest_Team'         => 'Data Object Test Team',
1385
			'DataObjectTest_Fixture'      => 'Data Object Test Fixture'
1386
		);
1387
1388
		foreach($assertions as $class => $expectedSingularName) {
1389
			$this->assertEquals(
1390
				$expectedSingularName,
1391
				singleton($class)->singular_name(),
1392
				"Assert that the singular_name for '$class' is correct."
1393
			);
1394
		}
1395
	}
1396
1397
	/**
1398
	 * Tests that plural_name() generates sensible defaults.
1399
	 */
1400
	public function testPluralName() {
1401
		$assertions = array(
1402
			'DataObjectTest_Player'       => 'Data Object Test Players',
1403
			'DataObjectTest_Team'         => 'Data Object Test Teams',
1404
			'DataObjectTest_Fixture'      => 'Data Object Test Fixtures',
1405
			'DataObjectTest_Play'         => 'Data Object Test Plays',
1406
			'DataObjectTest_Bogey'        => 'Data Object Test Bogeys',
1407
			'DataObjectTest_Ploy'         => 'Data Object Test Ploys',
1408
		);
1409
1410
		foreach($assertions as $class => $expectedPluralName) {
1411
			$this->assertEquals(
1412
				$expectedPluralName,
1413
				singleton($class)->plural_name(),
1414
				"Assert that the plural_name for '$class' is correct."
1415
			);
1416
		}
1417
	}
1418
1419
	public function testHasDatabaseField() {
1420
		$team = singleton('DataObjectTest_Team');
1421
		$subteam = singleton('DataObjectTest_SubTeam');
1422
1423
		$this->assertTrue(
1424
			$team->hasDatabaseField('Title'),
1425
			"hasOwnDatabaseField() works with \$db fields"
1426
		);
1427
		$this->assertTrue(
1428
			$team->hasDatabaseField('CaptainID'),
1429
			"hasOwnDatabaseField() works with \$has_one fields"
1430
		);
1431
		$this->assertFalse(
1432
			$team->hasDatabaseField('NonExistentField'),
1433
			"hasOwnDatabaseField() doesn't detect non-existend fields"
1434
		);
1435
		$this->assertTrue(
1436
			$team->hasDatabaseField('ExtendedDatabaseField'),
1437
			"hasOwnDatabaseField() works with extended fields"
1438
		);
1439
		$this->assertFalse(
1440
			$team->hasDatabaseField('SubclassDatabaseField'),
1441
			"hasOwnDatabaseField() doesn't pick up fields in subclasses on parent class"
1442
		);
1443
1444
		$this->assertTrue(
1445
			$subteam->hasDatabaseField('SubclassDatabaseField'),
1446
			"hasOwnDatabaseField() picks up fields in subclasses"
1447
		);
1448
1449
	}
1450
1451
	public function testFieldTypes() {
1452
		$obj = new DataObjectTest_Fixture();
1453
		$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...
1454
		$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...
1455
		$obj->write();
1456
		$obj->flushCache();
1457
1458
		$obj = DataObject::get_by_id('DataObjectTest_Fixture', $obj->ID);
1459
		$this->assertEquals('1988-01-02', $obj->DateField);
1460
		$this->assertEquals('1988-03-04 06:30:00', $obj->DatetimeField);
1461
	}
1462
1463
	public function testTwoSubclassesWithTheSameFieldNameWork() {
1464
		// Create two objects of different subclasses, setting the values of fields that are
1465
		// defined separately in each subclass
1466
		$obj1 = new DataObjectTest_SubTeam();
1467
		$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...
1468
		$obj2 = new OtherSubclassWithSameField();
1469
		$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...
1470
1471
		// Write them to the database
1472
		$obj1->write();
1473
		$obj2->write();
1474
1475
		// Check that the values of those fields are properly read from the database
1476
		$values = DataObject::get("DataObjectTest_Team", "\"DataObjectTest_Team\".\"ID\" IN
1477
			($obj1->ID, $obj2->ID)")->column("SubclassDatabaseField");
1478
		$this->assertEquals(array_intersect($values, array('obj1', 'obj2')), $values);
1479
	}
1480
1481
	public function testClassNameSetForNewObjects() {
1482
		$d = new DataObjectTest_Player();
1483
		$this->assertEquals('DataObjectTest_Player', $d->ClassName);
1484
	}
1485
1486
	public function testHasValue() {
1487
		$team = new DataObjectTest_Team();
1488
		$this->assertFalse($team->hasValue('Title', null, false));
1489
		$this->assertFalse($team->hasValue('DatabaseField', null, false));
1490
1491
		$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...
1492
		$this->assertTrue($team->hasValue('Title', null, false));
1493
		$this->assertFalse($team->hasValue('DatabaseField', null, false));
1494
1495
		$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...
1496
		$this->assertTrue($team->hasValue('Title', null, false));
1497
		$this->assertFalse (
1498
			$team->hasValue('DatabaseField', null, false),
1499
			'Test that a blank paragraph on a HTML field is not a valid value.'
1500
		);
1501
1502
		$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...
1503
		$this->assertTrue (
1504
			$team->hasValue('Title', null, false),
1505
			'Test that an empty paragraph is a value for non-HTML fields.'
1506
		);
1507
1508
		$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...
1509
		$this->assertTrue($team->hasValue('Title', null, false));
1510
		$this->assertTrue($team->hasValue('DatabaseField', null, false));
1511
	}
1512
1513
	public function testHasMany() {
1514
		$company = new DataObjectTest_Company();
1515
1516
		$this->assertEquals (
1517
			array (
1518
				'CurrentStaff'     => 'DataObjectTest_Staff',
1519
				'PreviousStaff'    => 'DataObjectTest_Staff'
1520
			),
1521
			$company->hasMany(),
1522
			'has_many strips field name data by default.'
1523
		);
1524
1525
		$this->assertEquals (
1526
			'DataObjectTest_Staff',
1527
			$company->hasManyComponent('CurrentStaff'),
1528
			'has_many strips field name data by default on single relationships.'
1529
		);
1530
1531
		$this->assertEquals (
1532
			array (
1533
				'CurrentStaff'     => 'DataObjectTest_Staff.CurrentCompany',
1534
				'PreviousStaff'    => 'DataObjectTest_Staff.PreviousCompany'
1535
			),
1536
			$company->hasMany(null, false),
1537
			'has_many returns field name data when $classOnly is false.'
1538
		);
1539
1540
		$this->assertEquals (
1541
			'DataObjectTest_Staff.CurrentCompany',
1542
			$company->hasManyComponent('CurrentStaff', false),
1543
			'has_many returns field name data on single records when $classOnly is false.'
1544
		);
1545
	}
1546
1547
	public function testGetRemoteJoinField() {
1548
		$company = new DataObjectTest_Company();
1549
1550
		$staffJoinField = $company->getRemoteJoinField('CurrentStaff', 'has_many', $polymorphic);
1551
		$this->assertEquals('CurrentCompanyID', $staffJoinField);
1552
		$this->assertFalse($polymorphic, 'DataObjectTest_Company->CurrentStaff is not polymorphic');
1553
		$previousStaffJoinField = $company->getRemoteJoinField('PreviousStaff', 'has_many', $polymorphic);
1554
		$this->assertEquals('PreviousCompanyID', $previousStaffJoinField);
1555
		$this->assertFalse($polymorphic, 'DataObjectTest_Company->PreviousStaff is not polymorphic');
1556
1557
		$ceo = new DataObjectTest_CEO();
1558
1559
		$this->assertEquals('CEOID', $ceo->getRemoteJoinField('Company', 'belongs_to', $polymorphic));
1560
		$this->assertFalse($polymorphic, 'DataObjectTest_CEO->Company is not polymorphic');
1561
		$this->assertEquals('PreviousCEOID', $ceo->getRemoteJoinField('PreviousCompany', 'belongs_to', $polymorphic));
1562
		$this->assertFalse($polymorphic, 'DataObjectTest_CEO->PreviousCompany is not polymorphic');
1563
1564
		$team = new DataObjectTest_Team();
1565
1566
		$this->assertEquals('Favourite', $team->getRemoteJoinField('Fans', 'has_many', $polymorphic));
1567
		$this->assertTrue($polymorphic, 'DataObjectTest_Team->Fans is polymorphic');
1568
		$this->assertEquals('TeamID', $team->getRemoteJoinField('Comments', 'has_many', $polymorphic));
1569
		$this->assertFalse($polymorphic, 'DataObjectTest_Team->Comments is not polymorphic');
1570
	}
1571
1572
	public function testBelongsTo() {
1573
		$company = new DataObjectTest_Company();
1574
		$ceo     = new DataObjectTest_CEO();
1575
1576
		$company->Name = 'New Company';
0 ignored issues
show
Documentation introduced by
The property Name 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...
1577
		$company->write();
1578
		$ceo->write();
1579
1580
		// Test belongs_to assignment
1581
		$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...
1582
		$company->write();
1583
1584
		$this->assertEquals($company->ID, $ceo->Company()->ID, 'belongs_to returns the right results.');
1585
1586
		// Test belongs_to can be infered via getNonReciprocalComponent
1587
		// Note: Will be returned as has_many since the belongs_to is ignored.
1588
		$this->assertDOSEquals(
1589
			[['Name' => 'New Company']],
1590
			$ceo->inferReciprocalComponent('DataObjectTest_Company', 'CEO')
1591
		);
1592
1593
		// Test has_one to a belongs_to can be infered via getNonReciprocalComponent
1594
		$this->assertEquals(
1595
			$ceo->ID,
1596
			$company->inferReciprocalComponent('DataObjectTest_CEO', 'Company')->ID
1597
		);
1598
1599
		// Test automatic creation of class where no assigment exists
1600
		$ceo = new DataObjectTest_CEO();
1601
		$ceo->write();
1602
1603
		$this->assertTrue (
1604
			$ceo->Company() instanceof DataObjectTest_Company,
1605
			'DataObjects across belongs_to relations are automatically created.'
1606
		);
1607
		$this->assertEquals($ceo->ID, $ceo->Company()->CEOID, 'Remote IDs are automatically set.');
1608
1609
		// Write object with components
1610
		$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...
1611
		$ceo->write(false, false, false, true);
1612
		$this->assertTrue($ceo->Company()->isInDB(), 'write() writes belongs_to components to the database.');
1613
1614
		$newCEO = DataObject::get_by_id('DataObjectTest_CEO', $ceo->ID);
1615
		$this->assertEquals (
1616
			$ceo->Company()->ID, $newCEO->Company()->ID, 'belongs_to can be retrieved from the database.'
1617
		);
1618
	}
1619
1620
	public function testBelongsToPolymorphic() {
1621
		$company = new DataObjectTest_Company();
1622
		$ceo     = new DataObjectTest_CEO();
1623
1624
		$company->write();
1625
		$ceo->write();
1626
1627
		// Test belongs_to assignment
1628
		$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...
1629
		$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...
1630
		$company->write();
1631
1632
		$this->assertEquals($company->ID, $ceo->CompanyOwned()->ID, 'belongs_to returns the right results.');
1633
		$this->assertEquals($company->class, $ceo->CompanyOwned()->class, 'belongs_to returns the right results.');
1634
1635
		// Test automatic creation of class where no assigment exists
1636
		$ceo = new DataObjectTest_CEO();
1637
		$ceo->write();
1638
1639
		$this->assertTrue (
1640
			$ceo->CompanyOwned() instanceof DataObjectTest_Company,
1641
			'DataObjects across polymorphic belongs_to relations are automatically created.'
1642
		);
1643
		$this->assertEquals($ceo->ID, $ceo->CompanyOwned()->OwnerID, 'Remote IDs are automatically set.');
1644
		$this->assertInstanceOf($ceo->CompanyOwned()->OwnerClass, $ceo, 'Remote class is automatically  set');
1645
1646
		// Write object with components
1647
		$ceo->write(false, false, false, true);
1648
		$this->assertTrue($ceo->CompanyOwned()->isInDB(), 'write() writes belongs_to components to the database.');
1649
1650
		$newCEO = DataObject::get_by_id('DataObjectTest_CEO', $ceo->ID);
1651
		$this->assertEquals (
1652
			$ceo->CompanyOwned()->ID,
1653
			$newCEO->CompanyOwned()->ID,
1654
			'polymorphic belongs_to can be retrieved from the database.'
1655
		);
1656
	}
1657
1658
	/**
1659
	 * @expectedException LogicException
1660
	 */
1661
	public function testInvalidate() {
1662
		$do = new DataObjectTest_Fixture();
1663
		$do->write();
1664
1665
		$do->delete();
1666
1667
		$do->delete(); // Prohibit invalid object manipulation
1668
		$do->write();
1669
		$do->duplicate();
1670
	}
1671
1672
	public function testToMap() {
1673
		$obj = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam1');
1674
1675
		$map = $obj->toMap();
1676
1677
		$this->assertArrayHasKey('ID', $map, 'Contains base fields');
1678
		$this->assertArrayHasKey('Title', $map, 'Contains fields from parent class');
1679
		$this->assertArrayHasKey('SubclassDatabaseField', $map, 'Contains fields from concrete class');
1680
1681
		$this->assertEquals($obj->ID, $map['ID'],
1682
			'Contains values from base fields');
1683
		$this->assertEquals($obj->Title, $map['Title'],
1684
			'Contains values from parent class fields');
1685
		$this->assertEquals($obj->SubclassDatabaseField, $map['SubclassDatabaseField'],
1686
			'Contains values from concrete class fields');
1687
1688
		$newObj = new DataObjectTest_SubTeam();
1689
		$this->assertArrayHasKey('Title', $map, 'Contains null fields');
1690
	}
1691
1692
	public function testIsEmpty() {
1693
		$objEmpty = new DataObjectTest_Team();
1694
		$this->assertTrue($objEmpty->isEmpty(), 'New instance without populated defaults is empty');
1695
1696
		$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...
1697
		$this->assertFalse($objEmpty->isEmpty(), 'Zero value in attribute considered non-empty');
1698
	}
1699
1700
	public function testRelField() {
1701
		$captain = $this->objFromFixture('DataObjectTest_Player', 'captain1');
1702
		// Test traversal of a single has_one
1703
		$this->assertEquals("Team 1", $captain->relField('FavouriteTeam.Title'));
1704
		// Test direct field access
1705
		$this->assertEquals("Captain", $captain->relField('FirstName'));
1706
1707
		$player = $this->objFromFixture('DataObjectTest_Player', 'player2');
1708
		// Test that we can traverse more than once, and that arbitrary methods are okay
1709
		$this->assertEquals("Team 1", $player->relField('Teams.First.Title'));
1710
1711
		$newPlayer = new DataObjectTest_Player();
1712
		$this->assertNull($newPlayer->relField('Teams.First.Title'));
1713
1714
		// Test that relField works on db field manipulations
1715
		$comment = $this->objFromFixture('DataObjectTest_TeamComment', 'comment3');
1716
		$this->assertEquals("PHIL IS A UNIQUE GUY, AND COMMENTS ON TEAM2" , $comment->relField('Comment.UpperCase'));
1717
	}
1718
1719
	public function testRelObject() {
1720
		$captain = $this->objFromFixture('DataObjectTest_Player', 'captain1');
1721
1722
		// Test traversal of a single has_one
1723
		$this->assertInstanceOf('SilverStripe\Model\FieldType\DBVarchar', $captain->relObject('FavouriteTeam.Title'));
1724
		$this->assertEquals("Team 1", $captain->relObject('FavouriteTeam.Title')->getValue());
1725
1726
		// Test direct field access
1727
		$this->assertInstanceOf('SilverStripe\Model\FieldType\DBBoolean', $captain->relObject('IsRetired'));
1728
		$this->assertEquals(1, $captain->relObject('IsRetired')->getValue());
1729
1730
		$player = $this->objFromFixture('DataObjectTest_Player', 'player2');
1731
		// Test that we can traverse more than once, and that arbitrary methods are okay
1732
		$this->assertInstanceOf('SilverStripe\Model\FieldType\DBVarchar', $player->relObject('Teams.First.Title'));
1733
		$this->assertEquals("Team 1", $player->relObject('Teams.First.Title')->getValue());
1734
	}
1735
1736
	public function testLateStaticBindingStyle() {
1737
		// Confirm that DataObjectTest_Player::get() operates as excepted
1738
		$this->assertEquals(4, DataObjectTest_Player::get()->Count());
1739
		$this->assertInstanceOf('DataObjectTest_Player', DataObjectTest_Player::get()->First());
1740
1741
		// You can't pass arguments to LSB syntax - use the DataList methods instead.
1742
		$this->setExpectedException('InvalidArgumentException');
1743
		DataObjectTest_Player::get(null, "\"ID\" = 1");
1744
1745
	}
1746
1747
	public function testBrokenLateStaticBindingStyle() {
1748
		// If you call DataObject::get() you have to pass a first argument
1749
		$this->setExpectedException('InvalidArgumentException');
1750
		DataObject::get();
1751
1752
	}
1753
1754
}
1755
1756
class DataObjectTest_Player extends Member implements TestOnly {
1757
	private static $db = array(
1758
		'IsRetired' => 'Boolean',
1759
		'ShirtNumber' => 'Varchar',
1760
	);
1761
1762
	private static $has_one = array(
1763
		'FavouriteTeam' => 'DataObjectTest_Team',
1764
	);
1765
1766
	private static $belongs_many_many = array(
1767
		'Teams' => 'DataObjectTest_Team'
1768
	);
1769
1770
	private static $has_many = array(
1771
		'Fans' => 'DataObjectTest_Fan.Favourite', // Polymorphic - Player fans
1772
		'CaptainTeams' => 'DataObjectTest_Team.Captain',
1773
		'FoundingTeams' => 'DataObjectTest_Team.Founder'
1774
	);
1775
1776
	private static $belongs_to = array (
1777
		'CompanyOwned'    => 'DataObjectTest_Company.Owner'
1778
	);
1779
1780
	private static $searchable_fields = array(
1781
		'IsRetired',
1782
		'ShirtNumber'
1783
	);
1784
}
1785
1786
class DataObjectTest_Team extends DataObject implements TestOnly {
1787
1788
	private static $db = array(
1789
		'Title' => 'Varchar',
1790
		'DatabaseField' => 'HTMLVarchar'
1791
	);
1792
1793
	private static $has_one = array(
1794
		"Captain" => 'DataObjectTest_Player',
1795
		"Founder" => 'DataObjectTest_Player',
1796
		'HasOneRelationship' => 'DataObjectTest_Player',
1797
	);
1798
1799
	private static $has_many = array(
1800
		'SubTeams' => 'DataObjectTest_SubTeam',
1801
		'Comments' => 'DataObjectTest_TeamComment',
1802
		'Fans' => 'DataObjectTest_Fan.Favourite', // Polymorphic - Team fans
1803
		'PlayerFans' => 'DataObjectTest_Player.FavouriteTeam'
1804
	);
1805
1806
	private static $many_many = array(
1807
		'Players' => 'DataObjectTest_Player'
1808
	);
1809
1810
	private static $many_many_extraFields = array(
1811
		'Players' => array(
1812
			'Position' => 'Varchar(100)'
1813
		)
1814
	);
1815
1816
	private static $belongs_many_many = array(
1817
		'Sponsors' => 'DataObjectTest_EquipmentCompany.SponsoredTeams',
1818
		'EquipmentSuppliers' => 'DataObjectTest_EquipmentCompany.EquipmentCustomers'
1819
	);
1820
1821
	private static $summary_fields = array(
1822
		'Title' => 'Custom Title',
1823
		'Title.UpperCase' => 'Title',
1824
		'Captain.ShirtNumber' => 'Captain\'s shirt number',
1825
		'Captain.FavouriteTeam.Title' => 'Captain\'s favourite team'
1826
	);
1827
1828
	private static $default_sort = '"Title"';
1829
1830
	public function MyTitle() {
1831
		return 'Team ' . $this->Title;
1832
	}
1833
1834
	public function getDynamicField() {
1835
		return 'dynamicfield';
1836
	}
1837
1838
}
1839
1840
class DataObjectTest_Fixture extends DataObject implements TestOnly {
1841
	private static $db = array(
1842
		// Funny field names
1843
		'Data' => 'Varchar',
1844
		'Duplicate' => 'Varchar',
1845
		'DbObject' => 'Varchar',
1846
1847
		// Field types
1848
		'DateField' => 'Date',
1849
		'DatetimeField' => 'SS_Datetime',
1850
1851
		'MyFieldWithDefault' => 'Varchar',
1852
		'MyFieldWithAltDefault' => 'Varchar'
1853
	);
1854
1855
	private static $defaults = array(
1856
		'MyFieldWithDefault' => 'Default Value',
1857
	);
1858
1859
	private static $summary_fields = array(
1860
		'Data' => 'Data',
1861
		'DateField.Nice' => 'Date'
1862
	);
1863
1864
	private static $searchable_fields = array();
1865
1866
	public function populateDefaults() {
1867
		parent::populateDefaults();
1868
1869
		$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...
1870
	}
1871
1872
}
1873
1874
class DataObjectTest_SubTeam extends DataObjectTest_Team implements TestOnly {
1875
	private static $db = array(
1876
		'SubclassDatabaseField' => 'Varchar'
1877
	);
1878
1879
	private static $has_one = array(
1880
		"ParentTeam" => 'DataObjectTest_Team',
1881
	);
1882
1883
	private static $many_many = array(
1884
		'FormerPlayers' => 'DataObjectTest_Player'
1885
	);
1886
1887
	private static $many_many_extraFields = array(
1888
		'FormerPlayers' => array(
1889
			'Position' => 'Varchar(100)'
1890
		)
1891
	);
1892
}
1893
class OtherSubclassWithSameField extends DataObjectTest_Team implements TestOnly {
1894
	private static $db = array(
1895
		'SubclassDatabaseField' => 'Varchar',
1896
	);
1897
}
1898
1899
1900
class DataObjectTest_FieldlessTable extends DataObject implements TestOnly {
1901
}
1902
1903
class DataObjectTest_FieldlessSubTable extends DataObjectTest_Team implements TestOnly {
1904
}
1905
1906
1907
class DataObjectTest_Team_Extension extends DataExtension implements TestOnly {
1908
1909
	private static $db = array(
1910
		'ExtendedDatabaseField' => 'Varchar'
1911
	);
1912
1913
	private static $has_one = array(
1914
		'ExtendedHasOneRelationship' => 'DataObjectTest_Player'
1915
	);
1916
1917
	public function getExtendedDynamicField() {
1918
		return "extended dynamic field";
1919
	}
1920
1921
}
1922
1923
class DataObjectTest_ValidatedObject extends DataObject implements TestOnly {
1924
1925
	private static $db = array(
1926
		'Name' => 'Varchar(50)'
1927
	);
1928
1929
	public function validate() {
1930
		if(!empty($this->Name)) {
1931
			return new ValidationResult();
1932
		} else {
1933
			return new ValidationResult(false, "This object needs a name. Otherwise it will have an identity crisis!");
1934
		}
1935
	}
1936
}
1937
1938
class DataObjectTest_Company extends DataObject implements TestOnly {
1939
1940
	private static $db = array(
1941
		'Name' => 'Varchar'
1942
	);
1943
1944
	private static $has_one = array (
1945
		'CEO'         => 'DataObjectTest_CEO',
1946
		'PreviousCEO' => 'DataObjectTest_CEO',
1947
		'Owner'       => 'DataObject' // polymorphic
1948
	);
1949
1950
	private static $has_many = array (
1951
		'CurrentStaff'     => 'DataObjectTest_Staff.CurrentCompany',
1952
		'PreviousStaff'    => 'DataObjectTest_Staff.PreviousCompany'
1953
	);
1954
}
1955
1956
class DataObjectTest_EquipmentCompany extends DataObjectTest_Company implements TestOnly {
1957
	private static $many_many = array(
1958
		'SponsoredTeams' => 'DataObjectTest_Team',
1959
		'EquipmentCustomers' => 'DataObjectTest_Team'
1960
	);
1961
1962
	private static $many_many_extraFields = array(
1963
		'SponsoredTeams' => array(
1964
			'SponsorFee' => 'Int'
1965
		)
1966
	);
1967
}
1968
1969
class DataObjectTest_SubEquipmentCompany extends DataObjectTest_EquipmentCompany implements TestOnly {
1970
	private static $db = array(
1971
		'SubclassDatabaseField' => 'Varchar'
1972
	);
1973
}
1974
1975
class DataObjectTest_Staff extends DataObject implements TestOnly {
1976
	private static $has_one = array (
1977
		'CurrentCompany'  => 'DataObjectTest_Company',
1978
		'PreviousCompany' => 'DataObjectTest_Company'
1979
	);
1980
}
1981
1982
class DataObjectTest_CEO extends DataObjectTest_Staff {
1983
	private static $belongs_to = array (
1984
		'Company'         => 'DataObjectTest_Company.CEO',
1985
		'PreviousCompany' => 'DataObjectTest_Company.PreviousCEO',
1986
		'CompanyOwned'    => 'DataObjectTest_Company.Owner'
1987
	);
1988
}
1989
1990
class DataObjectTest_TeamComment extends DataObject implements TestOnly {
1991
	private static $db = array(
1992
		'Name' => 'Varchar',
1993
		'Comment' => 'Text'
1994
	);
1995
1996
	private static $has_one = array(
1997
		'Team' => 'DataObjectTest_Team'
1998
	);
1999
2000
	private static $default_sort = '"Name" ASC';
2001
}
2002
2003
class DataObjectTest_Fan extends DataObject implements TestOnly {
2004
2005
	private static $db = array(
2006
		'Name' => 'Varchar(255)',
2007
		'Email' => 'Varchar',
2008
	);
2009
2010
	private static $has_one = array(
2011
		'Favourite' => 'DataObject', // Polymorphic relation
2012
		'SecondFavourite' => 'DataObject'
2013
	);
2014
}
2015
2016
class DataObjectTest_ExtendedTeamComment extends DataObjectTest_TeamComment {
2017
	private static $db = array(
2018
		'Comment' => 'HTMLText'
2019
	);
2020
}
2021
2022
class DataObjectTest_Play extends DataObject implements TestOnly {}
2023
class DataObjectTest_Ploy extends DataObject implements TestOnly {}
2024
class DataObjectTest_Bogey extends DataObject implements TestOnly {}
2025
2026
DataObjectTest_Team::add_extension('DataObjectTest_Team_Extension');
2027
2028