Completed
Push — new-committers ( 29cb6f...bcba16 )
by Sam
12:18 queued 33s
created

DataObjectTest::testBelongsTo()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 33
Code Lines 20

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 33
rs 8.8571
cc 1
eloc 20
nc 1
nop 0
1
<?php
2
/**
3
 * @package framework
4
 * @subpackage tests
5
 */
6
class DataObjectTest extends SapphireTest {
7
8
	protected static $fixture_file = 'DataObjectTest.yml';
9
10
	protected $extraDataObjects = array(
11
		'DataObjectTest_Team',
12
		'DataObjectTest_Fixture',
13
		'DataObjectTest_SubTeam',
14
		'OtherSubclassWithSameField',
15
		'DataObjectTest_FieldlessTable',
16
		'DataObjectTest_FieldlessSubTable',
17
		'DataObjectTest_ValidatedObject',
18
		'DataObjectTest_Player',
19
		'DataObjectTest_TeamComment',
20
		'DataObjectTest_EquipmentCompany',
21
		'DataObjectTest_SubEquipmentCompany',
22
		'DataObjectTest\NamespacedClass',
23
		'DataObjectTest\RelationClass',
24
		'DataObjectTest_ExtendedTeamComment',
25
		'DataObjectTest_Company',
26
		'DataObjectTest_Staff',
27
		'DataObjectTest_CEO',
28
		'DataObjectTest_Fan',
29
		'DataObjectTest_Play',
30
		'DataObjectTest_Ploy',
31
		'DataObjectTest_Bogey',
32
	);
33
34
	public function testDb() {
35
		$obj = new DataObjectTest_TeamComment();
36
		$dbFields = $obj->db();
37
38
		// Assert fields are included
39
		$this->assertArrayHasKey('Name', $dbFields);
40
41
		// Assert the base fields are excluded
42
		$this->assertArrayNotHasKey('Created', $dbFields);
43
		$this->assertArrayNotHasKey('LastEdited', $dbFields);
44
		$this->assertArrayNotHasKey('ClassName', $dbFields);
45
		$this->assertArrayNotHasKey('ID', $dbFields);
46
47
		// Assert that the correct field type is returned when passing a field
48
		$this->assertEquals('Varchar', $obj->db('Name'));
49
		$this->assertEquals('Text', $obj->db('Comment'));
50
51
		$obj = new DataObjectTest_ExtendedTeamComment();
52
		$dbFields = $obj->db();
53
54
		// Assert overloaded fields have correct data type
55
		$this->assertEquals('HTMLText', $obj->db('Comment'));
56
		$this->assertEquals('HTMLText', $dbFields['Comment'],
57
			'Calls to DataObject::db without a field specified return correct data types');
58
59
		// assertEquals doesn't verify the order of array elements, so access keys manually to check order:
60
		// expected: array('Name' => 'Varchar', 'Comment' => 'HTMLText')
61
		reset($dbFields);
62
		$this->assertEquals('Name', key($dbFields), 'DataObject::db returns fields in correct order');
63
		next($dbFields);
64
		$this->assertEquals('Comment', key($dbFields), 'DataObject::db returns fields in correct order');
65
	}
66
67
	public function testConstructAcceptsValues() {
68
		// Values can be an array...
69
		$player = new DataObjectTest_Player(array(
70
			'FirstName' => 'James',
71
			'Surname' => 'Smith'
72
		));
73
74
		$this->assertEquals('James', $player->FirstName);
75
		$this->assertEquals('Smith', $player->Surname);
76
77
		// ... or a stdClass inst
78
		$data = new stdClass();
79
		$data->FirstName = 'John';
80
		$data->Surname = 'Doe';
81
		$player = new DataObjectTest_Player($data);
0 ignored issues
show
Documentation introduced by
$data is of type object<stdClass>, but the function expects a array|null.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
82
83
		$this->assertEquals('John', $player->FirstName);
84
		$this->assertEquals('Doe', $player->Surname);
85
86
		// IDs should be stored as integers, not strings
87
		$player = new DataObjectTest_Player(array('ID' => '5'));
88
		$this->assertSame(5, $player->ID);
89
	}
90
91
	public function testValidObjectsForBaseFields() {
92
		$obj = new DataObjectTest_ValidatedObject();
93
94
		foreach (array('Created', 'LastEdited', 'ClassName', 'ID') as $field) {
95
			$helper = $obj->dbObject($field);
96
			$this->assertTrue(
97
				($helper instanceof DBField),
98
				"for {$field} expected helper to be DBField, but was " .
99
				(is_object($helper) ? get_class($helper) : "null")
100
			);
101
		}
102
	}
103
104
	public function testDataIntegrityWhenTwoSubclassesHaveSameField() {
105
		// Save data into DataObjectTest_SubTeam.SubclassDatabaseField
106
		$obj = new DataObjectTest_SubTeam();
107
		$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...
108
		$obj->write();
109
110
		// Change the class
111
		$obj->ClassName = 'OtherSubclassWithSameField';
112
		$obj->write();
113
		$obj->flushCache();
114
115
		// Re-fetch from the database and confirm that the data is sourced from
116
		// OtherSubclassWithSameField.SubclassDatabaseField
117
		$obj = DataObject::get_by_id('DataObjectTest_Team', $obj->ID);
118
		$this->assertNull($obj->SubclassDatabaseField);
119
120
		// Confirm that save the object in the other direction.
121
		$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...
122
		$obj->write();
123
124
		$obj->ClassName = 'DataObjectTest_SubTeam';
125
		$obj->write();
126
		$obj->flushCache();
127
128
		// If we restore the class, the old value has been lying dormant and will be available again.
129
		// NOTE: This behaviour is volatile; we may change this in the future to clear fields that
130
		// are no longer relevant when changing ClassName
131
		$obj = DataObject::get_by_id('DataObjectTest_Team', $obj->ID);
132
		$this->assertEquals('obj-SubTeam', $obj->SubclassDatabaseField);
133
	}
134
135
	/**
136
	 * Test deletion of DataObjects
137
	 *   - Deleting using delete() on the DataObject
138
	 *   - Deleting using DataObject::delete_by_id()
139
	 */
140
	public function testDelete() {
141
		// Test deleting using delete() on the DataObject
142
		// Get the first page
143
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain1');
144
		$objID = $obj->ID;
145
		// Check the page exists before deleting
146
		$this->assertTrue(is_object($obj) && $obj->exists());
147
		// Delete the page
148
		$obj->delete();
149
		// Check that page does not exist after deleting
150
		$obj = DataObject::get_by_id('DataObjectTest_Player', $objID);
151
		$this->assertTrue(!$obj || !$obj->exists());
152
153
154
		// Test deleting using DataObject::delete_by_id()
155
		// Get the second page
156
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain2');
157
		$objID = $obj->ID;
158
		// Check the page exists before deleting
159
		$this->assertTrue(is_object($obj) && $obj->exists());
160
		// Delete the page
161
		DataObject::delete_by_id('DataObjectTest_Player', $obj->ID);
162
		// Check that page does not exist after deleting
163
		$obj = DataObject::get_by_id('DataObjectTest_Player', $objID);
164
		$this->assertTrue(!$obj || !$obj->exists());
165
	}
166
167
	/**
168
	 * Test methods that get DataObjects
169
	 *   - DataObject::get()
170
	 *       - All records of a DataObject
171
	 *       - Filtering
172
	 *       - Sorting
173
	 *       - Joins
174
	 *       - Limit
175
	 *       - Container class
176
	 *   - DataObject::get_by_id()
177
	 *   - DataObject::get_one()
178
	 *        - With and without caching
179
	 *        - With and without ordering
180
	 */
181
	public function testGet() {
182
		// Test getting all records of a DataObject
183
		$comments = DataObject::get('DataObjectTest_TeamComment');
184
		$this->assertEquals(3, $comments->Count());
185
186
		// Test WHERE clause
187
		$comments = DataObject::get('DataObjectTest_TeamComment', "\"Name\"='Bob'");
188
		$this->assertEquals(1, $comments->Count());
189
		foreach($comments as $comment) {
190
			$this->assertEquals('Bob', $comment->Name);
191
		}
192
193
		// Test sorting
194
		$comments = DataObject::get('DataObjectTest_TeamComment', '', "\"Name\" ASC");
195
		$this->assertEquals(3, $comments->Count());
196
		$this->assertEquals('Bob', $comments->First()->Name);
197
		$comments = DataObject::get('DataObjectTest_TeamComment', '', "\"Name\" DESC");
198
		$this->assertEquals(3, $comments->Count());
199
		$this->assertEquals('Phil', $comments->First()->Name);
200
201
		// Test limit
202
		$comments = DataObject::get('DataObjectTest_TeamComment', '', "\"Name\" ASC", '', '1,2');
203
		$this->assertEquals(2, $comments->Count());
204
		$this->assertEquals('Joe', $comments->First()->Name);
205
		$this->assertEquals('Phil', $comments->Last()->Name);
206
207
		// Test get_by_id()
208
		$captain1ID = $this->idFromFixture('DataObjectTest_Player', 'captain1');
209
		$captain1 = DataObject::get_by_id('DataObjectTest_Player', $captain1ID);
210
		$this->assertEquals('Captain', $captain1->FirstName);
211
212
		// Test get_one() without caching
213
		$comment1 = DataObject::get_one('DataObjectTest_TeamComment', array(
214
			'"DataObjectTest_TeamComment"."Name"' => 'Joe'
215
		), false);
216
		$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...
217
218
		$comment2 = DataObject::get_one('DataObjectTest_TeamComment', array(
219
			'"DataObjectTest_TeamComment"."Name"' => 'Joe'
220
		), false);
221
		$this->assertNotEquals($comment1->Comment, $comment2->Comment);
222
223
		// Test get_one() with caching
224
		$comment1 = DataObject::get_one('DataObjectTest_TeamComment', array(
225
			'"DataObjectTest_TeamComment"."Name"' => 'Bob'
226
		), true);
227
		$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...
228
229
		$comment2 = DataObject::get_one('DataObjectTest_TeamComment', array(
230
			'"DataObjectTest_TeamComment"."Name"' => 'Bob'
231
		), true);
232
		$this->assertEquals((string)$comment1->Comment, (string)$comment2->Comment);
233
234
		// Test get_one() with order by without caching
235
		$comment = DataObject::get_one('DataObjectTest_TeamComment', '', false, "\"Name\" ASC");
236
		$this->assertEquals('Bob', $comment->Name);
237
238
		$comment = DataObject::get_one('DataObjectTest_TeamComment', '', false, "\"Name\" DESC");
239
		$this->assertEquals('Phil', $comment->Name);
240
241
		// Test get_one() with order by with caching
242
		$comment = DataObject::get_one('DataObjectTest_TeamComment', '', true, '"Name" ASC');
243
		$this->assertEquals('Bob', $comment->Name);
244
		$comment = DataObject::get_one('DataObjectTest_TeamComment', '', true, '"Name" DESC');
245
		$this->assertEquals('Phil', $comment->Name);
246
	}
247
248 View Code Duplication
	public function testGetCaseInsensitive() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
249
		// Test get_one() with bad case on the classname
250
		// Note: This will succeed only if the underlying DB server supports case-insensitive
251
		// table names (e.g. such as MySQL, but not SQLite3)
252
		if(!(DB::get_conn() instanceof MySQLDatabase)) {
253
			$this->markTestSkipped('MySQL only');
254
		}
255
256
		$subteam1 = DataObject::get_one('dataobjecttest_subteam', array(
257
			'"DataObjectTest_Team"."Title"' => 'Subteam 1'
258
		), true);
259
		$this->assertNotEmpty($subteam1);
260
		$this->assertEquals($subteam1->Title, "Subteam 1");
261
	}
262
263
	public function testGetSubclassFields() {
264
		/* Test that fields / has_one relations from the parent table and the subclass tables are extracted */
265
		$captain1 = $this->objFromFixture("DataObjectTest_Player", "captain1");
266
		// Base field
267
		$this->assertEquals('Captain', $captain1->FirstName);
268
		// Subclass field
269
		$this->assertEquals('007', $captain1->ShirtNumber);
270
		// Subclass has_one relation
271
		$this->assertEquals($this->idFromFixture('DataObjectTest_Team', 'team1'), $captain1->FavouriteTeamID);
272
	}
273
274
	public function testGetRelationClass() {
275
		$obj = new DataObjectTest_Player();
0 ignored issues
show
Unused Code introduced by
$obj is not used, you could remove the assignment.

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

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

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

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

Loading history...
276
		$this->assertEquals(singleton('DataObjectTest_Player')->getRelationClass('FavouriteTeam'),
277
			'DataObjectTest_Team', 'has_one is properly inspected');
278
		$this->assertEquals(singleton('DataObjectTest_Company')->getRelationClass('CurrentStaff'),
279
			'DataObjectTest_Staff', 'has_many is properly inspected');
280
		$this->assertEquals(singleton('DataObjectTest_Team')->getRelationClass('Players'), 'DataObjectTest_Player',
281
			'many_many is properly inspected');
282
		$this->assertEquals(singleton('DataObjectTest_Player')->getRelationClass('Teams'), 'DataObjectTest_Team',
283
			'belongs_many_many is properly inspected');
284
		$this->assertEquals(singleton('DataObjectTest_CEO')->getRelationClass('Company'), 'DataObjectTest_Company',
285
			'belongs_to is properly inspected');
286
		$this->assertEquals(singleton('DataObjectTest_Fan')->getRelationClass('Favourite'), 'DataObject',
287
			'polymorphic has_one is properly inspected');
288
	}
289
290
	/**
291
	 * Test that has_one relations can be retrieved
292
	 */
293
	public function testGetHasOneRelations() {
294
		$captain1 = $this->objFromFixture("DataObjectTest_Player", "captain1");
295
		$team1ID = $this->idFromFixture('DataObjectTest_Team', 'team1');
296
297
		// There will be a field called (relname)ID that contains the ID of the
298
		// object linked to via the has_one relation
299
		$this->assertEquals($team1ID, $captain1->FavouriteTeamID);
300
301
		// There will be a method called $obj->relname() that returns the object itself
302
		$this->assertEquals($team1ID, $captain1->FavouriteTeam()->ID);
303
304
		// Check entity with polymorphic has-one
305
		$fan1 = $this->objFromFixture("DataObjectTest_Fan", "fan1");
306
		$this->assertTrue((bool)$fan1->hasValue('Favourite'));
307
308
		// There will be fields named (relname)ID and (relname)Class for polymorphic
309
		// entities
310
		$this->assertEquals($team1ID, $fan1->FavouriteID);
311
		$this->assertEquals('DataObjectTest_Team', $fan1->FavouriteClass);
312
313
		// There will be a method called $obj->relname() that returns the object itself
314
		$favourite = $fan1->Favourite();
315
		$this->assertEquals($team1ID, $favourite->ID);
316
		$this->assertInstanceOf('DataObjectTest_Team', $favourite);
317
318
		// check behaviour of dbObject with polymorphic relations
319
		$favouriteDBObject = $fan1->dbObject('Favourite');
320
		$favouriteValue = $favouriteDBObject->getValue();
321
		$this->assertInstanceOf('PolymorphicForeignKey', $favouriteDBObject);
322
		$this->assertEquals($favourite->ID, $favouriteValue->ID);
323
		$this->assertEquals($favourite->ClassName, $favouriteValue->ClassName);
324
	}
325
326
	/**
327
	 * Simple test to ensure that namespaced classes and polymorphic relations work together
328
	 */
329
	public function testPolymorphicNamespacedRelations() {
330
		$parent = new \DataObjectTest\NamespacedClass();
331
		$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...
332
		$parent->write();
333
334
		$child = new \DataObjectTest\RelationClass();
335
		$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...
336
		$child->write();
337
		$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...
338
339
		$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...
340
		$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...
341
		$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...
342
	}
343
344
	public function testLimitAndCount() {
345
		$players = DataObject::get("DataObjectTest_Player");
346
347
		// There's 4 records in total
348
		$this->assertEquals(4, $players->count());
349
350
		// Testing "##, ##" syntax
351
		$this->assertEquals(4, $players->limit(20)->count());
352
		$this->assertEquals(4, $players->limit(20, 0)->count());
353
		$this->assertEquals(0, $players->limit(20, 20)->count());
354
		$this->assertEquals(2, $players->limit(2, 0)->count());
355
		$this->assertEquals(1, $players->limit(5, 3)->count());
356
	}
357
358
	/**
359
	 * Test writing of database columns which don't correlate to a DBField,
360
	 * e.g. all relation fields on has_one/has_many like "ParentID".
361
	 *
362
	 */
363
	public function testWritePropertyWithoutDBField() {
364
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain1');
365
		$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...
366
		$obj->write();
367
368
		// reload the page from the database
369
		$savedObj = DataObject::get_by_id('DataObjectTest_Player', $obj->ID);
370
		$this->assertTrue($savedObj->FavouriteTeamID == 99);
371
372
		// Test with porymorphic relation
373
		$obj2 = $this->objFromFixture("DataObjectTest_Fan", "fan1");
374
		$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...
375
		$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...
376
		$obj2->write();
377
378
		$savedObj2 = DataObject::get_by_id('DataObjectTest_Fan', $obj2->ID);
379
		$this->assertTrue($savedObj2->FavouriteID == 99);
380
		$this->assertTrue($savedObj2->FavouriteClass == 'DataObjectTest_Player');
381
	}
382
383
	/**
384
	 * Test has many relationships
385
	 *   - Test getComponents() gets the ComponentSet of the other side of the relation
386
	 *   - Test the IDs on the DataObjects are set correctly
387
	 */
388
	public function testHasManyRelationships() {
389
		$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
390
391
		// Test getComponents() gets the ComponentSet of the other side of the relation
392
		$this->assertTrue($team1->Comments()->Count() == 2);
393
394
		// Test the IDs on the DataObjects are set correctly
395
		foreach($team1->Comments() as $comment) {
396
			$this->assertEquals($team1->ID, $comment->TeamID);
397
		}
398
399
		// Test that we can add and remove items that already exist in the database
400
		$newComment = new DataObjectTest_TeamComment();
401
		$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...
402
		$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...
403
		$newComment->write();
404
		$team1->Comments()->add($newComment);
405
		$this->assertEquals($team1->ID, $newComment->TeamID);
406
407
		$comment1 = $this->objFromFixture('DataObjectTest_TeamComment', 'comment1');
408
		$comment2 = $this->objFromFixture('DataObjectTest_TeamComment', 'comment2');
409
		$team1->Comments()->remove($comment2);
410
411
		$team1CommentIDs = $team1->Comments()->sort('ID')->column('ID');
412
		$this->assertEquals(array($comment1->ID, $newComment->ID), $team1CommentIDs);
413
414
		// Test that removing an item from a list doesn't remove it from the same
415
		// relation belonging to a different object
416
		$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
417
		$team2 = $this->objFromFixture('DataObjectTest_Team', 'team2');
418
		$team2->Comments()->remove($comment1);
419
		$team1CommentIDs = $team1->Comments()->sort('ID')->column('ID');
420
		$this->assertEquals(array($comment1->ID, $newComment->ID), $team1CommentIDs);
421
	}
422
423
424
	/**
425
	 * Test has many relationships against polymorphic has_one fields
426
	 *   - Test getComponents() gets the ComponentSet of the other side of the relation
427
	 *   - Test the IDs on the DataObjects are set correctly
428
	 */
429
	public function testHasManyPolymorphicRelationships() {
430
		$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
431
432
		// Test getComponents() gets the ComponentSet of the other side of the relation
433
		$this->assertTrue($team1->Fans()->Count() == 2);
434
435
		// Test the IDs/Classes on the DataObjects are set correctly
436
		foreach($team1->Fans() as $fan) {
437
			$this->assertEquals($team1->ID, $fan->FavouriteID, 'Fan has the correct FavouriteID');
438
			$this->assertEquals('DataObjectTest_Team', $fan->FavouriteClass, 'Fan has the correct FavouriteClass');
439
		}
440
441
		// Test that we can add and remove items that already exist in the database
442
		$newFan = new DataObjectTest_Fan();
443
		$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...
444
		$newFan->write();
445
		$team1->Fans()->add($newFan);
446
		$this->assertEquals($team1->ID, $newFan->FavouriteID, 'Newly created fan has the correct FavouriteID');
447
		$this->assertEquals(
448
			'DataObjectTest_Team',
449
			$newFan->FavouriteClass,
450
			'Newly created fan has the correct FavouriteClass'
451
		);
452
453
		$fan1 = $this->objFromFixture('DataObjectTest_Fan', 'fan1');
454
		$fan3 = $this->objFromFixture('DataObjectTest_Fan', 'fan3');
455
		$team1->Fans()->remove($fan3);
456
457
		$team1FanIDs = $team1->Fans()->sort('ID')->column('ID');
458
		$this->assertEquals(array($fan1->ID, $newFan->ID), $team1FanIDs);
459
460
		// Test that removing an item from a list doesn't remove it from the same
461
		// relation belonging to a different object
462
		$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
463
		$player1 = $this->objFromFixture('DataObjectTest_Player', 'player1');
464
		$player1->Fans()->remove($fan1);
465
		$team1FanIDs = $team1->Fans()->sort('ID')->column('ID');
466
		$this->assertEquals(array($fan1->ID, $newFan->ID), $team1FanIDs);
467
	}
468
469
470
	public function testHasOneRelationship() {
471
		$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
472
		$player1 = $this->objFromFixture('DataObjectTest_Player', 'player1');
473
		$player2 = $this->objFromFixture('DataObjectTest_Player', 'player2');
474
		$fan1 = $this->objFromFixture('DataObjectTest_Fan', 'fan1');
475
476
		// Test relation probing
477
		$this->assertFalse((bool)$team1->hasValue('Captain', null, false));
478
		$this->assertFalse((bool)$team1->hasValue('CaptainID', null, false));
479
480
		// Add a captain to team 1
481
		$team1->setField('CaptainID', $player1->ID);
482
		$team1->write();
483
484
		$this->assertTrue((bool)$team1->hasValue('Captain', null, false));
485
		$this->assertTrue((bool)$team1->hasValue('CaptainID', null, false));
486
487
		$this->assertEquals($player1->ID, $team1->Captain()->ID,
488
			'The captain exists for team 1');
489
		$this->assertEquals($player1->ID, $team1->getComponent('Captain')->ID,
490
			'The captain exists through the component getter');
491
492
		$this->assertEquals($team1->Captain()->FirstName, 'Player 1',
493
			'Player 1 is the captain');
494
		$this->assertEquals($team1->getComponent('Captain')->FirstName, 'Player 1',
495
			'Player 1 is the captain');
496
497
		$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...
498
		$team1->write();
499
500
		$this->assertEquals($player2->ID, $team1->Captain()->ID);
501
		$this->assertEquals($player2->ID, $team1->getComponent('Captain')->ID);
502
		$this->assertEquals('Player 2', $team1->Captain()->FirstName);
503
		$this->assertEquals('Player 2', $team1->getComponent('Captain')->FirstName);
504
505
506
		// Set the favourite team for fan1
507
		$fan1->setField('FavouriteID', $team1->ID);
508
		$fan1->setField('FavouriteClass', $team1->class);
509
510
		$this->assertEquals($team1->ID, $fan1->Favourite()->ID, 'The team is assigned to fan 1');
511
		$this->assertInstanceOf($team1->class, $fan1->Favourite(), 'The team is assigned to fan 1');
512
		$this->assertEquals($team1->ID, $fan1->getComponent('Favourite')->ID,
513
			'The team exists through the component getter'
514
		);
515
		$this->assertInstanceOf($team1->class, $fan1->getComponent('Favourite'),
516
			'The team exists through the component getter'
517
		);
518
519
		$this->assertEquals($fan1->Favourite()->Title, 'Team 1',
520
			'Team 1 is the favourite');
521
		$this->assertEquals($fan1->getComponent('Favourite')->Title, 'Team 1',
522
			'Team 1 is the favourite');
523
	}
524
525
	/**
526
	 * @todo Extend type change tests (e.g. '0'==NULL)
527
	 */
528
	public function testChangedFields() {
529
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain1');
530
		$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...
531
		$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...
532
533
		$this->assertEquals(
534
			$obj->getChangedFields(false, 1),
535
			array(
536
				'FirstName' => array(
537
					'before' => 'Captain',
538
					'after' => 'Captain-changed',
539
					'level' => 2
540
				),
541
				'IsRetired' => array(
542
					'before' => 1,
543
					'after' => true,
544
					'level' => 1
545
				)
546
			),
547
			'Changed fields are correctly detected with strict type changes (level=1)'
548
		);
549
550
		$this->assertEquals(
551
			$obj->getChangedFields(false, 2),
552
			array(
553
				'FirstName' => array(
554
					'before'=>'Captain',
555
					'after'=>'Captain-changed',
556
					'level' => 2
557
				)
558
			),
559
			'Changed fields are correctly detected while ignoring type changes (level=2)'
560
		);
561
562
		$newObj = new DataObjectTest_Player();
563
		$newObj->FirstName = "New Player";
564
		$this->assertEquals(
565
			$newObj->getChangedFields(false, 2),
566
			array(
567
				'FirstName' => array(
568
					'before' => null,
569
					'after' => 'New Player',
570
					'level' => 2
571
				)
572
			),
573
			'Initialised fields are correctly detected as full changes'
574
		);
575
	}
576
577
	public function testIsChanged() {
578
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain1');
579
		$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...
580
		$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...
581
582
		$this->assertTrue($obj->isChanged('FirstName', 1));
583
		$this->assertTrue($obj->isChanged('FirstName', 2));
584
		$this->assertTrue($obj->isChanged('IsRetired', 1));
585
		$this->assertFalse($obj->isChanged('IsRetired', 2));
586
		$this->assertFalse($obj->isChanged('Email', 1), 'Doesnt change mark unchanged property');
587
		$this->assertFalse($obj->isChanged('Email', 2), 'Doesnt change mark unchanged property');
588
589
		$newObj = new DataObjectTest_Player();
590
		$newObj->FirstName = "New Player";
591
		$this->assertTrue($newObj->isChanged('FirstName', 1));
592
		$this->assertTrue($newObj->isChanged('FirstName', 2));
593
		$this->assertFalse($newObj->isChanged('Email', 1));
594
		$this->assertFalse($newObj->isChanged('Email', 2));
595
596
		$newObj->write();
597
		$this->assertFalse($newObj->isChanged('FirstName', 1));
598
		$this->assertFalse($newObj->isChanged('FirstName', 2));
599
		$this->assertFalse($newObj->isChanged('Email', 1));
600
		$this->assertFalse($newObj->isChanged('Email', 2));
601
602
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain1');
603
		$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...
604
		$this->assertTrue($obj->isChanged('FirstName', 1));
605
		$this->assertTrue($obj->isChanged('FirstName', 2));
606
607
		/* Test when there's not field provided */
608
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain1');
609
		$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...
610
		$this->assertTrue($obj->isChanged());
611
612
		$obj->write();
613
		$this->assertFalse($obj->isChanged());
614
	}
615
616
	public function testRandomSort() {
617
		/* If we perform the same regularly sorted query twice, it should return the same results */
618
		$itemsA = DataObject::get("DataObjectTest_TeamComment", "", "ID");
619
		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...
620
621
		$itemsB = DataObject::get("DataObjectTest_TeamComment", "", "ID");
622
		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...
623
624
		/* Test when there's not field provided */
625
		$obj = $this->objFromFixture('DataObjectTest_Player', 'captain1');
626
		$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...
627
		$this->assertTrue($obj->isChanged());
628
629
		$obj->write();
630
		$this->assertFalse($obj->isChanged());
631
632
		/* If we perform the same random query twice, it shouldn't return the same results */
633
		$itemsA = DataObject::get("DataObjectTest_TeamComment", "", DB::get_conn()->random());
634
		$itemsB = DataObject::get("DataObjectTest_TeamComment", "", DB::get_conn()->random());
635
		$itemsC = DataObject::get("DataObjectTest_TeamComment", "", DB::get_conn()->random());
636
		$itemsD = DataObject::get("DataObjectTest_TeamComment", "", DB::get_conn()->random());
637
		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...
638
		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...
639
		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...
640
		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...
641
642
		// These shouldn't all be the same (run it 4 times to minimise chance of an accidental collision)
643
		// There's about a 1 in a billion chance of an accidental collision
644
		$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...
645
	}
646
647
	public function testWriteSavesToHasOneRelations() {
648
		/* DataObject::write() should save to a has_one relationship if you set a field called (relname)ID */
649
		$team = new DataObjectTest_Team();
650
		$captainID = $this->idFromFixture('DataObjectTest_Player', 'player1');
651
		$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...
652
		$team->write();
653
		$this->assertEquals($captainID,
654
			DB::query("SELECT \"CaptainID\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $team->ID")->value());
655
656
		/* After giving it a value, you should also be able to set it back to null */
657
		$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...
658
		$team->write();
659
		$this->assertEquals(0,
660
			DB::query("SELECT \"CaptainID\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $team->ID")->value());
661
662
		/* You should also be able to save a blank to it when it's first created */
663
		$team = new DataObjectTest_Team();
664
		$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...
665
		$team->write();
666
		$this->assertEquals(0,
667
			DB::query("SELECT \"CaptainID\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $team->ID")->value());
668
669
		/* Ditto for existing records without a value */
670
		$existingTeam = $this->objFromFixture('DataObjectTest_Team', 'team1');
671
		$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...
672
		$existingTeam->write();
673
		$this->assertEquals(0,
674
			DB::query("SELECT \"CaptainID\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $existingTeam->ID")->value());
675
	}
676
677
	public function testCanAccessHasOneObjectsAsMethods() {
678
		/* If you have a has_one relation 'Captain' on $obj, and you set the $obj->CaptainID = (ID), then the
679
		 * object itself should be accessible as $obj->Captain() */
680
		$team = $this->objFromFixture('DataObjectTest_Team', 'team1');
681
		$captainID = $this->idFromFixture('DataObjectTest_Player', 'captain1');
682
683
		$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...
684
		$this->assertNotNull($team->Captain());
685
		$this->assertEquals($captainID, $team->Captain()->ID);
686
687
		// Test for polymorphic has_one relations
688
		$fan = $this->objFromFixture('DataObjectTest_Fan', 'fan1');
689
		$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...
690
		$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...
691
		$this->assertNotNull($fan->Favourite());
692
		$this->assertEquals($team->ID, $fan->Favourite()->ID);
693
		$this->assertInstanceOf($team->class, $fan->Favourite());
694
	}
695
696
	public function testFieldNamesThatMatchMethodNamesWork() {
697
		/* Check that a field name that corresponds to a method on DataObject will still work */
698
		$obj = new DataObjectTest_Fixture();
699
		$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...
700
		$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...
701
		$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...
702
		$obj->write();
703
704
		$this->assertNotNull($obj->ID);
705
		$this->assertEquals('value1',
706
			DB::query("SELECT \"Data\" FROM \"DataObjectTest_Fixture\" WHERE \"ID\" = $obj->ID")->value());
707
		$this->assertEquals('value2',
708
			DB::query("SELECT \"DbObject\" FROM \"DataObjectTest_Fixture\" WHERE \"ID\" = $obj->ID")->value());
709
		$this->assertEquals('value3',
710
			DB::query("SELECT \"Duplicate\" FROM \"DataObjectTest_Fixture\" WHERE \"ID\" = $obj->ID")->value());
711
	}
712
713
	/**
714
	 * @todo Re-enable all test cases for field existence after behaviour has been fixed
715
	 */
716
	public function testFieldExistence() {
717
		$teamInstance = $this->objFromFixture('DataObjectTest_Team', 'team1');
718
		$teamSingleton = singleton('DataObjectTest_Team');
719
720
		$subteamInstance = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam1');
721
		$subteamSingleton = singleton('DataObjectTest_SubTeam');
0 ignored issues
show
Unused Code introduced by
$subteamSingleton is not used, you could remove the assignment.

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

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

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

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

Loading history...
722
723
		/* hasField() singleton checks */
724
		$this->assertTrue($teamSingleton->hasField('ID'),
725
			'hasField() finds built-in fields in singletons');
726
		$this->assertTrue($teamSingleton->hasField('Title'),
727
			'hasField() finds custom fields in singletons');
728
729
		/* hasField() instance checks */
730
		$this->assertFalse($teamInstance->hasField('NonExistingField'),
731
			'hasField() doesnt find non-existing fields in instances');
732
		$this->assertTrue($teamInstance->hasField('ID'),
733
			'hasField() finds built-in fields in instances');
734
		$this->assertTrue($teamInstance->hasField('Created'),
735
			'hasField() finds built-in fields in instances');
736
		$this->assertTrue($teamInstance->hasField('DatabaseField'),
737
			'hasField() finds custom fields in instances');
738
		//$this->assertFalse($teamInstance->hasField('SubclassDatabaseField'),
739
		//'hasField() doesnt find subclass fields in parentclass instances');
740
		$this->assertTrue($teamInstance->hasField('DynamicField'),
741
			'hasField() finds dynamic getters in instances');
742
		$this->assertTrue($teamInstance->hasField('HasOneRelationshipID'),
743
			'hasField() finds foreign keys in instances');
744
		$this->assertTrue($teamInstance->hasField('ExtendedDatabaseField'),
745
			'hasField() finds extended fields in instances');
746
		$this->assertTrue($teamInstance->hasField('ExtendedHasOneRelationshipID'),
747
			'hasField() finds extended foreign keys in instances');
748
		//$this->assertTrue($teamInstance->hasField('ExtendedDynamicField'),
749
		//'hasField() includes extended dynamic getters in instances');
750
751
		/* hasField() subclass checks */
752
		$this->assertTrue($subteamInstance->hasField('ID'),
753
			'hasField() finds built-in fields in subclass instances');
754
		$this->assertTrue($subteamInstance->hasField('Created'),
755
			'hasField() finds built-in fields in subclass instances');
756
		$this->assertTrue($subteamInstance->hasField('DatabaseField'),
757
			'hasField() finds custom fields in subclass instances');
758
		$this->assertTrue($subteamInstance->hasField('SubclassDatabaseField'),
759
			'hasField() finds custom fields in subclass instances');
760
		$this->assertTrue($subteamInstance->hasField('DynamicField'),
761
			'hasField() finds dynamic getters in subclass instances');
762
		$this->assertTrue($subteamInstance->hasField('HasOneRelationshipID'),
763
			'hasField() finds foreign keys in subclass instances');
764
		$this->assertTrue($subteamInstance->hasField('ExtendedDatabaseField'),
765
			'hasField() finds extended fields in subclass instances');
766
		$this->assertTrue($subteamInstance->hasField('ExtendedHasOneRelationshipID'),
767
			'hasField() finds extended foreign keys in subclass instances');
768
769
		/* hasDatabaseField() singleton checks */
770
		//$this->assertTrue($teamSingleton->hasDatabaseField('ID'),
771
		//'hasDatabaseField() finds built-in fields in singletons');
772
		$this->assertTrue($teamSingleton->hasDatabaseField('Title'),
773
			'hasDatabaseField() finds custom fields in singletons');
774
775
		/* hasDatabaseField() instance checks */
776
		$this->assertFalse($teamInstance->hasDatabaseField('NonExistingField'),
777
			'hasDatabaseField() doesnt find non-existing fields in instances');
778
		//$this->assertTrue($teamInstance->hasDatabaseField('ID'),
779
		//'hasDatabaseField() finds built-in fields in instances');
780
		$this->assertTrue($teamInstance->hasDatabaseField('Created'),
781
			'hasDatabaseField() finds built-in fields in instances');
782
		$this->assertTrue($teamInstance->hasDatabaseField('DatabaseField'),
783
			'hasDatabaseField() finds custom fields in instances');
784
		$this->assertFalse($teamInstance->hasDatabaseField('SubclassDatabaseField'),
785
			'hasDatabaseField() doesnt find subclass fields in parentclass instances');
786
		//$this->assertFalse($teamInstance->hasDatabaseField('DynamicField'),
787
		//'hasDatabaseField() doesnt dynamic getters in instances');
788
		$this->assertTrue($teamInstance->hasDatabaseField('HasOneRelationshipID'),
789
			'hasDatabaseField() finds foreign keys in instances');
790
		$this->assertTrue($teamInstance->hasDatabaseField('ExtendedDatabaseField'),
791
			'hasDatabaseField() finds extended fields in instances');
792
		$this->assertTrue($teamInstance->hasDatabaseField('ExtendedHasOneRelationshipID'),
793
			'hasDatabaseField() finds extended foreign keys in instances');
794
		$this->assertFalse($teamInstance->hasDatabaseField('ExtendedDynamicField'),
795
			'hasDatabaseField() doesnt include extended dynamic getters in instances');
796
797
		/* hasDatabaseField() subclass checks */
798
		$this->assertTrue($subteamInstance->hasDatabaseField('DatabaseField'),
799
			'hasField() finds custom fields in subclass instances');
800
		$this->assertTrue($subteamInstance->hasDatabaseField('SubclassDatabaseField'),
801
			'hasField() finds custom fields in subclass instances');
802
803
	}
804
805
	/**
806
	 * @todo Re-enable all test cases for field inheritance aggregation after behaviour has been fixed
807
	 */
808
	public function testFieldInheritance() {
809
		$teamInstance = $this->objFromFixture('DataObjectTest_Team', 'team1');
810
		$subteamInstance = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam1');
811
812
		$this->assertEquals(
813
			array_keys($teamInstance->inheritedDatabaseFields()),
814
			array(
815
				//'ID',
816
				//'ClassName',
817
				//'Created',
818
				//'LastEdited',
819
				'Title',
820
				'DatabaseField',
821
				'ExtendedDatabaseField',
822
				'CaptainID',
823
				'HasOneRelationshipID',
824
				'ExtendedHasOneRelationshipID'
825
			),
826
			'inheritedDatabaseFields() contains all fields defined on instance: base, extended and foreign keys'
827
		);
828
829
		$this->assertEquals(
830
			array_keys(DataObject::database_fields('DataObjectTest_Team', false)),
831
			array(
832
				//'ID',
833
				'ClassName',
834
				'LastEdited',
835
				'Created',
836
				'Title',
837
				'DatabaseField',
838
				'ExtendedDatabaseField',
839
				'CaptainID',
840
				'HasOneRelationshipID',
841
				'ExtendedHasOneRelationshipID'
842
			),
843
			'databaseFields() contains only fields defined on instance, including base, extended and foreign keys'
844
		);
845
846
		$this->assertEquals(
847
			array_keys($subteamInstance->inheritedDatabaseFields()),
848
			array(
849
				//'ID',
850
				//'ClassName',
851
				//'Created',
852
				//'LastEdited',
853
				'SubclassDatabaseField',
854
				'ParentTeamID',
855
				'Title',
856
				'DatabaseField',
857
				'ExtendedDatabaseField',
858
				'CaptainID',
859
				'HasOneRelationshipID',
860
				'ExtendedHasOneRelationshipID',
861
			),
862
			'inheritedDatabaseFields() on subclass contains all fields, including base, extended  and foreign keys'
863
		);
864
865
		$this->assertEquals(
866
			array_keys(DataObject::database_fields('DataObjectTest_SubTeam', false)),
867
			array(
868
				'SubclassDatabaseField',
869
				'ParentTeamID',
870
			),
871
			'databaseFields() on subclass contains only fields defined on instance'
872
		);
873
	}
874
875
	public function testSearchableFields() {
876
		$player = $this->objFromFixture('DataObjectTest_Player', 'captain1');
877
		$fields = $player->searchableFields();
878
		$this->assertArrayHasKey(
879
			'IsRetired',
880
			$fields,
881
			'Fields defined by $searchable_fields static are correctly detected'
882
		);
883
		$this->assertArrayHasKey(
884
			'ShirtNumber',
885
			$fields,
886
			'Fields defined by $searchable_fields static are correctly detected'
887
		);
888
889
		$team = $this->objFromFixture('DataObjectTest_Team', 'team1');
890
		$fields = $team->searchableFields();
891
		$this->assertArrayHasKey(
892
			'Title',
893
			$fields,
894
			'Fields can be inherited from the $summary_fields static, including methods called on fields'
895
		);
896
		$this->assertArrayHasKey(
897
			'Captain.ShirtNumber',
898
			$fields,
899
			'Fields on related objects can be inherited from the $summary_fields static'
900
		);
901
		$this->assertArrayHasKey(
902
			'Captain.FavouriteTeam.Title',
903
			$fields,
904
			'Fields on related objects can be inherited from the $summary_fields static'
905
		);
906
907
		$testObj = new DataObjectTest_Fixture();
908
		$fields = $testObj->searchableFields();
909
		$this->assertEmpty($fields);
910
	}
911
912
	public function testSummaryFieldsCustomLabels() {
913
		$team = $this->objFromFixture('DataObjectTest_Team', 'team1');
914
		$summaryFields = $team->summaryFields();
915
916
		$this->assertEquals(
917
			'Custom Title',
918
			$summaryFields['Title'],
919
			'Custom title is preserved'
920
		);
921
922
		$this->assertEquals(
923
			'Captain\'s shirt number',
924
			$summaryFields['Captain.ShirtNumber'],
925
			'Custom title on relation is preserved'
926
		);
927
	}
928
929
	public function testDataObjectUpdate() {
930
		/* update() calls can use the dot syntax to reference has_one relations and other methods that return
931
		 * objects */
932
		$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
933
		$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...
934
935
		$team1->update(array(
936
			'DatabaseField' => 'Something',
937
			'Captain.FirstName' => 'Jim',
938
			'Captain.Email' => '[email protected]',
939
			'Captain.FavouriteTeam.Title' => 'New and improved team 1',
940
		));
941
942
		/* Test the simple case of updating fields on the object itself */
943
		$this->assertEquals('Something', $team1->DatabaseField);
944
945
		/* Setting Captain.Email and Captain.FirstName will have updated DataObjectTest_Captain.captain1 in
946
		 * the database.  Although update() doesn't usually write, it does write related records automatically. */
947
		$captain1 = $this->objFromFixture('DataObjectTest_Player', 'captain1');
948
		$this->assertEquals('Jim', $captain1->FirstName);
949
		$this->assertEquals('[email protected]', $captain1->Email);
950
951
		/* Jim's favourite team is team 1; we need to reload the object to the the change that setting Captain.
952
		 * FavouriteTeam.Title made */
953
		$reloadedTeam1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
954
		$this->assertEquals('New and improved team 1', $reloadedTeam1->Title);
955
	}
956
957
	public function testDataObjectUpdateNew() {
958
		/* update() calls can use the dot syntax to reference has_one relations and other methods that return
959
		 * objects */
960
		$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
961
		$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...
962
963
		$team1->update(array(
964
			'Captain.FirstName' => 'Jim',
965
			'Captain.FavouriteTeam.Title' => 'New and improved team 1',
966
		));
967
		/* Test that the captain ID has been updated */
968
		$this->assertGreaterThan(0, $team1->CaptainID);
969
970
		/* Fetch the newly created captain */
971
		$captain1 = DataObjectTest_Player::get()->byID($team1->CaptainID);
972
		$this->assertEquals('Jim', $captain1->FirstName);
973
974
		/* Grab the favourite team and make sure it has the correct values */
975
		$reloadedTeam1 = $captain1->FavouriteTeam();
976
		$this->assertEquals($reloadedTeam1->ID, $captain1->FavouriteTeamID);
977
		$this->assertEquals('New and improved team 1', $reloadedTeam1->Title);
978
	}
979
980
	public function testWritingInvalidDataObjectThrowsException() {
981
		$validatedObject = new DataObjectTest_ValidatedObject();
982
983
		$this->setExpectedException('ValidationException');
984
		$validatedObject->write();
985
	}
986
987
	public function testWritingValidDataObjectDoesntThrowException() {
988
		$validatedObject = new DataObjectTest_ValidatedObject();
989
		$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...
990
991
		$validatedObject->write();
992
		$this->assertTrue($validatedObject->isInDB(), "Validated object was not saved to database");
993
	}
994
995
	public function testSubclassCreation() {
996
		/* Creating a new object of a subclass should set the ClassName field correctly */
997
		$obj = new DataObjectTest_SubTeam();
998
		$obj->write();
999
		$this->assertEquals("DataObjectTest_SubTeam",
1000
			DB::query("SELECT \"ClassName\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $obj->ID")->value());
1001
	}
1002
1003
	public function testForceInsert() {
1004
		/* If you set an ID on an object and pass forceInsert = true, then the object should be correctly created */
1005
		$conn = DB::get_conn();
1006
		if(method_exists($conn, 'allowPrimaryKeyEditing')) $conn->allowPrimaryKeyEditing('DataObjectTest_Team', true);
1007
		$obj = new DataObjectTest_SubTeam();
1008
		$obj->ID = 1001;
1009
		$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...
1010
		$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...
1011
		$obj->write(false, true);
1012
		if(method_exists($conn, 'allowPrimaryKeyEditing')) $conn->allowPrimaryKeyEditing('DataObjectTest_Team', false);
1013
1014
		$this->assertEquals("DataObjectTest_SubTeam",
1015
			DB::query("SELECT \"ClassName\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $obj->ID")->value());
1016
1017
		/* Check that it actually saves to the database with the correct ID */
1018
		$this->assertEquals("1001", DB::query(
1019
			"SELECT \"ID\" FROM \"DataObjectTest_SubTeam\" WHERE \"SubclassDatabaseField\" = 'asdfasdf'")->value());
1020
		$this->assertEquals("1001",
1021
			DB::query("SELECT \"ID\" FROM \"DataObjectTest_Team\" WHERE \"Title\" = 'asdfasdf'")->value());
1022
	}
1023
1024
	public function TestHasOwnTable() {
1025
		/* Test DataObject::has_own_table() returns true if the object has $has_one or $db values */
1026
		$this->assertTrue(DataObject::has_own_table("DataObjectTest_Player"));
1027
		$this->assertTrue(DataObject::has_own_table("DataObjectTest_Team"));
1028
		$this->assertTrue(DataObject::has_own_table("DataObjectTest_Fixture"));
1029
1030
		/* Root DataObject that always have a table, even if they lack both $db and $has_one */
1031
		$this->assertTrue(DataObject::has_own_table("DataObjectTest_FieldlessTable"));
1032
1033
		/* Subclasses without $db or $has_one don't have a table */
1034
		$this->assertFalse(DataObject::has_own_table("DataObjectTest_FieldlessSubTable"));
1035
1036
		/* Return false if you don't pass it a subclass of DataObject */
1037
		$this->assertFalse(DataObject::has_own_table("DataObject"));
1038
		$this->assertFalse(DataObject::has_own_table("ViewableData"));
1039
		$this->assertFalse(DataObject::has_own_table("ThisIsntADataObject"));
1040
	}
1041
1042
	public function testMerge() {
1043
		// test right merge of subclasses
1044
		$left = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam1');
1045
		$right = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam2_with_player_relation');
1046
		$leftOrigID = $left->ID;
1047
		$left->merge($right, 'right', false, false);
1048
		$this->assertEquals(
1049
			$left->Title,
1050
			'Subteam 2',
1051
			'merge() with "right" priority overwrites fields with existing values on subclasses'
1052
		);
1053
		$this->assertEquals(
1054
			$left->ID,
1055
			$leftOrigID,
1056
			'merge() with "right" priority doesnt overwrite database ID'
1057
		);
1058
1059
		// test overwriteWithEmpty flag on existing left values
1060
		$left = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam2_with_player_relation');
1061
		$right = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam3_with_empty_fields');
1062
		$left->merge($right, 'right', false, true);
1063
		$this->assertEquals(
1064
			$left->Title,
1065
			'Subteam 3',
1066
			'merge() with $overwriteWithEmpty overwrites non-empty fields on left object'
1067
		);
1068
1069
		// test overwriteWithEmpty flag on empty left values
1070
		$left = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam1');
1071
		// $SubclassDatabaseField is empty on here
1072
		$right = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam2_with_player_relation');
1073
		$left->merge($right, 'right', false, true);
1074
		$this->assertEquals(
1075
			$left->SubclassDatabaseField,
1076
			NULL,
1077
			'merge() with $overwriteWithEmpty overwrites empty fields on left object'
1078
		);
1079
1080
		// @todo test "left" priority flag
1081
		// @todo test includeRelations flag
1082
		// @todo test includeRelations in combination with overwriteWithEmpty
1083
		// @todo test has_one relations
1084
		// @todo test has_many and many_many relations
1085
	}
1086
1087
	public function testPopulateDefaults() {
1088
		$obj = new DataObjectTest_Fixture();
1089
		$this->assertEquals(
1090
			$obj->MyFieldWithDefault,
1091
			'Default Value',
1092
			'Defaults are populated for in-memory object from $defaults array'
1093
		);
1094
1095
		$this->assertEquals(
1096
			$obj->MyFieldWithAltDefault,
1097
			'Default Value',
1098
			'Defaults are populated from overloaded populateDefaults() method'
1099
		);
1100
	}
1101
1102
	protected function makeAccessible($object, $method) {
1103
		$reflectionMethod = new ReflectionMethod($object, $method);
1104
		$reflectionMethod->setAccessible(true);
1105
		return $reflectionMethod;
1106
	}
1107
1108 View Code Duplication
	public function testValidateModelDefinitionsFailsWithArray() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1109
		Config::nest();
1110
1111
		$object = new DataObjectTest_Team;
1112
		$method = $this->makeAccessible($object, 'validateModelDefinitions');
1113
1114
		Config::inst()->update('DataObjectTest_Team', 'has_one', array('NotValid' => array('NoArraysAllowed')));
1115
		$this->setExpectedException('LogicException');
1116
1117
		try {
1118
			$method->invoke($object);
1119
		} catch(Exception $e) {
1120
			Config::unnest(); // Catch the exception so we can unnest config before failing the test
1121
			throw $e;
1122
		}
1123
	}
1124
1125 View Code Duplication
	public function testValidateModelDefinitionsFailsWithIntKey() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1126
		Config::nest();
1127
1128
		$object = new DataObjectTest_Team;
1129
		$method = $this->makeAccessible($object, 'validateModelDefinitions');
1130
1131
		Config::inst()->update('DataObjectTest_Team', 'has_many', array(12 => 'DataObjectTest_Player'));
1132
		$this->setExpectedException('LogicException');
1133
1134
		try {
1135
			$method->invoke($object);
1136
		} catch(Exception $e) {
1137
			Config::unnest(); // Catch the exception so we can unnest config before failing the test
1138
			throw $e;
1139
		}
1140
	}
1141
1142 View Code Duplication
	public function testValidateModelDefinitionsFailsWithIntValue() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1143
		Config::nest();
1144
1145
		$object = new DataObjectTest_Team;
1146
		$method = $this->makeAccessible($object, 'validateModelDefinitions');
1147
1148
		Config::inst()->update('DataObjectTest_Team', 'many_many', array('Players' => 12));
1149
		$this->setExpectedException('LogicException');
1150
1151
		try {
1152
			$method->invoke($object);
1153
		} catch(Exception $e) {
1154
			Config::unnest(); // Catch the exception so we can unnest config before failing the test
1155
			throw $e;
1156
		}
1157
	}
1158
1159
	/**
1160
	 * many_many_extraFields is allowed to have an array value, so shouldn't throw an exception
1161
	 */
1162 View Code Duplication
	public function testValidateModelDefinitionsPassesWithExtraFields() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1163
		Config::nest();
1164
1165
		$object = new DataObjectTest_Team;
1166
		$method = $this->makeAccessible($object, 'validateModelDefinitions');
1167
1168
		Config::inst()->update('DataObjectTest_Team', 'many_many_extraFields',
1169
			array('Relations' => array('Price' => 'Int')));
1170
1171
		try {
1172
			$method->invoke($object);
1173
		} catch(Exception $e) {
1174
			Config::unnest();
1175
			$this->fail('Exception should not be thrown');
1176
			throw $e;
1177
		}
1178
1179
		Config::unnest();
1180
	}
1181
1182
	public function testNewClassInstance() {
1183
		$dataObject = $this->objFromFixture('DataObjectTest_Team', 'team1');
1184
		$changedDO = $dataObject->newClassInstance('DataObjectTest_SubTeam');
1185
		$changedFields = $changedDO->getChangedFields();
1186
1187
		// Don't write the record, it will reset changed fields
1188
		$this->assertInstanceOf('DataObjectTest_SubTeam', $changedDO);
1189
		$this->assertEquals($changedDO->ClassName, 'DataObjectTest_SubTeam');
1190
		$this->assertContains('ClassName', array_keys($changedFields));
1191
		$this->assertEquals($changedFields['ClassName']['before'], 'DataObjectTest_Team');
1192
		$this->assertEquals($changedFields['ClassName']['after'], 'DataObjectTest_SubTeam');
1193
1194
		$changedDO->write();
1195
1196
		$this->assertInstanceOf('DataObjectTest_SubTeam', $changedDO);
1197
		$this->assertEquals($changedDO->ClassName, 'DataObjectTest_SubTeam');
1198
	}
1199
1200
	public function testMultipleManyManyWithSameClass() {
1201
		$team = $this->objFromFixture('DataObjectTest_Team', 'team1');
1202
		$sponsors = $team->Sponsors();
1203
		$equipmentSuppliers = $team->EquipmentSuppliers();
1204
1205
		// Check that DataObject::many_many() works as expected
1206
		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...
1207
		$this->assertEquals('DataObjectTest_Team', $class,
1208
			'DataObject::many_many() didn\'t find the correct base class');
1209
		$this->assertEquals('DataObjectTest_EquipmentCompany', $targetClass,
1210
			'DataObject::many_many() didn\'t find the correct target class for the relation');
1211
		$this->assertEquals('DataObjectTest_EquipmentCompany_SponsoredTeams', $joinTable,
1212
			'DataObject::many_many() didn\'t find the correct relation table');
1213
1214
		// Check that ManyManyList still works
1215
		$this->assertEquals(2, $sponsors->count(), 'Rows are missing from relation');
1216
		$this->assertEquals(1, $equipmentSuppliers->count(), 'Rows are missing from relation');
1217
1218
		// Check everything works when no relation is present
1219
		$teamWithoutSponsor = $this->objFromFixture('DataObjectTest_Team', 'team3');
1220
		$this->assertInstanceOf('ManyManyList', $teamWithoutSponsor->Sponsors());
1221
		$this->assertEquals(0, $teamWithoutSponsor->Sponsors()->count());
1222
1223
		// Check many_many_extraFields still works
1224
		$equipmentCompany = $this->objFromFixture('DataObjectTest_EquipmentCompany', 'equipmentcompany1');
1225
		$equipmentCompany->SponsoredTeams()->add($teamWithoutSponsor, array('SponsorFee' => 1000));
1226
		$sponsoredTeams = $equipmentCompany->SponsoredTeams();
1227
		$this->assertEquals(1000, $sponsoredTeams->byID($teamWithoutSponsor->ID)->SponsorFee,
1228
			'Data from many_many_extraFields was not stored/extracted correctly');
1229
1230
		// Check subclasses correctly inherit multiple many_manys
1231
		$subTeam = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam1');
1232
		$this->assertEquals(2, $subTeam->Sponsors()->count(),
1233
			'Child class did not inherit multiple many_manys');
1234
		$this->assertEquals(1, $subTeam->EquipmentSuppliers()->count(),
1235
			'Child class did not inherit multiple many_manys');
1236
		// Team 2 has one EquipmentCompany sponsor and one SubEquipmentCompany
1237
		$team2 = $this->objFromFixture('DataObjectTest_Team', 'team2');
1238
		$this->assertEquals(2, $team2->Sponsors()->count(),
1239
			'Child class did not inherit multiple belongs_many_manys');
1240
1241
		// Check many_many_extraFields also works from the belongs_many_many side
1242
		$sponsors = $team2->Sponsors();
1243
		$sponsors->add($equipmentCompany, array('SponsorFee' => 750));
1244
		$this->assertEquals(750, $sponsors->byID($equipmentCompany->ID)->SponsorFee,
1245
			'Data from many_many_extraFields was not stored/extracted correctly');
1246
1247
		$subEquipmentCompany = $this->objFromFixture('DataObjectTest_SubEquipmentCompany', 'subequipmentcompany1');
1248
		$subTeam->Sponsors()->add($subEquipmentCompany, array('SponsorFee' => 1200));
1249
		$this->assertEquals(1200, $subTeam->Sponsors()->byID($subEquipmentCompany->ID)->SponsorFee,
1250
			'Data from inherited many_many_extraFields was not stored/extracted correctly');
1251
	}
1252
1253
	public function testManyManyExtraFields() {
1254
		$player = $this->objFromFixture('DataObjectTest_Player', 'player1');
1255
		$team = $this->objFromFixture('DataObjectTest_Team', 'team1');
1256
1257
		// Get all extra fields
1258
		$teamExtraFields = $team->manyManyExtraFields();
1259
		$this->assertEquals(array(
1260
			'Players' => array('Position' => 'Varchar(100)')
1261
		), $teamExtraFields);
1262
1263
		// Ensure fields from parent classes are included
1264
		$subTeam = singleton('DataObjectTest_SubTeam');
1265
		$teamExtraFields = $subTeam->manyManyExtraFields();
1266
		$this->assertEquals(array(
1267
			'Players' => array('Position' => 'Varchar(100)'),
1268
			'FormerPlayers' => array('Position' => 'Varchar(100)')
1269
		), $teamExtraFields);
1270
1271
		// Extra fields are immediately available on the Team class (defined in $many_many_extraFields)
1272
		$teamExtraFields = $team->manyManyExtraFieldsForComponent('Players');
1273
		$this->assertEquals($teamExtraFields, array(
1274
			'Position' => 'Varchar(100)'
1275
		));
1276
1277
		// We'll have to go through the relation to get the extra fields on Player
1278
		$playerExtraFields = $player->manyManyExtraFieldsForComponent('Teams');
1279
		$this->assertEquals($playerExtraFields, array(
1280
			'Position' => 'Varchar(100)'
1281
		));
1282
1283
		// Iterate through a many-many relationship and confirm that extra fields are included
1284
		$newTeam = new DataObjectTest_Team();
1285
		$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...
1286
		$newTeam->write();
1287
		$newTeamID = $newTeam->ID;
1288
1289
		$newPlayer = new DataObjectTest_Player();
1290
		$newPlayer->FirstName = "Sam";
1291
		$newPlayer->Surname = "Minnee";
1292
		$newPlayer->write();
1293
1294
		// The idea of Sam as a prop is essentially humourous.
1295
		$newTeam->Players()->add($newPlayer, array("Position" => "Prop"));
1296
1297
		// Requery and uncache everything
1298
		$newTeam->flushCache();
1299
		$newTeam = DataObject::get_by_id('DataObjectTest_Team', $newTeamID);
1300
1301
		// Check that the Position many_many_extraField is extracted.
1302
		$player = $newTeam->Players()->First();
1303
		$this->assertEquals('Sam', $player->FirstName);
1304
		$this->assertEquals("Prop", $player->Position);
1305
1306
		// Check that ordering a many-many relation by an aggregate column doesn't fail
1307
		$player = $this->objFromFixture('DataObjectTest_Player', 'player2');
1308
		$player->Teams()->sort("count(DISTINCT \"DataObjectTest_Team_Players\".\"DataObjectTest_PlayerID\") DESC");
1309
	}
1310
1311
	/**
1312
	 * Check that the queries generated for many-many relation queries can have unlimitedRowCount
1313
	 * called on them.
1314
	 */
1315
	public function testManyManyUnlimitedRowCount() {
1316
		$player = $this->objFromFixture('DataObjectTest_Player', 'player2');
1317
		// TODO: What's going on here?
1318
		$this->assertEquals(2, $player->Teams()->dataQuery()->query()->unlimitedRowCount());
1319
	}
1320
1321
	/**
1322
	 * Tests that singular_name() generates sensible defaults.
1323
	 */
1324
	public function testSingularName() {
1325
		$assertions = array(
1326
			'DataObjectTest_Player'       => 'Data Object Test Player',
1327
			'DataObjectTest_Team'         => 'Data Object Test Team',
1328
			'DataObjectTest_Fixture'      => 'Data Object Test Fixture'
1329
		);
1330
1331
		foreach($assertions as $class => $expectedSingularName) {
1332
			$this->assertEquals(
1333
				$expectedSingularName,
1334
				singleton($class)->singular_name(),
1335
				"Assert that the singular_name for '$class' is correct."
1336
			);
1337
		}
1338
	}
1339
1340
	/**
1341
	 * Tests that plural_name() generates sensible defaults.
1342
	 */
1343
	public function testPluralName() {
1344
		$assertions = array(
1345
			'DataObjectTest_Player'       => 'Data Object Test Players',
1346
			'DataObjectTest_Team'         => 'Data Object Test Teams',
1347
			'DataObjectTest_Fixture'      => 'Data Object Test Fixtures',
1348
			'DataObjectTest_Play'         => 'Data Object Test Plays',
1349
			'DataObjectTest_Bogey'        => 'Data Object Test Bogeys',
1350
			'DataObjectTest_Ploy'         => 'Data Object Test Ploys',
1351
		);
1352
1353
		foreach($assertions as $class => $expectedPluralName) {
1354
			$this->assertEquals(
1355
				$expectedPluralName,
1356
				singleton($class)->plural_name(),
1357
				"Assert that the plural_name for '$class' is correct."
1358
			);
1359
		}
1360
	}
1361
1362
	public function testHasDatabaseField() {
1363
		$team = singleton('DataObjectTest_Team');
1364
		$subteam = singleton('DataObjectTest_SubTeam');
1365
1366
		$this->assertTrue(
1367
			$team->hasDatabaseField('Title'),
1368
			"hasOwnDatabaseField() works with \$db fields"
1369
		);
1370
		$this->assertTrue(
1371
			$team->hasDatabaseField('CaptainID'),
1372
			"hasOwnDatabaseField() works with \$has_one fields"
1373
		);
1374
		$this->assertFalse(
1375
			$team->hasDatabaseField('NonExistentField'),
1376
			"hasOwnDatabaseField() doesn't detect non-existend fields"
1377
		);
1378
		$this->assertTrue(
1379
			$team->hasDatabaseField('ExtendedDatabaseField'),
1380
			"hasOwnDatabaseField() works with extended fields"
1381
		);
1382
		$this->assertFalse(
1383
			$team->hasDatabaseField('SubclassDatabaseField'),
1384
			"hasOwnDatabaseField() doesn't pick up fields in subclasses on parent class"
1385
		);
1386
1387
		$this->assertTrue(
1388
			$subteam->hasDatabaseField('SubclassDatabaseField'),
1389
			"hasOwnDatabaseField() picks up fields in subclasses"
1390
		);
1391
1392
	}
1393
1394
	public function testFieldTypes() {
1395
		$obj = new DataObjectTest_Fixture();
1396
		$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...
1397
		$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...
1398
		$obj->write();
1399
		$obj->flushCache();
1400
1401
		$obj = DataObject::get_by_id('DataObjectTest_Fixture', $obj->ID);
1402
		$this->assertEquals('1988-01-02', $obj->DateField);
1403
		$this->assertEquals('1988-03-04 06:30:00', $obj->DatetimeField);
1404
	}
1405
1406
	public function testTwoSubclassesWithTheSameFieldNameWork() {
1407
		// Create two objects of different subclasses, setting the values of fields that are
1408
		// defined separately in each subclass
1409
		$obj1 = new DataObjectTest_SubTeam();
1410
		$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...
1411
		$obj2 = new OtherSubclassWithSameField();
1412
		$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...
1413
1414
		// Write them to the database
1415
		$obj1->write();
1416
		$obj2->write();
1417
1418
		// Check that the values of those fields are properly read from the database
1419
		$values = DataObject::get("DataObjectTest_Team", "\"DataObjectTest_Team\".\"ID\" IN
1420
			($obj1->ID, $obj2->ID)")->column("SubclassDatabaseField");
1421
		$this->assertEquals(array_intersect($values, array('obj1', 'obj2')), $values);
1422
	}
1423
1424
	public function testClassNameSetForNewObjects() {
1425
		$d = new DataObjectTest_Player();
1426
		$this->assertEquals('DataObjectTest_Player', $d->ClassName);
1427
	}
1428
1429
	public function testHasValue() {
1430
		$team = new DataObjectTest_Team();
1431
		$this->assertFalse($team->hasValue('Title', null, false));
1432
		$this->assertFalse($team->hasValue('DatabaseField', null, false));
1433
1434
		$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...
1435
		$this->assertTrue($team->hasValue('Title', null, false));
1436
		$this->assertFalse($team->hasValue('DatabaseField', null, false));
1437
1438
		$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...
1439
		$this->assertTrue($team->hasValue('Title', null, false));
1440
		$this->assertFalse (
1441
			$team->hasValue('DatabaseField', null, false),
1442
			'Test that a blank paragraph on a HTML field is not a valid value.'
1443
		);
1444
1445
		$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...
1446
		$this->assertTrue (
1447
			$team->hasValue('Title', null, false),
1448
			'Test that an empty paragraph is a value for non-HTML fields.'
1449
		);
1450
1451
		$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...
1452
		$this->assertTrue($team->hasValue('Title', null, false));
1453
		$this->assertTrue($team->hasValue('DatabaseField', null, false));
1454
	}
1455
1456
	public function testHasMany() {
1457
		$company = new DataObjectTest_Company();
1458
1459
		$this->assertEquals (
1460
			array (
1461
				'CurrentStaff'     => 'DataObjectTest_Staff',
1462
				'PreviousStaff'    => 'DataObjectTest_Staff'
1463
			),
1464
			$company->hasMany(),
1465
			'has_many strips field name data by default.'
1466
		);
1467
1468
		$this->assertEquals (
1469
			'DataObjectTest_Staff',
1470
			$company->hasManyComponent('CurrentStaff'),
1471
			'has_many strips field name data by default on single relationships.'
1472
		);
1473
1474
		$this->assertEquals (
1475
			array (
1476
				'CurrentStaff'     => 'DataObjectTest_Staff.CurrentCompany',
1477
				'PreviousStaff'    => 'DataObjectTest_Staff.PreviousCompany'
1478
			),
1479
			$company->hasMany(null, false),
1480
			'has_many returns field name data when $classOnly is false.'
1481
		);
1482
1483
		$this->assertEquals (
1484
			'DataObjectTest_Staff.CurrentCompany',
1485
			$company->hasManyComponent('CurrentStaff', false),
1486
			'has_many returns field name data on single records when $classOnly is false.'
1487
		);
1488
	}
1489
1490
	public function testGetRemoteJoinField() {
1491
		$company = new DataObjectTest_Company();
1492
1493
		$staffJoinField = $company->getRemoteJoinField('CurrentStaff', 'has_many', $polymorphic);
1494
		$this->assertEquals('CurrentCompanyID', $staffJoinField);
1495
		$this->assertFalse($polymorphic, 'DataObjectTest_Company->CurrentStaff is not polymorphic');
1496
		$previousStaffJoinField = $company->getRemoteJoinField('PreviousStaff', 'has_many', $polymorphic);
1497
		$this->assertEquals('PreviousCompanyID', $previousStaffJoinField);
1498
		$this->assertFalse($polymorphic, 'DataObjectTest_Company->PreviousStaff is not polymorphic');
1499
1500
		$ceo = new DataObjectTest_CEO();
1501
1502
		$this->assertEquals('CEOID', $ceo->getRemoteJoinField('Company', 'belongs_to', $polymorphic));
1503
		$this->assertFalse($polymorphic, 'DataObjectTest_CEO->Company is not polymorphic');
1504
		$this->assertEquals('PreviousCEOID', $ceo->getRemoteJoinField('PreviousCompany', 'belongs_to', $polymorphic));
1505
		$this->assertFalse($polymorphic, 'DataObjectTest_CEO->PreviousCompany is not polymorphic');
1506
1507
		$team = new DataObjectTest_Team();
1508
1509
		$this->assertEquals('Favourite', $team->getRemoteJoinField('Fans', 'has_many', $polymorphic));
1510
		$this->assertTrue($polymorphic, 'DataObjectTest_Team->Fans is polymorphic');
1511
		$this->assertEquals('TeamID', $team->getRemoteJoinField('Comments', 'has_many', $polymorphic));
1512
		$this->assertFalse($polymorphic, 'DataObjectTest_Team->Comments is not polymorphic');
1513
	}
1514
1515
	public function testBelongsTo() {
1516
		$company = new DataObjectTest_Company();
1517
		$ceo     = new DataObjectTest_CEO();
1518
1519
		$company->write();
1520
		$ceo->write();
1521
1522
		// Test belongs_to assignment
1523
		$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...
1524
		$company->write();
1525
1526
		$this->assertEquals($company->ID, $ceo->Company()->ID, 'belongs_to returns the right results.');
1527
1528
		// Test automatic creation of class where no assigment exists
1529
		$ceo = new DataObjectTest_CEO();
1530
		$ceo->write();
1531
1532
		$this->assertTrue (
1533
			$ceo->Company() instanceof DataObjectTest_Company,
1534
			'DataObjects across belongs_to relations are automatically created.'
1535
		);
1536
		$this->assertEquals($ceo->ID, $ceo->Company()->CEOID, 'Remote IDs are automatically set.');
1537
1538
		// Write object with components
1539
		$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...
1540
		$ceo->write(false, false, false, true);
1541
		$this->assertTrue($ceo->Company()->isInDB(), 'write() writes belongs_to components to the database.');
1542
1543
		$newCEO = DataObject::get_by_id('DataObjectTest_CEO', $ceo->ID);
1544
		$this->assertEquals (
1545
			$ceo->Company()->ID, $newCEO->Company()->ID, 'belongs_to can be retrieved from the database.'
1546
		);
1547
	}
1548
1549
	public function testBelongsToPolymorphic() {
1550
		$company = new DataObjectTest_Company();
1551
		$ceo     = new DataObjectTest_CEO();
1552
1553
		$company->write();
1554
		$ceo->write();
1555
1556
		// Test belongs_to assignment
1557
		$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...
1558
		$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...
1559
		$company->write();
1560
1561
		$this->assertEquals($company->ID, $ceo->CompanyOwned()->ID, 'belongs_to returns the right results.');
1562
		$this->assertEquals($company->class, $ceo->CompanyOwned()->class, 'belongs_to returns the right results.');
1563
1564
		// Test automatic creation of class where no assigment exists
1565
		$ceo = new DataObjectTest_CEO();
1566
		$ceo->write();
1567
1568
		$this->assertTrue (
1569
			$ceo->CompanyOwned() instanceof DataObjectTest_Company,
1570
			'DataObjects across polymorphic belongs_to relations are automatically created.'
1571
		);
1572
		$this->assertEquals($ceo->ID, $ceo->CompanyOwned()->OwnerID, 'Remote IDs are automatically set.');
1573
		$this->assertInstanceOf($ceo->CompanyOwned()->OwnerClass, $ceo, 'Remote class is automatically  set');
1574
1575
		// Write object with components
1576
		$ceo->write(false, false, false, true);
1577
		$this->assertTrue($ceo->CompanyOwned()->isInDB(), 'write() writes belongs_to components to the database.');
1578
1579
		$newCEO = DataObject::get_by_id('DataObjectTest_CEO', $ceo->ID);
1580
		$this->assertEquals (
1581
			$ceo->CompanyOwned()->ID,
1582
			$newCEO->CompanyOwned()->ID,
1583
			'polymorphic belongs_to can be retrieved from the database.'
1584
		);
1585
	}
1586
1587
	/**
1588
	 * @expectedException LogicException
1589
	 */
1590
	public function testInvalidate() {
1591
		$do = new DataObjectTest_Fixture();
1592
		$do->write();
1593
1594
		$do->delete();
1595
1596
		$do->delete(); // Prohibit invalid object manipulation
1597
		$do->write();
1598
		$do->duplicate();
1599
	}
1600
1601
	public function testToMap() {
1602
		$obj = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam1');
1603
1604
		$map = $obj->toMap();
1605
1606
		$this->assertArrayHasKey('ID', $map, 'Contains base fields');
1607
		$this->assertArrayHasKey('Title', $map, 'Contains fields from parent class');
1608
		$this->assertArrayHasKey('SubclassDatabaseField', $map, 'Contains fields from concrete class');
1609
1610
		$this->assertEquals($obj->ID, $map['ID'],
1611
			'Contains values from base fields');
1612
		$this->assertEquals($obj->Title, $map['Title'],
1613
			'Contains values from parent class fields');
1614
		$this->assertEquals($obj->SubclassDatabaseField, $map['SubclassDatabaseField'],
1615
			'Contains values from concrete class fields');
1616
1617
		$newObj = new DataObjectTest_SubTeam();
0 ignored issues
show
Unused Code introduced by
$newObj is not used, you could remove the assignment.

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

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

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

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

Loading history...
1618
		$this->assertArrayHasKey('Title', $map, 'Contains null fields');
1619
	}
1620
1621
	public function testIsEmpty() {
1622
		$objEmpty = new DataObjectTest_Team();
1623
		$this->assertTrue($objEmpty->isEmpty(), 'New instance without populated defaults is empty');
1624
1625
		$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...
1626
		$this->assertFalse($objEmpty->isEmpty(), 'Zero value in attribute considered non-empty');
1627
	}
1628
1629
	public function testRelField() {
1630
		$captain = $this->objFromFixture('DataObjectTest_Player', 'captain1');
1631
		// Test traversal of a single has_one
1632
		$this->assertEquals("Team 1", $captain->relField('FavouriteTeam.Title'));
1633
		// Test direct field access
1634
		$this->assertEquals("Captain", $captain->relField('FirstName'));
1635
1636
		$player = $this->objFromFixture('DataObjectTest_Player', 'player2');
1637
		// Test that we can traverse more than once, and that arbitrary methods are okay
1638
		$this->assertEquals("Team 1", $player->relField('Teams.First.Title'));
1639
1640
		$newPlayer = new DataObjectTest_Player();
1641
		$this->assertNull($newPlayer->relField('Teams.First.Title'));
1642
1643
		// Test that relField works on db field manipulations
1644
		$comment = $this->objFromFixture('DataObjectTest_TeamComment', 'comment3');
1645
		$this->assertEquals("PHIL IS A UNIQUE GUY, AND COMMENTS ON TEAM2" , $comment->relField('Comment.UpperCase'));
1646
	}
1647
1648
	public function testRelObject() {
1649
		$captain = $this->objFromFixture('DataObjectTest_Player', 'captain1');
1650
1651
		// Test traversal of a single has_one
1652
		$this->assertInstanceOf("Varchar", $captain->relObject('FavouriteTeam.Title'));
1653
		$this->assertEquals("Team 1", $captain->relObject('FavouriteTeam.Title')->getValue());
1654
1655
		// Test direct field access
1656
		$this->assertInstanceOf("Boolean", $captain->relObject('IsRetired'));
1657
		$this->assertEquals(1, $captain->relObject('IsRetired')->getValue());
1658
1659
		$player = $this->objFromFixture('DataObjectTest_Player', 'player2');
1660
		// Test that we can traverse more than once, and that arbitrary methods are okay
1661
		$this->assertInstanceOf("Varchar", $player->relObject('Teams.First.Title'));
1662
		$this->assertEquals("Team 1", $player->relObject('Teams.First.Title')->getValue());
1663
	}
1664
1665
	public function testLateStaticBindingStyle() {
1666
		// Confirm that DataObjectTest_Player::get() operates as excepted
1667
		$this->assertEquals(4, DataObjectTest_Player::get()->Count());
1668
		$this->assertInstanceOf('DataObjectTest_Player', DataObjectTest_Player::get()->First());
1669
1670
		// You can't pass arguments to LSB syntax - use the DataList methods instead.
1671
		$this->setExpectedException('InvalidArgumentException');
1672
		DataObjectTest_Player::get(null, "\"ID\" = 1");
1673
1674
	}
1675
1676
	public function testBrokenLateStaticBindingStyle() {
1677
		// If you call DataObject::get() you have to pass a first argument
1678
		$this->setExpectedException('InvalidArgumentException');
1679
		DataObject::get();
1680
1681
	}
1682
1683
}
1684
1685
class DataObjectTest_Player extends Member implements TestOnly {
1686
	private static $db = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1687
		'IsRetired' => 'Boolean',
1688
		'ShirtNumber' => 'Varchar',
1689
	);
1690
1691
	private static $has_one = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1692
		'FavouriteTeam' => 'DataObjectTest_Team',
1693
	);
1694
1695
	private static $belongs_many_many = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1696
		'Teams' => 'DataObjectTest_Team'
1697
	);
1698
1699
	private static $has_many = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1700
		'Fans' => 'DataObjectTest_Fan.Favourite' // Polymorphic - Player fans
1701
	);
1702
1703
	private static $belongs_to = array (
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1704
		'CompanyOwned'    => 'DataObjectTest_Company.Owner'
1705
	);
1706
1707
	private static $searchable_fields = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1708
		'IsRetired',
1709
		'ShirtNumber'
1710
	);
1711
}
1712
1713
class DataObjectTest_Team extends DataObject implements TestOnly {
1714
1715
	private static $db = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1716
		'Title' => 'Varchar',
1717
		'DatabaseField' => 'HTMLVarchar'
1718
	);
1719
1720
	private static $has_one = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1721
		"Captain" => 'DataObjectTest_Player',
1722
		'HasOneRelationship' => 'DataObjectTest_Player',
1723
	);
1724
1725
	private static $has_many = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1726
		'SubTeams' => 'DataObjectTest_SubTeam',
1727
		'Comments' => 'DataObjectTest_TeamComment',
1728
		'Fans' => 'DataObjectTest_Fan.Favourite' // Polymorphic - Team fans
1729
	);
1730
1731
	private static $many_many = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1732
		'Players' => 'DataObjectTest_Player'
1733
	);
1734
1735
	private static $many_many_extraFields = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1736
		'Players' => array(
1737
			'Position' => 'Varchar(100)'
1738
		)
1739
	);
1740
1741
	private static $belongs_many_many = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1742
		'Sponsors' => 'DataObjectTest_EquipmentCompany.SponsoredTeams',
1743
		'EquipmentSuppliers' => 'DataObjectTest_EquipmentCompany.EquipmentCustomers'
1744
	);
1745
1746
	private static $summary_fields = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1747
		'Title' => 'Custom Title',
1748
		'Title.UpperCase' => 'Title',
1749
		'Captain.ShirtNumber' => 'Captain\'s shirt number',
1750
		'Captain.FavouriteTeam.Title' => 'Captain\'s favourite team'
1751
	);
1752
1753
	private static $default_sort = '"Title"';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1754
1755
	public function MyTitle() {
1756
		return 'Team ' . $this->Title;
1757
	}
1758
1759
	public function getDynamicField() {
1760
		return 'dynamicfield';
1761
	}
1762
1763
}
1764
1765
class DataObjectTest_Fixture extends DataObject implements TestOnly {
1766
	private static $db = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1767
		// Funny field names
1768
		'Data' => 'Varchar',
1769
		'Duplicate' => 'Varchar',
1770
		'DbObject' => 'Varchar',
1771
1772
		// Field types
1773
		'DateField' => 'Date',
1774
		'DatetimeField' => 'Datetime',
1775
1776
		'MyFieldWithDefault' => 'Varchar',
1777
		'MyFieldWithAltDefault' => 'Varchar'
1778
	);
1779
1780
	private static $defaults = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1781
		'MyFieldWithDefault' => 'Default Value',
1782
	);
1783
1784
	private static $summary_fields = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1785
		'Data' => 'Data',
1786
		'DateField.Nice' => 'Date'
1787
	);
1788
1789
	private static $searchable_fields = array();
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1790
1791
	public function populateDefaults() {
1792
		parent::populateDefaults();
1793
1794
		$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...
1795
	}
1796
1797
}
1798
1799
class DataObjectTest_SubTeam extends DataObjectTest_Team implements TestOnly {
1800
	private static $db = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1801
		'SubclassDatabaseField' => 'Varchar'
1802
	);
1803
1804
	private static $has_one = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1805
		"ParentTeam" => 'DataObjectTest_Team',
1806
	);
1807
1808
	private static $many_many = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1809
		'FormerPlayers' => 'DataObjectTest_Player'
1810
	);
1811
1812
	private static $many_many_extraFields = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1813
		'FormerPlayers' => array(
1814
			'Position' => 'Varchar(100)'
1815
		)
1816
	);
1817
}
1818
class OtherSubclassWithSameField extends DataObjectTest_Team implements TestOnly {
1819
	private static $db = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1820
		'SubclassDatabaseField' => 'Varchar',
1821
	);
1822
}
1823
1824
1825
class DataObjectTest_FieldlessTable extends DataObject implements TestOnly {
1826
}
1827
1828
class DataObjectTest_FieldlessSubTable extends DataObjectTest_Team implements TestOnly {
1829
}
1830
1831
1832
class DataObjectTest_Team_Extension extends DataExtension implements TestOnly {
1833
1834
	private static $db = array(
1835
		'ExtendedDatabaseField' => 'Varchar'
1836
	);
1837
1838
	private static $has_one = array(
1839
		'ExtendedHasOneRelationship' => 'DataObjectTest_Player'
1840
	);
1841
1842
	public function getExtendedDynamicField() {
1843
		return "extended dynamic field";
1844
	}
1845
1846
}
1847
1848
class DataObjectTest_ValidatedObject extends DataObject implements TestOnly {
1849
1850
	private static $db = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1851
		'Name' => 'Varchar(50)'
1852
	);
1853
1854
	protected function validate() {
1855
		if(!empty($this->Name)) {
1856
			return new ValidationResult();
1857
		} else {
1858
			return new ValidationResult(false, "This object needs a name. Otherwise it will have an identity crisis!");
1859
		}
1860
	}
1861
}
1862
1863
class DataObjectTest_Company extends DataObject implements TestOnly {
1864
1865
	private static $db = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1866
		'Name' => 'Varchar'
1867
	);
1868
1869
	private static $has_one = array (
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1870
		'CEO'         => 'DataObjectTest_CEO',
1871
		'PreviousCEO' => 'DataObjectTest_CEO',
1872
		'Owner'       => 'DataObject' // polymorphic
1873
	);
1874
1875
	private static $has_many = array (
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1876
		'CurrentStaff'     => 'DataObjectTest_Staff.CurrentCompany',
1877
		'PreviousStaff'    => 'DataObjectTest_Staff.PreviousCompany'
1878
	);
1879
}
1880
1881
class DataObjectTest_EquipmentCompany extends DataObjectTest_Company implements TestOnly {
1882
	private static $many_many = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1883
		'SponsoredTeams' => 'DataObjectTest_Team',
1884
		'EquipmentCustomers' => 'DataObjectTest_Team'
1885
	);
1886
1887
	private static $many_many_extraFields = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1888
		'SponsoredTeams' => array(
1889
			'SponsorFee' => 'Int'
1890
		)
1891
	);
1892
}
1893
1894
class DataObjectTest_SubEquipmentCompany extends DataObjectTest_EquipmentCompany implements TestOnly {
1895
	private static $db = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1896
		'SubclassDatabaseField' => 'Varchar'
1897
	);
1898
}
1899
1900
class DataObjectTest_Staff extends DataObject implements TestOnly {
1901
	private static $has_one = array (
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1902
		'CurrentCompany'  => 'DataObjectTest_Company',
1903
		'PreviousCompany' => 'DataObjectTest_Company'
1904
	);
1905
}
1906
1907
class DataObjectTest_CEO extends DataObjectTest_Staff {
1908
	private static $belongs_to = array (
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1909
		'Company'         => 'DataObjectTest_Company.CEO',
1910
		'PreviousCompany' => 'DataObjectTest_Company.PreviousCEO',
1911
		'CompanyOwned'    => 'DataObjectTest_Company.Owner'
1912
	);
1913
}
1914
1915
class DataObjectTest_TeamComment extends DataObject implements TestOnly {
1916
	private static $db = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1917
		'Name' => 'Varchar',
1918
		'Comment' => 'Text'
1919
	);
1920
1921
	private static $has_one = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1922
		'Team' => 'DataObjectTest_Team'
1923
	);
1924
1925
	private static $default_sort = '"Name" ASC';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1926
}
1927
1928
class DataObjectTest_Fan extends DataObject implements TestOnly {
1929
1930
	private static $db = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1931
		'Name' => 'Varchar(255)'
1932
	);
1933
1934
	private static $has_one = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1935
		'Favourite' => 'DataObject', // Polymorphic relation
1936
		'SecondFavourite' => 'DataObject'
1937
	);
1938
}
1939
1940
class DataObjectTest_ExtendedTeamComment extends DataObjectTest_TeamComment {
1941
	private static $db = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1942
		'Comment' => 'HTMLText'
1943
	);
1944
}
1945
1946
class DataObjectTest_Play extends DataObject implements TestOnly {}
1947
class DataObjectTest_Ploy extends DataObject implements TestOnly {}
1948
class DataObjectTest_Bogey extends DataObject implements TestOnly {}
1949
1950
DataObjectTest_Team::add_extension('DataObjectTest_Team_Extension');
1951
1952