Passed
Push — 4.1 ( 802261...1362b2 )
by
unknown
15:08 queued 06:46
created

testSetFieldWithArrayOnScalarOnlyField()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 0
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\ORM\Tests;
4
5
use InvalidArgumentException;
6
use LogicException;
7
use SilverStripe\Core\Config\Config;
8
use SilverStripe\Dev\SapphireTest;
9
use SilverStripe\i18n\i18n;
10
use SilverStripe\ORM\Connect\MySQLDatabase;
11
use SilverStripe\ORM\DataObject;
12
use SilverStripe\ORM\DataObjectSchema;
13
use SilverStripe\ORM\DB;
14
use SilverStripe\ORM\FieldType\DBBoolean;
15
use SilverStripe\ORM\FieldType\DBDatetime;
16
use SilverStripe\ORM\FieldType\DBField;
17
use SilverStripe\ORM\FieldType\DBPolymorphicForeignKey;
18
use SilverStripe\ORM\FieldType\DBVarchar;
19
use SilverStripe\ORM\ManyManyList;
20
use SilverStripe\ORM\Tests\DataObjectTest\Company;
21
use SilverStripe\ORM\Tests\DataObjectTest\Player;
22
use SilverStripe\ORM\Tests\DataObjectTest\Team;
23
use SilverStripe\View\ViewableData;
24
use stdClass;
25
26
class DataObjectTest extends SapphireTest
27
{
28
29
    protected static $fixture_file = 'DataObjectTest.yml';
30
31
    /**
32
     * Standard set of dataobject test classes
33
     *
34
     * @var array
35
     */
36
    public static $extra_data_objects = array(
37
        DataObjectTest\Team::class,
38
        DataObjectTest\Fixture::class,
39
        DataObjectTest\SubTeam::class,
40
        DataObjectTest\OtherSubclassWithSameField::class,
41
        DataObjectTest\FieldlessTable::class,
42
        DataObjectTest\FieldlessSubTable::class,
43
        DataObjectTest\ValidatedObject::class,
44
        DataObjectTest\Player::class,
45
        DataObjectTest\TeamComment::class,
46
        DataObjectTest\EquipmentCompany::class,
47
        DataObjectTest\SubEquipmentCompany::class,
48
        DataObjectTest\ExtendedTeamComment::class,
49
        DataObjectTest\Company::class,
50
        DataObjectTest\Staff::class,
51
        DataObjectTest\CEO::class,
52
        DataObjectTest\Fan::class,
53
        DataObjectTest\Play::class,
54
        DataObjectTest\Ploy::class,
55
        DataObjectTest\Bogey::class,
56
        DataObjectTest\Sortable::class,
57
        DataObjectTest\Bracket::class,
58
        DataObjectTest\RelationParent::class,
59
        DataObjectTest\RelationChildFirst::class,
60
        DataObjectTest\RelationChildSecond::class,
61
    );
62
63
    public static function getExtraDataObjects()
64
    {
65
        return array_merge(
66
            DataObjectTest::$extra_data_objects,
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
67
            ManyManyListTest::$extra_data_objects
68
        );
69
    }
70
71
    /**
72
     * @dataProvider provideSingletons
73
     */
74
    public function testSingleton($inst, $defaultValue, $altDefaultValue)
75
    {
76
        $inst = $inst();
77
        // Test that populateDefaults() isn't called on singletons
78
        // which can lead to SQL errors during build, and endless loops
79
        if ($defaultValue) {
80
            $this->assertEquals($defaultValue, $inst->MyFieldWithDefault);
81
        } else {
82
            $this->assertEmpty($inst->MyFieldWithDefault);
83
        }
84
85
        if ($altDefaultValue) {
86
            $this->assertEquals($altDefaultValue, $inst->MyFieldWithAltDefault);
87
        } else {
88
            $this->assertEmpty($inst->MyFieldWithAltDefault);
89
        }
90
    }
91
92
    public function provideSingletons()
93
    {
94
        // because PHPUnit evalutes test providers *before* setUp methods
95
        // any extensions added in the setUp methods won't be available
96
        // we must return closures to generate the arguments at run time
97
        return array(
98
            'create() static method' => array(function () {
99
                return DataObjectTest\Fixture::create();
100
            }, 'Default Value', 'Default Value'),
101
            'New object creation' => array(function () {
102
                return new DataObjectTest\Fixture();
103
            }, 'Default Value', 'Default Value'),
104
            'singleton() function' => array(function () {
105
                return singleton(DataObjectTest\Fixture::class);
106
            }, null, null),
107
            'singleton() static method' => array(function () {
108
                return DataObjectTest\Fixture::singleton();
109
            }, null, null),
110
            'Manual constructor args' => array(function () {
111
                return new DataObjectTest\Fixture(null, true);
112
            }, null, null),
113
        );
114
    }
115
116
    public function testDb()
117
    {
118
        $schema = DataObject::getSchema();
119
        $dbFields = $schema->fieldSpecs(DataObjectTest\TeamComment::class);
120
121
        // Assert fields are included
122
        $this->assertArrayHasKey('Name', $dbFields);
123
124
        // Assert the base fields are included
125
        $this->assertArrayHasKey('Created', $dbFields);
126
        $this->assertArrayHasKey('LastEdited', $dbFields);
127
        $this->assertArrayHasKey('ClassName', $dbFields);
128
        $this->assertArrayHasKey('ID', $dbFields);
129
130
        // Assert that the correct field type is returned when passing a field
131
        $this->assertEquals('Varchar', $schema->fieldSpec(DataObjectTest\TeamComment::class, 'Name'));
132
        $this->assertEquals('Text', $schema->fieldSpec(DataObjectTest\TeamComment::class, 'Comment'));
133
134
        // Test with table required
135
        $this->assertEquals(
136
            DataObjectTest\TeamComment::class . '.Varchar',
137
            $schema->fieldSpec(DataObjectTest\TeamComment::class, 'Name', DataObjectSchema::INCLUDE_CLASS)
138
        );
139
        $this->assertEquals(
140
            DataObjectTest\TeamComment::class . '.Text',
141
            $schema->fieldSpec(DataObjectTest\TeamComment::class, 'Comment', DataObjectSchema::INCLUDE_CLASS)
142
        );
143
        $dbFields = $schema->fieldSpecs(DataObjectTest\ExtendedTeamComment::class);
144
145
        // fixed fields are still included in extended classes
146
        $this->assertArrayHasKey('Created', $dbFields);
147
        $this->assertArrayHasKey('LastEdited', $dbFields);
148
        $this->assertArrayHasKey('ClassName', $dbFields);
149
        $this->assertArrayHasKey('ID', $dbFields);
150
151
        // Assert overloaded fields have correct data type
152
        $this->assertEquals('HTMLText', $schema->fieldSpec(DataObjectTest\ExtendedTeamComment::class, 'Comment'));
153
        $this->assertEquals(
154
            'HTMLText',
155
            $dbFields['Comment'],
156
            'Calls to DataObject::db without a field specified return correct data types'
157
        );
158
159
        // assertEquals doesn't verify the order of array elements, so access keys manually to check order:
160
        // expected: array('Name' => 'Varchar', 'Comment' => 'HTMLText')
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
161
        $this->assertEquals(
162
            array(
163
                'Name',
164
                'Comment'
165
            ),
166
            array_slice(array_keys($dbFields), 4, 2),
167
            'DataObject::db returns fields in correct order'
168
        );
169
    }
170
171
    public function testConstructAcceptsValues()
172
    {
173
        // Values can be an array...
174
        $player = new DataObjectTest\Player(
175
            array(
176
                'FirstName' => 'James',
177
                'Surname' => 'Smith'
178
            )
179
        );
180
181
        $this->assertEquals('James', $player->FirstName);
182
        $this->assertEquals('Smith', $player->Surname);
183
184
        // ... or a stdClass inst
185
        $data = new stdClass();
186
        $data->FirstName = 'John';
187
        $data->Surname = 'Doe';
188
        $player = new DataObjectTest\Player($data);
0 ignored issues
show
Bug introduced by
$data of type stdClass is incompatible with the type array|null expected by parameter $record of SilverStripe\ORM\Tests\D...t\Player::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

188
        $player = new DataObjectTest\Player(/** @scrutinizer ignore-type */ $data);
Loading history...
189
190
        $this->assertEquals('John', $player->FirstName);
191
        $this->assertEquals('Doe', $player->Surname);
192
193
        // IDs should be stored as integers, not strings
194
        $player = new DataObjectTest\Player(array('ID' => '5'));
195
        $this->assertSame(5, $player->ID);
196
    }
197
198
    public function testValidObjectsForBaseFields()
199
    {
200
        $obj = new DataObjectTest\ValidatedObject();
201
202
        foreach (array('Created', 'LastEdited', 'ClassName', 'ID') as $field) {
203
            $helper = $obj->dbObject($field);
204
            $this->assertTrue(
205
                ($helper instanceof DBField),
206
                "for {$field} expected helper to be DBField, but was " . (is_object($helper) ? get_class($helper) : "null")
207
            );
208
        }
209
    }
210
211
    public function testDataIntegrityWhenTwoSubclassesHaveSameField()
212
    {
213
        // Save data into DataObjectTest_SubTeam.SubclassDatabaseField
214
        $obj = new DataObjectTest\SubTeam();
215
        $obj->SubclassDatabaseField = "obj-SubTeam";
0 ignored issues
show
Bug Best Practice introduced by
The property SubclassDatabaseField does not exist on SilverStripe\ORM\Tests\DataObjectTest\SubTeam. Since you implemented __set, consider adding a @property annotation.
Loading history...
216
        $obj->write();
217
218
        // Change the class
219
        $obj->ClassName = DataObjectTest\OtherSubclassWithSameField::class;
220
        $obj->write();
221
        $obj->flushCache();
222
223
        // Re-fetch from the database and confirm that the data is sourced from
224
        // OtherSubclassWithSameField.SubclassDatabaseField
225
        $obj = DataObject::get_by_id(DataObjectTest\Team::class, $obj->ID);
226
        $this->assertNull($obj->SubclassDatabaseField);
0 ignored issues
show
Bug Best Practice introduced by
The property SubclassDatabaseField does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
227
228
        // Confirm that save the object in the other direction.
229
        $obj->SubclassDatabaseField = 'obj-Other';
0 ignored issues
show
Bug Best Practice introduced by
The property SubclassDatabaseField does not exist on SilverStripe\ORM\DataObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
230
        $obj->write();
231
232
        $obj->ClassName = DataObjectTest\SubTeam::class;
233
        $obj->write();
234
        $obj->flushCache();
235
236
        // If we restore the class, the old value has been lying dormant and will be available again.
237
        // NOTE: This behaviour is volatile; we may change this in the future to clear fields that
238
        // are no longer relevant when changing ClassName
239
        $obj = DataObject::get_by_id(DataObjectTest\Team::class, $obj->ID);
240
        $this->assertEquals('obj-SubTeam', $obj->SubclassDatabaseField);
241
    }
242
243
    /**
244
     * Test deletion of DataObjects
245
     *   - Deleting using delete() on the DataObject
246
     *   - Deleting using DataObject::delete_by_id()
247
     */
248
    public function testDelete()
249
    {
250
        // Test deleting using delete() on the DataObject
251
        // Get the first page
252
        $obj = $this->objFromFixture(DataObjectTest\Player::class, 'captain1');
253
        $objID = $obj->ID;
254
        // Check the page exists before deleting
255
        $this->assertTrue(is_object($obj) && $obj->exists());
256
        // Delete the page
257
        $obj->delete();
258
        // Check that page does not exist after deleting
259
        $obj = DataObject::get_by_id(DataObjectTest\Player::class, $objID);
260
        $this->assertTrue(!$obj || !$obj->exists());
261
262
263
        // Test deleting using DataObject::delete_by_id()
264
        // Get the second page
265
        $obj = $this->objFromFixture(DataObjectTest\Player::class, 'captain2');
266
        $objID = $obj->ID;
267
        // Check the page exists before deleting
268
        $this->assertTrue(is_object($obj) && $obj->exists());
269
        // Delete the page
270
        DataObject::delete_by_id(DataObjectTest\Player::class, $obj->ID);
271
        // Check that page does not exist after deleting
272
        $obj = DataObject::get_by_id(DataObjectTest\Player::class, $objID);
273
        $this->assertTrue(!$obj || !$obj->exists());
274
    }
275
276
    /**
277
     * Test methods that get DataObjects
278
     *   - DataObject::get()
279
     *       - All records of a DataObject
280
     *       - Filtering
281
     *       - Sorting
282
     *       - Joins
283
     *       - Limit
284
     *       - Container class
285
     *   - DataObject::get_by_id()
286
     *   - DataObject::get_one()
287
     *        - With and without caching
288
     *        - With and without ordering
289
     */
290
    public function testGet()
291
    {
292
        // Test getting all records of a DataObject
293
        $comments = DataObject::get(DataObjectTest\TeamComment::class);
294
        $this->assertEquals(3, $comments->count());
295
296
        // Test WHERE clause
297
        $comments = DataObject::get(DataObjectTest\TeamComment::class, "\"Name\"='Bob'");
298
        $this->assertEquals(1, $comments->count());
299
        foreach ($comments as $comment) {
300
            $this->assertEquals('Bob', $comment->Name);
301
        }
302
303
        // Test sorting
304
        $comments = DataObject::get(DataObjectTest\TeamComment::class, '', "\"Name\" ASC");
305
        $this->assertEquals(3, $comments->count());
306
        $this->assertEquals('Bob', $comments->first()->Name);
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
307
        $comments = DataObject::get(DataObjectTest\TeamComment::class, '', "\"Name\" DESC");
308
        $this->assertEquals(3, $comments->count());
309
        $this->assertEquals('Phil', $comments->first()->Name);
310
311
        // Test limit
312
        $comments = DataObject::get(DataObjectTest\TeamComment::class, '', "\"Name\" ASC", '', '1,2');
313
        $this->assertEquals(2, $comments->count());
314
        $this->assertEquals('Joe', $comments->first()->Name);
315
        $this->assertEquals('Phil', $comments->last()->Name);
316
317
        // Test get_by_id()
318
        $captain1ID = $this->idFromFixture(DataObjectTest\Player::class, 'captain1');
319
        $captain1 = DataObject::get_by_id(DataObjectTest\Player::class, $captain1ID);
320
        $this->assertEquals('Captain', $captain1->FirstName);
0 ignored issues
show
Bug Best Practice introduced by
The property FirstName does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
321
322
        // Test get_one() without caching
323
        $comment1 = DataObject::get_one(
324
            DataObjectTest\TeamComment::class,
325
            array(
326
                '"DataObjectTest_TeamComment"."Name"' => 'Joe'
327
            ),
328
            false
329
        );
330
        $comment1->Comment = "Something Else";
0 ignored issues
show
Bug Best Practice introduced by
The property Comment does not exist on SilverStripe\ORM\DataObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
331
332
        $comment2 = DataObject::get_one(
333
            DataObjectTest\TeamComment::class,
334
            array(
335
                '"DataObjectTest_TeamComment"."Name"' => 'Joe'
336
            ),
337
            false
338
        );
339
        $this->assertNotEquals($comment1->Comment, $comment2->Comment);
0 ignored issues
show
Bug Best Practice introduced by
The property Comment does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
340
341
        // Test get_one() with caching
342
        $comment1 = DataObject::get_one(
343
            DataObjectTest\TeamComment::class,
344
            array(
345
                '"DataObjectTest_TeamComment"."Name"' => 'Bob'
346
            ),
347
            true
348
        );
349
        $comment1->Comment = "Something Else";
350
351
        $comment2 = DataObject::get_one(
352
            DataObjectTest\TeamComment::class,
353
            array(
354
                '"DataObjectTest_TeamComment"."Name"' => 'Bob'
355
            ),
356
            true
357
        );
358
        $this->assertEquals((string)$comment1->Comment, (string)$comment2->Comment);
359
360
        // Test get_one() with order by without caching
361
        $comment = DataObject::get_one(DataObjectTest\TeamComment::class, '', false, "\"Name\" ASC");
362
        $this->assertEquals('Bob', $comment->Name);
363
364
        $comment = DataObject::get_one(DataObjectTest\TeamComment::class, '', false, "\"Name\" DESC");
365
        $this->assertEquals('Phil', $comment->Name);
366
367
        // Test get_one() with order by with caching
368
        $comment = DataObject::get_one(DataObjectTest\TeamComment::class, '', true, '"Name" ASC');
369
        $this->assertEquals('Bob', $comment->Name);
370
        $comment = DataObject::get_one(DataObjectTest\TeamComment::class, '', true, '"Name" DESC');
371
        $this->assertEquals('Phil', $comment->Name);
372
    }
373
374
    public function testGetCaseInsensitive()
375
    {
376
        // Test get_one() with bad case on the classname
377
        // Note: This will succeed only if the underlying DB server supports case-insensitive
378
        // table names (e.g. such as MySQL, but not SQLite3)
379
        if (!(DB::get_conn() instanceof MySQLDatabase)) {
380
            $this->markTestSkipped('MySQL only');
381
        }
382
383
        $subteam1 = DataObject::get_one(
384
            strtolower(DataObjectTest\SubTeam::class),
385
            array(
386
                '"DataObjectTest_Team"."Title"' => 'Subteam 1'
387
            ),
388
            true
389
        );
390
        $this->assertNotEmpty($subteam1);
391
        $this->assertEquals($subteam1->Title, "Subteam 1");
392
    }
393
394
    public function testGetSubclassFields()
395
    {
396
        /* Test that fields / has_one relations from the parent table and the subclass tables are extracted */
397
        $captain1 = $this->objFromFixture(DataObjectTest\Player::class, "captain1");
398
        // Base field
399
        $this->assertEquals('Captain', $captain1->FirstName);
0 ignored issues
show
Bug Best Practice introduced by
The property FirstName does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
400
        // Subclass field
401
        $this->assertEquals('007', $captain1->ShirtNumber);
0 ignored issues
show
Bug Best Practice introduced by
The property ShirtNumber does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
402
        // Subclass has_one relation
403
        $this->assertEquals($this->idFromFixture(DataObjectTest\Team::class, 'team1'), $captain1->FavouriteTeamID);
0 ignored issues
show
Bug Best Practice introduced by
The property FavouriteTeamID does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
404
    }
405
406
    public function testGetRelationClass()
407
    {
408
        $obj = new DataObjectTest\Player();
0 ignored issues
show
Unused Code introduced by
The assignment to $obj is dead and can be removed.
Loading history...
409
        $this->assertEquals(
410
            singleton(DataObjectTest\Player::class)->getRelationClass('FavouriteTeam'),
411
            DataObjectTest\Team::class,
412
            'has_one is properly inspected'
413
        );
414
        $this->assertEquals(
415
            singleton(DataObjectTest\Company::class)->getRelationClass('CurrentStaff'),
416
            DataObjectTest\Staff::class,
417
            'has_many is properly inspected'
418
        );
419
        $this->assertEquals(
420
            singleton(DataObjectTest\Team::class)->getRelationClass('Players'),
421
            DataObjectTest\Player::class,
422
            'many_many is properly inspected'
423
        );
424
        $this->assertEquals(
425
            singleton(DataObjectTest\Player::class)->getRelationClass('Teams'),
426
            DataObjectTest\Team::class,
427
            'belongs_many_many is properly inspected'
428
        );
429
        $this->assertEquals(
430
            singleton(DataObjectTest\CEO::class)->getRelationClass('Company'),
431
            DataObjectTest\Company::class,
432
            'belongs_to is properly inspected'
433
        );
434
        $this->assertEquals(
435
            singleton(DataObjectTest\Fan::class)->getRelationClass('Favourite'),
436
            DataObject::class,
437
            'polymorphic has_one is properly inspected'
438
        );
439
    }
440
441
    /**
442
     * Test that has_one relations can be retrieved
443
     */
444
    public function testGetHasOneRelations()
445
    {
446
        $captain1 = $this->objFromFixture(DataObjectTest\Player::class, "captain1");
447
        $team1ID = $this->idFromFixture(DataObjectTest\Team::class, 'team1');
448
449
        // There will be a field called (relname)ID that contains the ID of the
450
        // object linked to via the has_one relation
451
        $this->assertEquals($team1ID, $captain1->FavouriteTeamID);
0 ignored issues
show
Bug Best Practice introduced by
The property FavouriteTeamID does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
452
453
        // There will be a method called $obj->relname() that returns the object itself
454
        $this->assertEquals($team1ID, $captain1->FavouriteTeam()->ID);
0 ignored issues
show
Bug introduced by
The method FavouriteTeam() does not exist on SilverStripe\ORM\DataObject. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

454
        $this->assertEquals($team1ID, $captain1->/** @scrutinizer ignore-call */ FavouriteTeam()->ID);
Loading history...
455
456
        // Test that getNonReciprocalComponent can find has_one from the has_many end
457
        $this->assertEquals(
458
            $team1ID,
459
            $captain1->inferReciprocalComponent(DataObjectTest\Team::class, 'PlayerFans')->ID
0 ignored issues
show
Bug Best Practice introduced by
The property ID does not exist on SilverStripe\ORM\DataList. Since you implemented __get, consider adding a @property annotation.
Loading history...
460
        );
461
462
        // Check entity with polymorphic has-one
463
        $fan1 = $this->objFromFixture(DataObjectTest\Fan::class, "fan1");
464
        $this->assertTrue((bool)$fan1->hasValue('Favourite'));
465
466
        // There will be fields named (relname)ID and (relname)Class for polymorphic
467
        // entities
468
        $this->assertEquals($team1ID, $fan1->FavouriteID);
0 ignored issues
show
Bug Best Practice introduced by
The property FavouriteID does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
469
        $this->assertEquals(DataObjectTest\Team::class, $fan1->FavouriteClass);
0 ignored issues
show
Bug Best Practice introduced by
The property FavouriteClass does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
470
471
        // There will be a method called $obj->relname() that returns the object itself
472
        $favourite = $fan1->Favourite();
0 ignored issues
show
Bug introduced by
The method Favourite() does not exist on SilverStripe\ORM\DataObject. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

472
        /** @scrutinizer ignore-call */ 
473
        $favourite = $fan1->Favourite();
Loading history...
473
        $this->assertEquals($team1ID, $favourite->ID);
474
        $this->assertInstanceOf(DataObjectTest\Team::class, $favourite);
475
476
        // check behaviour of dbObject with polymorphic relations
477
        $favouriteDBObject = $fan1->dbObject('Favourite');
478
        $favouriteValue = $favouriteDBObject->getValue();
479
        $this->assertInstanceOf(DBPolymorphicForeignKey::class, $favouriteDBObject);
480
        $this->assertEquals($favourite->ID, $favouriteValue->ID);
481
        $this->assertEquals($favourite->ClassName, $favouriteValue->ClassName);
482
    }
483
484
    public function testLimitAndCount()
485
    {
486
        $players = DataObject::get(DataObjectTest\Player::class);
487
488
        // There's 4 records in total
489
        $this->assertEquals(4, $players->count());
490
491
        // Testing "##, ##" syntax
492
        $this->assertEquals(4, $players->limit(20)->count());
493
        $this->assertEquals(4, $players->limit(20, 0)->count());
494
        $this->assertEquals(0, $players->limit(20, 20)->count());
495
        $this->assertEquals(2, $players->limit(2, 0)->count());
496
        $this->assertEquals(1, $players->limit(5, 3)->count());
497
    }
498
499
    public function testWriteNoChangesDoesntUpdateLastEdited()
500
    {
501
        // set mock now so we can be certain of LastEdited time for our test
502
        DBDatetime::set_mock_now('2017-01-01 00:00:00');
503
        $obj = new Player();
504
        $obj->FirstName = 'Test';
505
        $obj->Surname = 'Plater';
506
        $obj->Email = '[email protected]';
507
        $obj->write();
508
        $this->assertEquals('2017-01-01 00:00:00', $obj->LastEdited);
509
        $writtenObj = Player::get()->byID($obj->ID);
510
        $this->assertEquals('2017-01-01 00:00:00', $writtenObj->LastEdited);
511
512
        // set mock now so we get a new LastEdited if, for some reason, it's updated
513
        DBDatetime::set_mock_now('2017-02-01 00:00:00');
514
        $writtenObj->write();
515
        $this->assertEquals('2017-01-01 00:00:00', $writtenObj->LastEdited);
516
        $this->assertEquals($obj->ID, $writtenObj->ID);
517
518
        $reWrittenObj = Player::get()->byID($writtenObj->ID);
519
        $this->assertEquals('2017-01-01 00:00:00', $reWrittenObj->LastEdited);
520
    }
521
522
    /**
523
     * Test writing of database columns which don't correlate to a DBField,
524
     * e.g. all relation fields on has_one/has_many like "ParentID".
525
     */
526
    public function testWritePropertyWithoutDBField()
527
    {
528
        $obj = $this->objFromFixture(DataObjectTest\Player::class, 'captain1');
529
        $obj->FavouriteTeamID = 99;
0 ignored issues
show
Bug Best Practice introduced by
The property FavouriteTeamID does not exist on SilverStripe\ORM\DataObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
530
        $obj->write();
531
532
        // reload the page from the database
533
        $savedObj = DataObject::get_by_id(DataObjectTest\Player::class, $obj->ID);
534
        $this->assertTrue($savedObj->FavouriteTeamID == 99);
0 ignored issues
show
Bug Best Practice introduced by
The property FavouriteTeamID does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
535
536
        // Test with porymorphic relation
537
        $obj2 = $this->objFromFixture(DataObjectTest\Fan::class, "fan1");
538
        $obj2->FavouriteID = 99;
0 ignored issues
show
Bug Best Practice introduced by
The property FavouriteID does not exist on SilverStripe\ORM\DataObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
539
        $obj2->FavouriteClass = DataObjectTest\Player::class;
0 ignored issues
show
Bug Best Practice introduced by
The property FavouriteClass does not exist on SilverStripe\ORM\DataObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
540
        $obj2->write();
541
542
        $savedObj2 = DataObject::get_by_id(DataObjectTest\Fan::class, $obj2->ID);
543
        $this->assertTrue($savedObj2->FavouriteID == 99);
0 ignored issues
show
Bug Best Practice introduced by
The property FavouriteID does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
544
        $this->assertTrue($savedObj2->FavouriteClass == DataObjectTest\Player::class);
0 ignored issues
show
Bug Best Practice introduced by
The property FavouriteClass does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
545
    }
546
547
    /**
548
     * Test has many relationships
549
     *   - Test getComponents() gets the ComponentSet of the other side of the relation
550
     *   - Test the IDs on the DataObjects are set correctly
551
     */
552
    public function testHasManyRelationships()
553
    {
554
        $team1 = $this->objFromFixture(DataObjectTest\Team::class, 'team1');
555
556
        // Test getComponents() gets the ComponentSet of the other side of the relation
557
        $this->assertTrue($team1->Comments()->count() == 2);
0 ignored issues
show
Bug introduced by
The method Comments() does not exist on SilverStripe\ORM\DataObject. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

557
        $this->assertTrue($team1->/** @scrutinizer ignore-call */ Comments()->count() == 2);
Loading history...
558
559
        $team1Comments = [
560
            ['Comment' => 'This is a team comment by Joe'],
561
            ['Comment' => 'This is a team comment by Bob'],
562
        ];
563
564
        // Test the IDs on the DataObjects are set correctly
565
        $this->assertListEquals($team1Comments, $team1->Comments());
566
567
        // Test that has_many can be infered from the has_one via getNonReciprocalComponent
568
        $this->assertListEquals(
569
            $team1Comments,
570
            $team1->inferReciprocalComponent(DataObjectTest\TeamComment::class, 'Team')
0 ignored issues
show
Bug introduced by
It seems like $team1->inferReciprocalC...Comment::class, 'Team') can also be of type SilverStripe\ORM\DataObject; however, parameter $list of SilverStripe\Dev\SapphireTest::assertListEquals() does only seem to accept SilverStripe\ORM\SS_List, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

570
            /** @scrutinizer ignore-type */ $team1->inferReciprocalComponent(DataObjectTest\TeamComment::class, 'Team')
Loading history...
571
        );
572
573
        // Test that we can add and remove items that already exist in the database
574
        $newComment = new DataObjectTest\TeamComment();
575
        $newComment->Name = "Automated commenter";
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\Tests\DataObjectTest\TeamComment. Since you implemented __set, consider adding a @property annotation.
Loading history...
576
        $newComment->Comment = "This is a new comment";
0 ignored issues
show
Bug Best Practice introduced by
The property Comment does not exist on SilverStripe\ORM\Tests\DataObjectTest\TeamComment. Since you implemented __set, consider adding a @property annotation.
Loading history...
577
        $newComment->write();
578
        $team1->Comments()->add($newComment);
579
        $this->assertEquals($team1->ID, $newComment->TeamID);
0 ignored issues
show
Bug Best Practice introduced by
The property TeamID does not exist on SilverStripe\ORM\Tests\DataObjectTest\TeamComment. Since you implemented __get, consider adding a @property annotation.
Loading history...
580
581
        $comment1 = $this->objFromFixture(DataObjectTest\TeamComment::class, 'comment1');
582
        $comment2 = $this->objFromFixture(DataObjectTest\TeamComment::class, 'comment2');
583
        $team1->Comments()->remove($comment2);
584
585
        $team1CommentIDs = $team1->Comments()->sort('ID')->column('ID');
0 ignored issues
show
Bug introduced by
The method sort() does not exist on SilverStripe\ORM\SS_List. It seems like you code against a sub-type of said class. However, the method does not exist in SilverStripe\ORM\Filterable or SilverStripe\ORM\Limitable. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

585
        $team1CommentIDs = $team1->Comments()->/** @scrutinizer ignore-call */ sort('ID')->column('ID');
Loading history...
586
        $this->assertEquals(array($comment1->ID, $newComment->ID), $team1CommentIDs);
587
588
        // Test that removing an item from a list doesn't remove it from the same
589
        // relation belonging to a different object
590
        $team1 = $this->objFromFixture(DataObjectTest\Team::class, 'team1');
591
        $team2 = $this->objFromFixture(DataObjectTest\Team::class, 'team2');
592
        $team2->Comments()->remove($comment1);
593
        $team1CommentIDs = $team1->Comments()->sort('ID')->column('ID');
594
        $this->assertEquals(array($comment1->ID, $newComment->ID), $team1CommentIDs);
595
    }
596
597
598
    /**
599
     * Test has many relationships against polymorphic has_one fields
600
     *   - Test getComponents() gets the ComponentSet of the other side of the relation
601
     *   - Test the IDs on the DataObjects are set correctly
602
     */
603
    public function testHasManyPolymorphicRelationships()
604
    {
605
        $team1 = $this->objFromFixture(DataObjectTest\Team::class, 'team1');
606
607
        // Test getComponents() gets the ComponentSet of the other side of the relation
608
        $this->assertTrue($team1->Fans()->count() == 2);
0 ignored issues
show
Bug introduced by
The method Fans() does not exist on SilverStripe\ORM\DataObject. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

608
        $this->assertTrue($team1->/** @scrutinizer ignore-call */ Fans()->count() == 2);
Loading history...
609
610
        // Test the IDs/Classes on the DataObjects are set correctly
611
        foreach ($team1->Fans() as $fan) {
612
            $this->assertEquals($team1->ID, $fan->FavouriteID, 'Fan has the correct FavouriteID');
613
            $this->assertEquals(DataObjectTest\Team::class, $fan->FavouriteClass, 'Fan has the correct FavouriteClass');
614
        }
615
616
        // Test that we can add and remove items that already exist in the database
617
        $newFan = new DataObjectTest\Fan();
618
        $newFan->Name = "New fan";
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\Tests\DataObjectTest\Fan. Since you implemented __set, consider adding a @property annotation.
Loading history...
619
        $newFan->write();
620
        $team1->Fans()->add($newFan);
621
        $this->assertEquals($team1->ID, $newFan->FavouriteID, 'Newly created fan has the correct FavouriteID');
0 ignored issues
show
Bug Best Practice introduced by
The property FavouriteID does not exist on SilverStripe\ORM\Tests\DataObjectTest\Fan. Since you implemented __get, consider adding a @property annotation.
Loading history...
622
        $this->assertEquals(
623
            DataObjectTest\Team::class,
624
            $newFan->FavouriteClass,
0 ignored issues
show
Bug Best Practice introduced by
The property FavouriteClass does not exist on SilverStripe\ORM\Tests\DataObjectTest\Fan. Since you implemented __get, consider adding a @property annotation.
Loading history...
625
            'Newly created fan has the correct FavouriteClass'
626
        );
627
628
        $fan1 = $this->objFromFixture(DataObjectTest\Fan::class, 'fan1');
629
        $fan3 = $this->objFromFixture(DataObjectTest\Fan::class, 'fan3');
630
        $team1->Fans()->remove($fan3);
631
632
        $team1FanIDs = $team1->Fans()->sort('ID')->column('ID');
633
        $this->assertEquals(array($fan1->ID, $newFan->ID), $team1FanIDs);
634
635
        // Test that removing an item from a list doesn't remove it from the same
636
        // relation belonging to a different object
637
        $team1 = $this->objFromFixture(DataObjectTest\Team::class, 'team1');
638
        $player1 = $this->objFromFixture(DataObjectTest\Player::class, 'player1');
639
        $player1->Fans()->remove($fan1);
640
        $team1FanIDs = $team1->Fans()->sort('ID')->column('ID');
641
        $this->assertEquals(array($fan1->ID, $newFan->ID), $team1FanIDs);
642
    }
643
644
645
    public function testHasOneRelationship()
646
    {
647
        $team1 = $this->objFromFixture(DataObjectTest\Team::class, 'team1');
648
        $player1 = $this->objFromFixture(DataObjectTest\Player::class, 'player1');
649
        $player2 = $this->objFromFixture(DataObjectTest\Player::class, 'player2');
650
        $fan1 = $this->objFromFixture(DataObjectTest\Fan::class, 'fan1');
651
652
        // Test relation probing
653
        $this->assertFalse((bool)$team1->hasValue('Captain', null, false));
654
        $this->assertFalse((bool)$team1->hasValue('CaptainID', null, false));
655
656
        // Add a captain to team 1
657
        $team1->setField('CaptainID', $player1->ID);
658
        $team1->write();
659
660
        $this->assertTrue((bool)$team1->hasValue('Captain', null, false));
661
        $this->assertTrue((bool)$team1->hasValue('CaptainID', null, false));
662
663
        $this->assertEquals(
664
            $player1->ID,
665
            $team1->Captain()->ID,
0 ignored issues
show
Bug introduced by
The method Captain() does not exist on SilverStripe\ORM\DataObject. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

665
            $team1->/** @scrutinizer ignore-call */ 
666
                    Captain()->ID,
Loading history...
666
            'The captain exists for team 1'
667
        );
668
        $this->assertEquals(
669
            $player1->ID,
670
            $team1->getComponent('Captain')->ID,
671
            'The captain exists through the component getter'
672
        );
673
674
        $this->assertEquals(
675
            $team1->Captain()->FirstName,
676
            'Player 1',
677
            'Player 1 is the captain'
678
        );
679
        $this->assertEquals(
680
            $team1->getComponent('Captain')->FirstName,
681
            'Player 1',
682
            'Player 1 is the captain'
683
        );
684
685
        $team1->CaptainID = $player2->ID;
0 ignored issues
show
Bug Best Practice introduced by
The property CaptainID does not exist on SilverStripe\ORM\DataObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
686
        $team1->write();
687
688
        $this->assertEquals($player2->ID, $team1->Captain()->ID);
689
        $this->assertEquals($player2->ID, $team1->getComponent('Captain')->ID);
690
        $this->assertEquals('Player 2', $team1->Captain()->FirstName);
691
        $this->assertEquals('Player 2', $team1->getComponent('Captain')->FirstName);
692
693
694
        // Set the favourite team for fan1
695
        $fan1->setField('FavouriteID', $team1->ID);
696
        $fan1->setField('FavouriteClass', get_class($team1));
697
698
        $this->assertEquals($team1->ID, $fan1->Favourite()->ID, 'The team is assigned to fan 1');
699
        $this->assertInstanceOf(get_class($team1), $fan1->Favourite(), 'The team is assigned to fan 1');
700
        $this->assertEquals(
701
            $team1->ID,
702
            $fan1->getComponent('Favourite')->ID,
703
            'The team exists through the component getter'
704
        );
705
        $this->assertInstanceOf(
706
            get_class($team1),
707
            $fan1->getComponent('Favourite'),
708
            'The team exists through the component getter'
709
        );
710
711
        $this->assertEquals(
712
            $fan1->Favourite()->Title,
713
            'Team 1',
714
            'Team 1 is the favourite'
715
        );
716
        $this->assertEquals(
717
            $fan1->getComponent('Favourite')->Title,
718
            'Team 1',
719
            'Team 1 is the favourite'
720
        );
721
    }
722
723
    /**
724
     * Test has_one used as field getter/setter
725
     */
726
    public function testHasOneAsField()
727
    {
728
        /** @var DataObjectTest\Team $team1 */
729
        $team1 = $this->objFromFixture(DataObjectTest\Team::class, 'team1');
730
        $captain1 = $this->objFromFixture(DataObjectTest\Player::class, 'captain1');
731
        $captain2 = $this->objFromFixture(DataObjectTest\Player::class, 'captain2');
732
733
        // Setter: By RelationID
734
        $team1->CaptainID = $captain1->ID;
0 ignored issues
show
Bug Best Practice introduced by
The property CaptainID does not exist on SilverStripe\ORM\Tests\DataObjectTest\Team. Since you implemented __set, consider adding a @property annotation.
Loading history...
735
        $team1->write();
736
        $this->assertEquals($captain1->ID, $team1->Captain->ID);
0 ignored issues
show
Bug Best Practice introduced by
The property Captain does not exist on SilverStripe\ORM\Tests\DataObjectTest\Team. Since you implemented __get, consider adding a @property annotation.
Loading history...
737
738
        // Setter: New object
739
        $team1->Captain = $captain2;
0 ignored issues
show
Bug Best Practice introduced by
The property Captain does not exist on SilverStripe\ORM\Tests\DataObjectTest\Team. Since you implemented __set, consider adding a @property annotation.
Loading history...
740
        $team1->write();
741
        $this->assertEquals($captain2->ID, $team1->Captain->ID);
742
743
        // Setter: Custom data (required by DataDifferencer)
744
        $team1->Captain = DBField::create_field('HTMLFragment', '<p>No captain</p>');
745
        $this->assertEquals('<p>No captain</p>', $team1->Captain);
746
    }
747
748
    /**
749
     * @todo Extend type change tests (e.g. '0'==NULL)
750
     */
751
    public function testChangedFields()
752
    {
753
        $obj = $this->objFromFixture(DataObjectTest\Player::class, 'captain1');
754
        $obj->FirstName = 'Captain-changed';
0 ignored issues
show
Bug Best Practice introduced by
The property FirstName does not exist on SilverStripe\ORM\DataObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
755
        $obj->IsRetired = true;
0 ignored issues
show
Bug Best Practice introduced by
The property IsRetired does not exist on SilverStripe\ORM\DataObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
756
757
        $this->assertEquals(
758
            $obj->getChangedFields(true, DataObject::CHANGE_STRICT),
759
            array(
760
                'FirstName' => array(
761
                    'before' => 'Captain',
762
                    'after' => 'Captain-changed',
763
                    'level' => DataObject::CHANGE_VALUE
764
                ),
765
                'IsRetired' => array(
766
                    'before' => 1,
767
                    'after' => true,
768
                    'level' => DataObject::CHANGE_STRICT
769
                )
770
            ),
771
            'Changed fields are correctly detected with strict type changes (level=1)'
772
        );
773
774
        $this->assertEquals(
775
            $obj->getChangedFields(true, DataObject::CHANGE_VALUE),
776
            array(
777
                'FirstName' => array(
778
                    'before' => 'Captain',
779
                    'after' => 'Captain-changed',
780
                    'level' => DataObject::CHANGE_VALUE
781
                )
782
            ),
783
            'Changed fields are correctly detected while ignoring type changes (level=2)'
784
        );
785
786
        $newObj = new DataObjectTest\Player();
787
        $newObj->FirstName = "New Player";
788
        $this->assertEquals(
789
            array(
790
                'FirstName' => array(
791
                    'before' => null,
792
                    'after' => 'New Player',
793
                    'level' => DataObject::CHANGE_VALUE
794
                )
795
            ),
796
            $newObj->getChangedFields(true, DataObject::CHANGE_VALUE),
797
            'Initialised fields are correctly detected as full changes'
798
        );
799
    }
800
801
    /**
802
     * @skipUpgrade
803
     */
804
    public function testIsChanged()
805
    {
806
        $obj = $this->objFromFixture(DataObjectTest\Player::class, 'captain1');
807
        $obj->NonDBField = 'bob';
0 ignored issues
show
Bug Best Practice introduced by
The property NonDBField does not exist on SilverStripe\ORM\DataObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
808
        $obj->FirstName = 'Captain-changed';
0 ignored issues
show
Bug Best Practice introduced by
The property FirstName does not exist on SilverStripe\ORM\DataObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
809
        $obj->IsRetired = true; // type change only, database stores "1"
0 ignored issues
show
Bug Best Practice introduced by
The property IsRetired does not exist on SilverStripe\ORM\DataObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
810
811
        // Now that DB fields are changed, isChanged is true
812
        $this->assertTrue($obj->isChanged('NonDBField'));
813
        $this->assertFalse($obj->isChanged('NonField'));
814
        $this->assertTrue($obj->isChanged('FirstName', DataObject::CHANGE_STRICT));
815
        $this->assertTrue($obj->isChanged('FirstName', DataObject::CHANGE_VALUE));
816
        $this->assertTrue($obj->isChanged('IsRetired', DataObject::CHANGE_STRICT));
817
        $this->assertFalse($obj->isChanged('IsRetired', DataObject::CHANGE_VALUE));
818
        $this->assertFalse($obj->isChanged('Email', 1), 'Doesnt change mark unchanged property');
819
        $this->assertFalse($obj->isChanged('Email', 2), 'Doesnt change mark unchanged property');
820
821
        $newObj = new DataObjectTest\Player();
822
        $newObj->FirstName = "New Player";
823
        $this->assertTrue($newObj->isChanged('FirstName', DataObject::CHANGE_STRICT));
824
        $this->assertTrue($newObj->isChanged('FirstName', DataObject::CHANGE_VALUE));
825
        $this->assertFalse($newObj->isChanged('Email', DataObject::CHANGE_STRICT));
826
        $this->assertFalse($newObj->isChanged('Email', DataObject::CHANGE_VALUE));
827
828
        $newObj->write();
829
        $this->assertFalse($newObj->ischanged());
830
        $this->assertFalse($newObj->isChanged('FirstName', DataObject::CHANGE_STRICT));
831
        $this->assertFalse($newObj->isChanged('FirstName', DataObject::CHANGE_VALUE));
832
        $this->assertFalse($newObj->isChanged('Email', DataObject::CHANGE_STRICT));
833
        $this->assertFalse($newObj->isChanged('Email', DataObject::CHANGE_VALUE));
834
835
        $obj = $this->objFromFixture(DataObjectTest\Player::class, 'captain1');
836
        $obj->FirstName = null;
837
        $this->assertTrue($obj->isChanged('FirstName', DataObject::CHANGE_STRICT));
838
        $this->assertTrue($obj->isChanged('FirstName', DataObject::CHANGE_VALUE));
839
840
        /* Test when there's not field provided */
841
        $obj = $this->objFromFixture(DataObjectTest\Player::class, 'captain2');
842
        $this->assertFalse($obj->isChanged());
843
        $obj->NonDBField = 'new value';
844
        $this->assertFalse($obj->isChanged());
845
        $obj->FirstName = "New Player";
846
        $this->assertTrue($obj->isChanged());
847
848
        $obj->write();
849
        $this->assertFalse($obj->isChanged());
850
    }
851
852
    public function testRandomSort()
853
    {
854
        /* If we perform the same regularly sorted query twice, it should return the same results */
855
        $itemsA = DataObject::get(DataObjectTest\TeamComment::class, "", "ID");
856
        foreach ($itemsA as $item) {
857
            $keysA[] = $item->ID;
858
        }
859
860
        $itemsB = DataObject::get(DataObjectTest\TeamComment::class, "", "ID");
861
        foreach ($itemsB as $item) {
862
            $keysB[] = $item->ID;
863
        }
864
865
        /* Test when there's not field provided */
866
        $obj = $this->objFromFixture(DataObjectTest\Player::class, 'captain1');
867
        $obj->FirstName = "New Player";
0 ignored issues
show
Bug Best Practice introduced by
The property FirstName does not exist on SilverStripe\ORM\DataObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
868
        $this->assertTrue($obj->isChanged());
869
870
        $obj->write();
871
        $this->assertFalse($obj->isChanged());
872
873
        /* If we perform the same random query twice, it shouldn't return the same results */
874
        $itemsA = DataObject::get(DataObjectTest\TeamComment::class, "", DB::get_conn()->random());
875
        $itemsB = DataObject::get(DataObjectTest\TeamComment::class, "", DB::get_conn()->random());
876
        $itemsC = DataObject::get(DataObjectTest\TeamComment::class, "", DB::get_conn()->random());
877
        $itemsD = DataObject::get(DataObjectTest\TeamComment::class, "", DB::get_conn()->random());
878
        foreach ($itemsA as $item) {
879
            $keysA[] = $item->ID;
880
        }
881
        foreach ($itemsB as $item) {
882
            $keysB[] = $item->ID;
883
        }
884
        foreach ($itemsC as $item) {
885
            $keysC[] = $item->ID;
886
        }
887
        foreach ($itemsD as $item) {
888
            $keysD[] = $item->ID;
889
        }
890
891
        // These shouldn't all be the same (run it 4 times to minimise chance of an accidental collision)
892
        // There's about a 1 in a billion chance of an accidental collision
893
        $this->assertTrue($keysA != $keysB || $keysB != $keysC || $keysC != $keysD);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $keysC seems to be defined by a foreach iteration on line 884. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
Comprehensibility Best Practice introduced by
The variable $keysD seems to be defined by a foreach iteration on line 887. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
Comprehensibility Best Practice introduced by
The variable $keysB seems to be defined by a foreach iteration on line 861. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
Comprehensibility Best Practice introduced by
The variable $keysA seems to be defined by a foreach iteration on line 856. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
894
    }
895
896
    public function testWriteSavesToHasOneRelations()
897
    {
898
        /* DataObject::write() should save to a has_one relationship if you set a field called (relname)ID */
899
        $team = new DataObjectTest\Team();
900
        $captainID = $this->idFromFixture(DataObjectTest\Player::class, 'player1');
901
        $team->CaptainID = $captainID;
0 ignored issues
show
Bug Best Practice introduced by
The property CaptainID does not exist on SilverStripe\ORM\Tests\DataObjectTest\Team. Since you implemented __set, consider adding a @property annotation.
Loading history...
902
        $team->write();
903
        $this->assertEquals(
904
            $captainID,
905
            DB::query("SELECT \"CaptainID\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $team->ID")->value()
906
        );
907
908
        /* After giving it a value, you should also be able to set it back to null */
909
        $team->CaptainID = '';
910
        $team->write();
911
        $this->assertEquals(
912
            0,
913
            DB::query("SELECT \"CaptainID\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $team->ID")->value()
914
        );
915
916
        /* You should also be able to save a blank to it when it's first created */
917
        $team = new DataObjectTest\Team();
918
        $team->CaptainID = '';
919
        $team->write();
920
        $this->assertEquals(
921
            0,
922
            DB::query("SELECT \"CaptainID\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $team->ID")->value()
923
        );
924
925
        /* Ditto for existing records without a value */
926
        $existingTeam = $this->objFromFixture(DataObjectTest\Team::class, 'team1');
927
        $existingTeam->CaptainID = '';
0 ignored issues
show
Bug Best Practice introduced by
The property CaptainID does not exist on SilverStripe\ORM\DataObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
928
        $existingTeam->write();
929
        $this->assertEquals(
930
            0,
931
            DB::query("SELECT \"CaptainID\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $existingTeam->ID")->value()
932
        );
933
    }
934
935
    public function testCanAccessHasOneObjectsAsMethods()
936
    {
937
        /* If you have a has_one relation 'Captain' on $obj, and you set the $obj->CaptainID = (ID), then the
938
        * object itself should be accessible as $obj->Captain() */
939
        $team = $this->objFromFixture(DataObjectTest\Team::class, 'team1');
940
        $captainID = $this->idFromFixture(DataObjectTest\Player::class, 'captain1');
941
942
        $team->CaptainID = $captainID;
0 ignored issues
show
Bug Best Practice introduced by
The property CaptainID does not exist on SilverStripe\ORM\DataObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
943
        $this->assertNotNull($team->Captain());
944
        $this->assertEquals($captainID, $team->Captain()->ID);
945
946
        // Test for polymorphic has_one relations
947
        $fan = $this->objFromFixture(DataObjectTest\Fan::class, 'fan1');
948
        $fan->FavouriteID = $team->ID;
0 ignored issues
show
Bug Best Practice introduced by
The property FavouriteID does not exist on SilverStripe\ORM\DataObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
949
        $fan->FavouriteClass = DataObjectTest\Team::class;
0 ignored issues
show
Bug Best Practice introduced by
The property FavouriteClass does not exist on SilverStripe\ORM\DataObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
950
        $this->assertNotNull($fan->Favourite());
951
        $this->assertEquals($team->ID, $fan->Favourite()->ID);
952
        $this->assertInstanceOf(DataObjectTest\Team::class, $fan->Favourite());
953
    }
954
955
    public function testFieldNamesThatMatchMethodNamesWork()
956
    {
957
        /* Check that a field name that corresponds to a method on DataObject will still work */
958
        $obj = new DataObjectTest\Fixture();
959
        $obj->Data = "value1";
0 ignored issues
show
Bug Best Practice introduced by
The property Data does not exist on SilverStripe\ORM\Tests\DataObjectTest\Fixture. Since you implemented __set, consider adding a @property annotation.
Loading history...
960
        $obj->DbObject = "value2";
0 ignored issues
show
Bug Best Practice introduced by
The property DbObject does not exist on SilverStripe\ORM\Tests\DataObjectTest\Fixture. Since you implemented __set, consider adding a @property annotation.
Loading history...
961
        $obj->Duplicate = "value3";
0 ignored issues
show
Bug Best Practice introduced by
The property Duplicate does not exist on SilverStripe\ORM\Tests\DataObjectTest\Fixture. Since you implemented __set, consider adding a @property annotation.
Loading history...
962
        $obj->write();
963
964
        $this->assertNotNull($obj->ID);
965
        $this->assertEquals(
966
            'value1',
967
            DB::query("SELECT \"Data\" FROM \"DataObjectTest_Fixture\" WHERE \"ID\" = $obj->ID")->value()
968
        );
969
        $this->assertEquals(
970
            'value2',
971
            DB::query("SELECT \"DbObject\" FROM \"DataObjectTest_Fixture\" WHERE \"ID\" = $obj->ID")->value()
972
        );
973
        $this->assertEquals(
974
            'value3',
975
            DB::query("SELECT \"Duplicate\" FROM \"DataObjectTest_Fixture\" WHERE \"ID\" = $obj->ID")->value()
976
        );
977
    }
978
979
    /**
980
     * @todo Re-enable all test cases for field existence after behaviour has been fixed
981
     */
982
    public function testFieldExistence()
983
    {
984
        $teamInstance = $this->objFromFixture(DataObjectTest\Team::class, 'team1');
985
        $teamSingleton = singleton(DataObjectTest\Team::class);
986
987
        $subteamInstance = $this->objFromFixture(DataObjectTest\SubTeam::class, 'subteam1');
988
        $schema = DataObject::getSchema();
989
990
        /* hasField() singleton checks */
991
        $this->assertTrue(
992
            $teamSingleton->hasField('ID'),
993
            'hasField() finds built-in fields in singletons'
994
        );
995
        $this->assertTrue(
996
            $teamSingleton->hasField('Title'),
997
            'hasField() finds custom fields in singletons'
998
        );
999
1000
        /* hasField() instance checks */
1001
        $this->assertFalse(
1002
            $teamInstance->hasField('NonExistingField'),
1003
            'hasField() doesnt find non-existing fields in instances'
1004
        );
1005
        $this->assertTrue(
1006
            $teamInstance->hasField('ID'),
1007
            'hasField() finds built-in fields in instances'
1008
        );
1009
        $this->assertTrue(
1010
            $teamInstance->hasField('Created'),
1011
            'hasField() finds built-in fields in instances'
1012
        );
1013
        $this->assertTrue(
1014
            $teamInstance->hasField('DatabaseField'),
1015
            'hasField() finds custom fields in instances'
1016
        );
1017
        //$this->assertFalse($teamInstance->hasField('SubclassDatabaseField'),
0 ignored issues
show
Unused Code Comprehensibility introduced by
82% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
1018
        //'hasField() doesnt find subclass fields in parentclass instances');
1019
        $this->assertTrue(
1020
            $teamInstance->hasField('DynamicField'),
1021
            'hasField() finds dynamic getters in instances'
1022
        );
1023
        $this->assertTrue(
1024
            $teamInstance->hasField('HasOneRelationshipID'),
1025
            'hasField() finds foreign keys in instances'
1026
        );
1027
        $this->assertTrue(
1028
            $teamInstance->hasField('ExtendedDatabaseField'),
1029
            'hasField() finds extended fields in instances'
1030
        );
1031
        $this->assertTrue(
1032
            $teamInstance->hasField('ExtendedHasOneRelationshipID'),
1033
            'hasField() finds extended foreign keys in instances'
1034
        );
1035
        //$this->assertTrue($teamInstance->hasField('ExtendedDynamicField'),
0 ignored issues
show
Unused Code Comprehensibility introduced by
82% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
1036
        //'hasField() includes extended dynamic getters in instances');
1037
1038
        /* hasField() subclass checks */
1039
        $this->assertTrue(
1040
            $subteamInstance->hasField('ID'),
1041
            'hasField() finds built-in fields in subclass instances'
1042
        );
1043
        $this->assertTrue(
1044
            $subteamInstance->hasField('Created'),
1045
            'hasField() finds built-in fields in subclass instances'
1046
        );
1047
        $this->assertTrue(
1048
            $subteamInstance->hasField('DatabaseField'),
1049
            'hasField() finds custom fields in subclass instances'
1050
        );
1051
        $this->assertTrue(
1052
            $subteamInstance->hasField('SubclassDatabaseField'),
1053
            'hasField() finds custom fields in subclass instances'
1054
        );
1055
        $this->assertTrue(
1056
            $subteamInstance->hasField('DynamicField'),
1057
            'hasField() finds dynamic getters in subclass instances'
1058
        );
1059
        $this->assertTrue(
1060
            $subteamInstance->hasField('HasOneRelationshipID'),
1061
            'hasField() finds foreign keys in subclass instances'
1062
        );
1063
        $this->assertTrue(
1064
            $subteamInstance->hasField('ExtendedDatabaseField'),
1065
            'hasField() finds extended fields in subclass instances'
1066
        );
1067
        $this->assertTrue(
1068
            $subteamInstance->hasField('ExtendedHasOneRelationshipID'),
1069
            'hasField() finds extended foreign keys in subclass instances'
1070
        );
1071
1072
        /* hasDatabaseField() singleton checks */
1073
        //$this->assertTrue($teamSingleton->hasDatabaseField('ID'),
0 ignored issues
show
Unused Code Comprehensibility introduced by
82% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
1074
        //'hasDatabaseField() finds built-in fields in singletons');
1075
        $this->assertNotEmpty(
1076
            $schema->fieldSpec(DataObjectTest\Team::class, 'Title'),
1077
            'hasDatabaseField() finds custom fields in singletons'
1078
        );
1079
1080
        /* hasDatabaseField() instance checks */
1081
        $this->assertNull(
1082
            $schema->fieldSpec(DataObjectTest\Team::class, 'NonExistingField'),
1083
            'hasDatabaseField() doesnt find non-existing fields in instances'
1084
        );
1085
        //$this->assertNotEmpty($schema->fieldSpec(DataObjectTest_Team::class, 'ID'),
0 ignored issues
show
Unused Code Comprehensibility introduced by
69% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
1086
        //'hasDatabaseField() finds built-in fields in instances');
1087
        $this->assertNotEmpty(
1088
            $schema->fieldSpec(DataObjectTest\Team::class, 'Created'),
1089
            'hasDatabaseField() finds built-in fields in instances'
1090
        );
1091
        $this->assertNotEmpty(
1092
            $schema->fieldSpec(DataObjectTest\Team::class, 'DatabaseField'),
1093
            'hasDatabaseField() finds custom fields in instances'
1094
        );
1095
        $this->assertNull(
1096
            $schema->fieldSpec(DataObjectTest\Team::class, 'SubclassDatabaseField'),
1097
            'hasDatabaseField() doesnt find subclass fields in parentclass instances'
1098
        );
1099
        //$this->assertNull($schema->fieldSpec(DataObjectTest_Team::class, 'DynamicField'),
0 ignored issues
show
Unused Code Comprehensibility introduced by
69% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
1100
        //'hasDatabaseField() doesnt dynamic getters in instances');
1101
        $this->assertNotEmpty(
1102
            $schema->fieldSpec(DataObjectTest\Team::class, 'HasOneRelationshipID'),
1103
            'hasDatabaseField() finds foreign keys in instances'
1104
        );
1105
        $this->assertNotEmpty(
1106
            $schema->fieldSpec(DataObjectTest\Team::class, 'ExtendedDatabaseField'),
1107
            'hasDatabaseField() finds extended fields in instances'
1108
        );
1109
        $this->assertNotEmpty(
1110
            $schema->fieldSpec(DataObjectTest\Team::class, 'ExtendedHasOneRelationshipID'),
1111
            'hasDatabaseField() finds extended foreign keys in instances'
1112
        );
1113
        $this->assertNull(
1114
            $schema->fieldSpec(DataObjectTest\Team::class, 'ExtendedDynamicField'),
1115
            'hasDatabaseField() doesnt include extended dynamic getters in instances'
1116
        );
1117
1118
        /* hasDatabaseField() subclass checks */
1119
        $this->assertNotEmpty(
1120
            $schema->fieldSpec(DataObjectTest\SubTeam::class, 'DatabaseField'),
1121
            'hasField() finds custom fields in subclass instances'
1122
        );
1123
        $this->assertNotEmpty(
1124
            $schema->fieldSpec(DataObjectTest\SubTeam::class, 'SubclassDatabaseField'),
1125
            'hasField() finds custom fields in subclass instances'
1126
        );
1127
    }
1128
1129
    /**
1130
     * @todo Re-enable all test cases for field inheritance aggregation after behaviour has been fixed
1131
     */
1132
    public function testFieldInheritance()
1133
    {
1134
        $schema = DataObject::getSchema();
1135
1136
        // Test logical fields (including composite)
1137
        $teamSpecifications = $schema->fieldSpecs(DataObjectTest\Team::class);
1138
        $expected = array(
1139
            'ID',
1140
            'ClassName',
1141
            'LastEdited',
1142
            'Created',
1143
            'Title',
1144
            'DatabaseField',
1145
            'ExtendedDatabaseField',
1146
            'CaptainID',
1147
            'FounderID',
1148
            'HasOneRelationshipID',
1149
            'ExtendedHasOneRelationshipID'
1150
        );
1151
        $actual = array_keys($teamSpecifications);
1152
        sort($expected);
1153
        sort($actual);
1154
        $this->assertEquals(
1155
            $expected,
1156
            $actual,
1157
            'fieldSpecifications() contains all fields defined on instance: base, extended and foreign keys'
1158
        );
1159
1160
        $teamFields = $schema->databaseFields(DataObjectTest\Team::class, false);
1161
        $expected = array(
1162
            'ID',
1163
            'ClassName',
1164
            'LastEdited',
1165
            'Created',
1166
            'Title',
1167
            'DatabaseField',
1168
            'ExtendedDatabaseField',
1169
            'CaptainID',
1170
            'FounderID',
1171
            'HasOneRelationshipID',
1172
            'ExtendedHasOneRelationshipID'
1173
        );
1174
        $actual = array_keys($teamFields);
1175
        sort($expected);
1176
        sort($actual);
1177
        $this->assertEquals(
1178
            $expected,
1179
            $actual,
1180
            'databaseFields() contains only fields defined on instance, including base, extended and foreign keys'
1181
        );
1182
1183
        $subteamSpecifications = $schema->fieldSpecs(DataObjectTest\SubTeam::class);
1184
        $expected = array(
1185
            'ID',
1186
            'ClassName',
1187
            'LastEdited',
1188
            'Created',
1189
            'Title',
1190
            'DatabaseField',
1191
            'ExtendedDatabaseField',
1192
            'CaptainID',
1193
            'FounderID',
1194
            'HasOneRelationshipID',
1195
            'ExtendedHasOneRelationshipID',
1196
            'SubclassDatabaseField',
1197
            'ParentTeamID',
1198
        );
1199
        $actual = array_keys($subteamSpecifications);
1200
        sort($expected);
1201
        sort($actual);
1202
        $this->assertEquals(
1203
            $expected,
1204
            $actual,
1205
            'fieldSpecifications() on subclass contains all fields, including base, extended  and foreign keys'
1206
        );
1207
1208
        $subteamFields = $schema->databaseFields(DataObjectTest\SubTeam::class, false);
1209
        $expected = array(
1210
            'ID',
1211
            'SubclassDatabaseField',
1212
            'ParentTeamID',
1213
        );
1214
        $actual = array_keys($subteamFields);
1215
        sort($expected);
1216
        sort($actual);
1217
        $this->assertEquals(
1218
            $expected,
1219
            $actual,
1220
            'databaseFields() on subclass contains only fields defined on instance'
1221
        );
1222
    }
1223
1224
    public function testSearchableFields()
1225
    {
1226
        $player = $this->objFromFixture(DataObjectTest\Player::class, 'captain1');
1227
        $fields = $player->searchableFields();
1228
        $this->assertArrayHasKey(
1229
            'IsRetired',
1230
            $fields,
1231
            'Fields defined by $searchable_fields static are correctly detected'
1232
        );
1233
        $this->assertArrayHasKey(
1234
            'ShirtNumber',
1235
            $fields,
1236
            'Fields defined by $searchable_fields static are correctly detected'
1237
        );
1238
1239
        $team = $this->objFromFixture(DataObjectTest\Team::class, 'team1');
1240
        $fields = $team->searchableFields();
1241
        $this->assertArrayHasKey(
1242
            'Title',
1243
            $fields,
1244
            'Fields can be inherited from the $summary_fields static, including methods called on fields'
1245
        );
1246
        $this->assertArrayHasKey(
1247
            'Captain.ShirtNumber',
1248
            $fields,
1249
            'Fields on related objects can be inherited from the $summary_fields static'
1250
        );
1251
        $this->assertArrayHasKey(
1252
            'Captain.FavouriteTeam.Title',
1253
            $fields,
1254
            'Fields on related objects can be inherited from the $summary_fields static'
1255
        );
1256
1257
        $testObj = new DataObjectTest\Fixture();
1258
        $fields = $testObj->searchableFields();
1259
        $this->assertEmpty($fields);
1260
    }
1261
1262
    public function testCastingHelper()
1263
    {
1264
        $team = $this->objFromFixture(DataObjectTest\Team::class, 'team1');
1265
1266
        $this->assertEquals('Varchar', $team->castingHelper('Title'), 'db field wasn\'t casted correctly');
1267
        $this->assertEquals('HTMLVarchar', $team->castingHelper('DatabaseField'), 'db field wasn\'t casted correctly');
1268
1269
        $sponsor = $team->Sponsors()->first();
0 ignored issues
show
Bug introduced by
The method Sponsors() does not exist on SilverStripe\ORM\DataObject. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1269
        $sponsor = $team->/** @scrutinizer ignore-call */ Sponsors()->first();
Loading history...
1270
        $this->assertEquals('Int', $sponsor->castingHelper('SponsorFee'), 'many_many_extraFields not casted correctly');
1271
    }
1272
1273
    public function testSummaryFieldsCustomLabels()
1274
    {
1275
        $team = $this->objFromFixture(DataObjectTest\Team::class, 'team1');
1276
        $summaryFields = $team->summaryFields();
1277
1278
        $this->assertEquals(
1279
            [
1280
                'Title' => 'Custom Title',
1281
                'Title.UpperCase' => 'Title',
1282
                'Captain.ShirtNumber' => 'Captain\'s shirt number',
1283
                'Captain.FavouriteTeam.Title' => 'Captain\'s favourite team',
1284
            ],
1285
            $summaryFields
1286
        );
1287
    }
1288
1289
    public function testDataObjectUpdate()
1290
    {
1291
        /* update() calls can use the dot syntax to reference has_one relations and other methods that return
1292
        * objects */
1293
        $team1 = $this->objFromFixture(DataObjectTest\Team::class, 'team1');
1294
        $team1->CaptainID = $this->idFromFixture(DataObjectTest\Player::class, 'captain1');
0 ignored issues
show
Bug Best Practice introduced by
The property CaptainID does not exist on SilverStripe\ORM\DataObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
1295
1296
        $team1->update(
1297
            array(
1298
                'DatabaseField' => 'Something',
1299
                'Captain.FirstName' => 'Jim',
1300
                'Captain.Email' => '[email protected]',
1301
                'Captain.FavouriteTeam.Title' => 'New and improved team 1',
1302
            )
1303
        );
1304
1305
        /* Test the simple case of updating fields on the object itself */
1306
        $this->assertEquals('Something', $team1->DatabaseField);
0 ignored issues
show
Bug Best Practice introduced by
The property DatabaseField does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
1307
1308
        /* Setting Captain.Email and Captain.FirstName will have updated DataObjectTest_Captain.captain1 in
1309
        * the database.  Although update() doesn't usually write, it does write related records automatically. */
1310
        $captain1 = $this->objFromFixture(DataObjectTest\Player::class, 'captain1');
1311
        $this->assertEquals('Jim', $captain1->FirstName);
0 ignored issues
show
Bug Best Practice introduced by
The property FirstName does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
1312
        $this->assertEquals('[email protected]', $captain1->Email);
0 ignored issues
show
Bug Best Practice introduced by
The property Email does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
1313
1314
        /* Jim's favourite team is team 1; we need to reload the object to the the change that setting Captain.
1315
        * FavouriteTeam.Title made */
1316
        $reloadedTeam1 = $this->objFromFixture(DataObjectTest\Team::class, 'team1');
1317
        $this->assertEquals('New and improved team 1', $reloadedTeam1->Title);
1318
    }
1319
1320
    public function testDataObjectUpdateNew()
1321
    {
1322
        /* update() calls can use the dot syntax to reference has_one relations and other methods that return
1323
        * objects */
1324
        $team1 = $this->objFromFixture(DataObjectTest\Team::class, 'team1');
1325
        $team1->CaptainID = 0;
0 ignored issues
show
Bug Best Practice introduced by
The property CaptainID does not exist on SilverStripe\ORM\DataObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
1326
1327
        $team1->update(
1328
            array(
1329
                'Captain.FirstName' => 'Jim',
1330
                'Captain.FavouriteTeam.Title' => 'New and improved team 1',
1331
            )
1332
        );
1333
        /* Test that the captain ID has been updated */
1334
        $this->assertGreaterThan(0, $team1->CaptainID);
0 ignored issues
show
Bug Best Practice introduced by
The property CaptainID does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
1335
1336
        /* Fetch the newly created captain */
1337
        $captain1 = DataObjectTest\Player::get()->byID($team1->CaptainID);
1338
        $this->assertEquals('Jim', $captain1->FirstName);
0 ignored issues
show
Bug Best Practice introduced by
The property FirstName does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
1339
1340
        /* Grab the favourite team and make sure it has the correct values */
1341
        $reloadedTeam1 = $captain1->FavouriteTeam();
1342
        $this->assertEquals($reloadedTeam1->ID, $captain1->FavouriteTeamID);
0 ignored issues
show
Bug Best Practice introduced by
The property FavouriteTeamID does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
1343
        $this->assertEquals('New and improved team 1', $reloadedTeam1->Title);
1344
    }
1345
1346
1347
    /**
1348
     * @expectedException \SilverStripe\ORM\ValidationException
1349
     */
1350
    public function testWritingInvalidDataObjectThrowsException()
1351
    {
1352
        $validatedObject = new DataObjectTest\ValidatedObject();
1353
        $validatedObject->write();
1354
    }
1355
1356
    public function testWritingValidDataObjectDoesntThrowException()
1357
    {
1358
        $validatedObject = new DataObjectTest\ValidatedObject();
1359
        $validatedObject->Name = "Mr. Jones";
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\Tests\D...ectTest\ValidatedObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
1360
1361
        $validatedObject->write();
1362
        $this->assertTrue($validatedObject->isInDB(), "Validated object was not saved to database");
1363
    }
1364
1365
    public function testSubclassCreation()
1366
    {
1367
        /* Creating a new object of a subclass should set the ClassName field correctly */
1368
        $obj = new DataObjectTest\SubTeam();
1369
        $obj->write();
1370
        $this->assertEquals(
1371
            DataObjectTest\SubTeam::class,
1372
            DB::query("SELECT \"ClassName\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $obj->ID")->value()
1373
        );
1374
    }
1375
1376
    public function testForceInsert()
1377
    {
1378
        /* If you set an ID on an object and pass forceInsert = true, then the object should be correctly created */
1379
        $conn = DB::get_conn();
1380
        if (method_exists($conn, 'allowPrimaryKeyEditing')) {
1381
            $conn->allowPrimaryKeyEditing(DataObjectTest\Team::class, true);
1382
        }
1383
        $obj = new DataObjectTest\SubTeam();
1384
        $obj->ID = 1001;
1385
        $obj->Title = 'asdfasdf';
1386
        $obj->SubclassDatabaseField = 'asdfasdf';
0 ignored issues
show
Bug Best Practice introduced by
The property SubclassDatabaseField does not exist on SilverStripe\ORM\Tests\DataObjectTest\SubTeam. Since you implemented __set, consider adding a @property annotation.
Loading history...
1387
        $obj->write(false, true);
1388
        if (method_exists($conn, 'allowPrimaryKeyEditing')) {
1389
            $conn->allowPrimaryKeyEditing(DataObjectTest\Team::class, false);
1390
        }
1391
1392
        $this->assertEquals(
1393
            DataObjectTest\SubTeam::class,
1394
            DB::query("SELECT \"ClassName\" FROM \"DataObjectTest_Team\" WHERE \"ID\" = $obj->ID")->value()
1395
        );
1396
1397
        /* Check that it actually saves to the database with the correct ID */
1398
        $this->assertEquals(
1399
            "1001",
1400
            DB::query(
1401
                "SELECT \"ID\" FROM \"DataObjectTest_SubTeam\" WHERE \"SubclassDatabaseField\" = 'asdfasdf'"
1402
            )->value()
1403
        );
1404
        $this->assertEquals(
1405
            "1001",
1406
            DB::query("SELECT \"ID\" FROM \"DataObjectTest_Team\" WHERE \"Title\" = 'asdfasdf'")->value()
1407
        );
1408
    }
1409
1410
    public function testHasOwnTable()
1411
    {
1412
        $schema = DataObject::getSchema();
1413
        /* Test DataObject::has_own_table() returns true if the object has $has_one or $db values */
1414
        $this->assertTrue($schema->classHasTable(DataObjectTest\Player::class));
1415
        $this->assertTrue($schema->classHasTable(DataObjectTest\Team::class));
1416
        $this->assertTrue($schema->classHasTable(DataObjectTest\Fixture::class));
1417
1418
        /* Root DataObject that always have a table, even if they lack both $db and $has_one */
1419
        $this->assertTrue($schema->classHasTable(DataObjectTest\FieldlessTable::class));
1420
1421
        /* Subclasses without $db or $has_one don't have a table */
1422
        $this->assertFalse($schema->classHasTable(DataObjectTest\FieldlessSubTable::class));
1423
1424
        /* Return false if you don't pass it a subclass of DataObject */
1425
        $this->assertFalse($schema->classHasTable(DataObject::class));
1426
        $this->assertFalse($schema->classHasTable(ViewableData::class));
1427
1428
        /* Invalid class name */
1429
        $this->assertFalse($schema->classHasTable("ThisIsntADataObject"));
1430
    }
1431
1432
    public function testMerge()
1433
    {
1434
        // test right merge of subclasses
1435
        $left = $this->objFromFixture(DataObjectTest\SubTeam::class, 'subteam1');
1436
        $right = $this->objFromFixture(DataObjectTest\SubTeam::class, 'subteam2_with_player_relation');
1437
        $leftOrigID = $left->ID;
1438
        $left->merge($right, 'right', false, false);
1439
        $this->assertEquals(
1440
            $left->Title,
1441
            'Subteam 2',
1442
            'merge() with "right" priority overwrites fields with existing values on subclasses'
1443
        );
1444
        $this->assertEquals(
1445
            $left->ID,
1446
            $leftOrigID,
1447
            'merge() with "right" priority doesnt overwrite database ID'
1448
        );
1449
1450
        // test overwriteWithEmpty flag on existing left values
1451
        $left = $this->objFromFixture(DataObjectTest\SubTeam::class, 'subteam2_with_player_relation');
1452
        $right = $this->objFromFixture(DataObjectTest\SubTeam::class, 'subteam3_with_empty_fields');
1453
        $left->merge($right, 'right', false, true);
1454
        $this->assertEquals(
1455
            $left->Title,
1456
            'Subteam 3',
1457
            'merge() with $overwriteWithEmpty overwrites non-empty fields on left object'
1458
        );
1459
1460
        // test overwriteWithEmpty flag on empty left values
1461
        $left = $this->objFromFixture(DataObjectTest\SubTeam::class, 'subteam1');
1462
        // $SubclassDatabaseField is empty on here
1463
        $right = $this->objFromFixture(DataObjectTest\SubTeam::class, 'subteam2_with_player_relation');
1464
        $left->merge($right, 'right', false, true);
1465
        $this->assertEquals(
1466
            $left->SubclassDatabaseField,
0 ignored issues
show
Bug Best Practice introduced by
The property SubclassDatabaseField does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
1467
            null,
1468
            'merge() with $overwriteWithEmpty overwrites empty fields on left object'
1469
        );
1470
1471
        // @todo test "left" priority flag
1472
        // @todo test includeRelations flag
1473
        // @todo test includeRelations in combination with overwriteWithEmpty
1474
        // @todo test has_one relations
1475
        // @todo test has_many and many_many relations
1476
    }
1477
1478
    public function testPopulateDefaults()
1479
    {
1480
        $obj = new DataObjectTest\Fixture();
1481
        $this->assertEquals(
1482
            $obj->MyFieldWithDefault,
0 ignored issues
show
Bug Best Practice introduced by
The property MyFieldWithDefault does not exist on SilverStripe\ORM\Tests\DataObjectTest\Fixture. Since you implemented __get, consider adding a @property annotation.
Loading history...
1483
            'Default Value',
1484
            'Defaults are populated for in-memory object from $defaults array'
1485
        );
1486
1487
        $this->assertEquals(
1488
            $obj->MyFieldWithAltDefault,
1489
            'Default Value',
1490
            'Defaults are populated from overloaded populateDefaults() method'
1491
        );
1492
    }
1493
1494
    /**
1495
     * @expectedException \InvalidArgumentException
1496
     */
1497
    public function testValidateModelDefinitionsFailsWithArray()
1498
    {
1499
        Config::modify()->merge(DataObjectTest\Team::class, 'has_one', array('NotValid' => array('NoArraysAllowed')));
1500
        DataObject::getSchema()->hasOneComponent(DataObjectTest\Team::class, 'NotValid');
1501
    }
1502
1503
    /**
1504
     * @expectedException \InvalidArgumentException
1505
     */
1506
    public function testValidateModelDefinitionsFailsWithIntKey()
1507
    {
1508
        Config::modify()->set(DataObjectTest\Team::class, 'has_many', array(0 => DataObjectTest\Player::class));
1509
        DataObject::getSchema()->hasManyComponent(DataObjectTest\Team::class, 0);
1510
    }
1511
1512
    /**
1513
     * @expectedException \InvalidArgumentException
1514
     */
1515
    public function testValidateModelDefinitionsFailsWithIntValue()
1516
    {
1517
        Config::modify()->merge(DataObjectTest\Team::class, 'many_many', array('Players' => 12));
1518
        DataObject::getSchema()->manyManyComponent(DataObjectTest\Team::class, 'Players');
1519
    }
1520
1521
    public function testNewClassInstance()
1522
    {
1523
        $dataObject = $this->objFromFixture(DataObjectTest\Team::class, 'team1');
1524
        $changedDO = $dataObject->newClassInstance(DataObjectTest\SubTeam::class);
1525
        $changedFields = $changedDO->getChangedFields();
1526
1527
        // Don't write the record, it will reset changed fields
1528
        $this->assertInstanceOf(DataObjectTest\SubTeam::class, $changedDO);
1529
        $this->assertEquals($changedDO->ClassName, DataObjectTest\SubTeam::class);
1530
        $this->assertEquals($changedDO->RecordClassName, DataObjectTest\SubTeam::class);
0 ignored issues
show
Bug Best Practice introduced by
The property RecordClassName does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
1531
        $this->assertContains('ClassName', array_keys($changedFields));
1532
        $this->assertEquals($changedFields['ClassName']['before'], DataObjectTest\Team::class);
1533
        $this->assertEquals($changedFields['ClassName']['after'], DataObjectTest\SubTeam::class);
1534
        $this->assertEquals($changedFields['RecordClassName']['before'], DataObjectTest\Team::class);
1535
        $this->assertEquals($changedFields['RecordClassName']['after'], DataObjectTest\SubTeam::class);
1536
1537
        $changedDO->write();
1538
1539
        $this->assertInstanceOf(DataObjectTest\SubTeam::class, $changedDO);
1540
        $this->assertEquals($changedDO->ClassName, DataObjectTest\SubTeam::class);
1541
1542
        // Test invalid classes fail
1543
        $this->expectException(InvalidArgumentException::class);
1544
        $this->expectExceptionMessage('Controller is not a valid subclass of DataObject');
1545
        /**
1546
         * @skipUpgrade
1547
         */
1548
        $dataObject->newClassInstance('Controller');
1549
    }
1550
1551
    public function testMultipleManyManyWithSameClass()
1552
    {
1553
        $team = $this->objFromFixture(DataObjectTest\Team::class, 'team1');
1554
        $company2 = $this->objFromFixture(DataObjectTest\EquipmentCompany::class, 'equipmentcompany2');
1555
        $sponsors = $team->Sponsors();
1556
        $equipmentSuppliers = $team->EquipmentSuppliers();
0 ignored issues
show
Bug introduced by
The method EquipmentSuppliers() does not exist on SilverStripe\ORM\DataObject. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1556
        /** @scrutinizer ignore-call */ 
1557
        $equipmentSuppliers = $team->EquipmentSuppliers();
Loading history...
1557
1558
        // Check that DataObject::many_many() works as expected
1559
        $manyManyComponent = DataObject::getSchema()->manyManyComponent(DataObjectTest\Team::class, 'Sponsors');
1560
        $this->assertEquals(ManyManyList::class, $manyManyComponent['relationClass']);
1561
        $this->assertEquals(
1562
            DataObjectTest\Team::class,
1563
            $manyManyComponent['parentClass'],
1564
            'DataObject::many_many() didn\'t find the correct base class'
1565
        );
1566
        $this->assertEquals(
1567
            DataObjectTest\EquipmentCompany::class,
1568
            $manyManyComponent['childClass'],
1569
            'DataObject::many_many() didn\'t find the correct target class for the relation'
1570
        );
1571
        $this->assertEquals(
1572
            'DataObjectTest_EquipmentCompany_SponsoredTeams',
1573
            $manyManyComponent['join'],
1574
            'DataObject::many_many() didn\'t find the correct relation table'
1575
        );
1576
        $this->assertEquals('DataObjectTest_TeamID', $manyManyComponent['parentField']);
1577
        $this->assertEquals('DataObjectTest_EquipmentCompanyID', $manyManyComponent['childField']);
1578
1579
        // Check that ManyManyList still works
1580
        $this->assertEquals(2, $sponsors->count(), 'Rows are missing from relation');
1581
        $this->assertEquals(1, $equipmentSuppliers->count(), 'Rows are missing from relation');
1582
1583
        // Check everything works when no relation is present
1584
        $teamWithoutSponsor = $this->objFromFixture(DataObjectTest\Team::class, 'team3');
1585
        $this->assertInstanceOf(ManyManyList::class, $teamWithoutSponsor->Sponsors());
1586
        $this->assertEquals(0, $teamWithoutSponsor->Sponsors()->count());
1587
1588
        // Test that belongs_many_many can be infered from with getNonReciprocalComponent
1589
        $this->assertListEquals(
1590
            [
1591
                ['Name' => 'Company corp'],
1592
                ['Name' => 'Team co.'],
1593
            ],
1594
            $team->inferReciprocalComponent(DataObjectTest\EquipmentCompany::class, 'SponsoredTeams')
0 ignored issues
show
Bug introduced by
It seems like $team->inferReciprocalCo...lass, 'SponsoredTeams') can also be of type SilverStripe\ORM\DataObject; however, parameter $list of SilverStripe\Dev\SapphireTest::assertListEquals() does only seem to accept SilverStripe\ORM\SS_List, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1594
            /** @scrutinizer ignore-type */ $team->inferReciprocalComponent(DataObjectTest\EquipmentCompany::class, 'SponsoredTeams')
Loading history...
1595
        );
1596
1597
        // Test that many_many can be infered from getNonReciprocalComponent
1598
        $this->assertListEquals(
1599
            [
1600
                ['Title' => 'Team 1'],
1601
                ['Title' => 'Team 2'],
1602
                ['Title' => 'Subteam 1'],
1603
            ],
1604
            $company2->inferReciprocalComponent(DataObjectTest\Team::class, 'Sponsors')
1605
        );
1606
1607
        // Check many_many_extraFields still works
1608
        $equipmentCompany = $this->objFromFixture(DataObjectTest\EquipmentCompany::class, 'equipmentcompany1');
1609
        $equipmentCompany->SponsoredTeams()->add($teamWithoutSponsor, array('SponsorFee' => 1000));
0 ignored issues
show
Bug introduced by
The method SponsoredTeams() does not exist on SilverStripe\ORM\DataObject. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1609
        $equipmentCompany->/** @scrutinizer ignore-call */ 
1610
                           SponsoredTeams()->add($teamWithoutSponsor, array('SponsorFee' => 1000));
Loading history...
1610
        $sponsoredTeams = $equipmentCompany->SponsoredTeams();
1611
        $this->assertEquals(
1612
            1000,
1613
            $sponsoredTeams->byID($teamWithoutSponsor->ID)->SponsorFee,
1614
            'Data from many_many_extraFields was not stored/extracted correctly'
1615
        );
1616
1617
        // Check subclasses correctly inherit multiple many_manys
1618
        $subTeam = $this->objFromFixture(DataObjectTest\SubTeam::class, 'subteam1');
1619
        $this->assertEquals(
1620
            2,
1621
            $subTeam->Sponsors()->count(),
1622
            'Child class did not inherit multiple many_manys'
1623
        );
1624
        $this->assertEquals(
1625
            1,
1626
            $subTeam->EquipmentSuppliers()->count(),
1627
            'Child class did not inherit multiple many_manys'
1628
        );
1629
        // Team 2 has one EquipmentCompany sponsor and one SubEquipmentCompany
1630
        $team2 = $this->objFromFixture(DataObjectTest\Team::class, 'team2');
1631
        $this->assertEquals(
1632
            2,
1633
            $team2->Sponsors()->count(),
1634
            'Child class did not inherit multiple belongs_many_manys'
1635
        );
1636
1637
        // Check many_many_extraFields also works from the belongs_many_many side
1638
        $sponsors = $team2->Sponsors();
1639
        $sponsors->add($equipmentCompany, array('SponsorFee' => 750));
1640
        $this->assertEquals(
1641
            750,
1642
            $sponsors->byID($equipmentCompany->ID)->SponsorFee,
1643
            'Data from many_many_extraFields was not stored/extracted correctly'
1644
        );
1645
1646
        $subEquipmentCompany = $this->objFromFixture(DataObjectTest\SubEquipmentCompany::class, 'subequipmentcompany1');
1647
        $subTeam->Sponsors()->add($subEquipmentCompany, array('SponsorFee' => 1200));
1648
        $this->assertEquals(
1649
            1200,
1650
            $subTeam->Sponsors()->byID($subEquipmentCompany->ID)->SponsorFee,
1651
            'Data from inherited many_many_extraFields was not stored/extracted correctly'
1652
        );
1653
    }
1654
1655
    public function testManyManyExtraFields()
1656
    {
1657
        $team = $this->objFromFixture(DataObjectTest\Team::class, 'team1');
1658
        $schema = DataObject::getSchema();
1659
1660
        // Get all extra fields
1661
        $teamExtraFields = $team->manyManyExtraFields();
1662
        $this->assertEquals(
1663
            array(
1664
                'Players' => array('Position' => 'Varchar(100)')
1665
            ),
1666
            $teamExtraFields
1667
        );
1668
1669
        // Ensure fields from parent classes are included
1670
        $subTeam = singleton(DataObjectTest\SubTeam::class);
1671
        $teamExtraFields = $subTeam->manyManyExtraFields();
1672
        $this->assertEquals(
1673
            array(
1674
                'Players' => array('Position' => 'Varchar(100)'),
1675
                'FormerPlayers' => array('Position' => 'Varchar(100)')
1676
            ),
1677
            $teamExtraFields
1678
        );
1679
1680
        // Extra fields are immediately available on the Team class (defined in $many_many_extraFields)
1681
        $teamExtraFields = $schema->manyManyExtraFieldsForComponent(DataObjectTest\Team::class, 'Players');
1682
        $this->assertEquals(
1683
            $teamExtraFields,
1684
            array(
1685
                'Position' => 'Varchar(100)'
1686
            )
1687
        );
1688
1689
        // We'll have to go through the relation to get the extra fields on Player
1690
        $playerExtraFields = $schema->manyManyExtraFieldsForComponent(DataObjectTest\Player::class, 'Teams');
1691
        $this->assertEquals(
1692
            $playerExtraFields,
1693
            array(
1694
                'Position' => 'Varchar(100)'
1695
            )
1696
        );
1697
1698
        // Iterate through a many-many relationship and confirm that extra fields are included
1699
        $newTeam = new DataObjectTest\Team();
1700
        $newTeam->Title = "New team";
1701
        $newTeam->write();
1702
        $newTeamID = $newTeam->ID;
1703
1704
        $newPlayer = new DataObjectTest\Player();
1705
        $newPlayer->FirstName = "Sam";
1706
        $newPlayer->Surname = "Minnee";
1707
        $newPlayer->write();
1708
1709
        // The idea of Sam as a prop is essentially humourous.
1710
        $newTeam->Players()->add($newPlayer, array("Position" => "Prop"));
1711
1712
        // Requery and uncache everything
1713
        $newTeam->flushCache();
1714
        $newTeam = DataObject::get_by_id(DataObjectTest\Team::class, $newTeamID);
1715
1716
        // Check that the Position many_many_extraField is extracted.
1717
        $player = $newTeam->Players()->first();
0 ignored issues
show
Bug introduced by
The method Players() does not exist on SilverStripe\ORM\DataObject. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1717
        $player = $newTeam->/** @scrutinizer ignore-call */ Players()->first();
Loading history...
1718
        $this->assertEquals('Sam', $player->FirstName);
1719
        $this->assertEquals("Prop", $player->Position);
1720
1721
        // Check that ordering a many-many relation by an aggregate column doesn't fail
1722
        $player = $this->objFromFixture(DataObjectTest\Player::class, 'player2');
1723
        $player->Teams()->sort("count(DISTINCT \"DataObjectTest_Team_Players\".\"DataObjectTest_PlayerID\") DESC");
0 ignored issues
show
Bug introduced by
The method Teams() does not exist on SilverStripe\ORM\DataObject. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1723
        $player->/** @scrutinizer ignore-call */ 
1724
                 Teams()->sort("count(DISTINCT \"DataObjectTest_Team_Players\".\"DataObjectTest_PlayerID\") DESC");
Loading history...
1724
    }
1725
1726
    /**
1727
     * Check that the queries generated for many-many relation queries can have unlimitedRowCount
1728
     * called on them.
1729
     */
1730
    public function testManyManyUnlimitedRowCount()
1731
    {
1732
        $player = $this->objFromFixture(DataObjectTest\Player::class, 'player2');
1733
        // TODO: What's going on here?
1734
        $this->assertEquals(2, $player->Teams()->dataQuery()->query()->unlimitedRowCount());
1735
    }
1736
1737
    /**
1738
     * Tests that singular_name() generates sensible defaults.
1739
     */
1740
    public function testSingularName()
1741
    {
1742
        $assertions = array(
1743
            DataObjectTest\Player::class => 'Player',
1744
            DataObjectTest\Team::class => 'Team',
1745
            DataObjectTest\Fixture::class => 'Fixture',
1746
        );
1747
1748
        foreach ($assertions as $class => $expectedSingularName) {
1749
            $this->assertEquals(
1750
                $expectedSingularName,
1751
                singleton($class)->singular_name(),
1752
                "Assert that the singular_name for '$class' is correct."
1753
            );
1754
        }
1755
    }
1756
1757
    /**
1758
     * Tests that plural_name() generates sensible defaults.
1759
     */
1760
    public function testPluralName()
1761
    {
1762
        $assertions = array(
1763
            DataObjectTest\Player::class => 'Players',
1764
            DataObjectTest\Team::class => 'Teams',
1765
            DataObjectTest\Fixture::class => 'Fixtures',
1766
            DataObjectTest\Play::class => 'Plays',
1767
            DataObjectTest\Bogey::class => 'Bogeys',
1768
            DataObjectTest\Ploy::class => 'Ploys',
1769
        );
1770
        i18n::set_locale('en_NZ');
1771
        foreach ($assertions as $class => $expectedPluralName) {
1772
            $this->assertEquals(
1773
                $expectedPluralName,
1774
                DataObject::singleton($class)->plural_name(),
1775
                "Assert that the plural_name for '$class' is correct."
1776
            );
1777
            $this->assertEquals(
1778
                $expectedPluralName,
1779
                DataObject::singleton($class)->i18n_plural_name(),
1780
                "Assert that the i18n_plural_name for '$class' is correct."
1781
            );
1782
        }
1783
    }
1784
1785
    public function testHasDatabaseField()
1786
    {
1787
        $team = singleton(DataObjectTest\Team::class);
1788
        $subteam = singleton(DataObjectTest\SubTeam::class);
1789
1790
        $this->assertTrue(
1791
            $team->hasDatabaseField('Title'),
1792
            "hasOwnDatabaseField() works with \$db fields"
1793
        );
1794
        $this->assertTrue(
1795
            $team->hasDatabaseField('CaptainID'),
1796
            "hasOwnDatabaseField() works with \$has_one fields"
1797
        );
1798
        $this->assertFalse(
1799
            $team->hasDatabaseField('NonExistentField'),
1800
            "hasOwnDatabaseField() doesn't detect non-existend fields"
1801
        );
1802
        $this->assertTrue(
1803
            $team->hasDatabaseField('ExtendedDatabaseField'),
1804
            "hasOwnDatabaseField() works with extended fields"
1805
        );
1806
        $this->assertFalse(
1807
            $team->hasDatabaseField('SubclassDatabaseField'),
1808
            "hasOwnDatabaseField() doesn't pick up fields in subclasses on parent class"
1809
        );
1810
1811
        $this->assertTrue(
1812
            $subteam->hasDatabaseField('SubclassDatabaseField'),
1813
            "hasOwnDatabaseField() picks up fields in subclasses"
1814
        );
1815
    }
1816
1817
    public function testFieldTypes()
1818
    {
1819
        $obj = new DataObjectTest\Fixture();
1820
        $obj->DateField = '1988-01-02';
0 ignored issues
show
Bug Best Practice introduced by
The property DateField does not exist on SilverStripe\ORM\Tests\DataObjectTest\Fixture. Since you implemented __set, consider adding a @property annotation.
Loading history...
1821
        $obj->DatetimeField = '1988-03-04 06:30';
0 ignored issues
show
Bug Best Practice introduced by
The property DatetimeField does not exist on SilverStripe\ORM\Tests\DataObjectTest\Fixture. Since you implemented __set, consider adding a @property annotation.
Loading history...
1822
        $obj->write();
1823
        $obj->flushCache();
1824
1825
        $obj = DataObject::get_by_id(DataObjectTest\Fixture::class, $obj->ID);
1826
        $this->assertEquals('1988-01-02', $obj->DateField);
0 ignored issues
show
Bug Best Practice introduced by
The property DateField does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
1827
        $this->assertEquals('1988-03-04 06:30:00', $obj->DatetimeField);
0 ignored issues
show
Bug Best Practice introduced by
The property DatetimeField does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
1828
    }
1829
1830
    public function testTwoSubclassesWithTheSameFieldNameWork()
1831
    {
1832
        // Create two objects of different subclasses, setting the values of fields that are
1833
        // defined separately in each subclass
1834
        $obj1 = new DataObjectTest\SubTeam();
1835
        $obj1->SubclassDatabaseField = "obj1";
0 ignored issues
show
Bug Best Practice introduced by
The property SubclassDatabaseField does not exist on SilverStripe\ORM\Tests\DataObjectTest\SubTeam. Since you implemented __set, consider adding a @property annotation.
Loading history...
1836
        $obj2 = new DataObjectTest\OtherSubclassWithSameField();
1837
        $obj2->SubclassDatabaseField = "obj2";
0 ignored issues
show
Bug Best Practice introduced by
The property SubclassDatabaseField does not exist on SilverStripe\ORM\Tests\D...erSubclassWithSameField. Since you implemented __set, consider adding a @property annotation.
Loading history...
1838
1839
        // Write them to the database
1840
        $obj1->write();
1841
        $obj2->write();
1842
1843
        // Check that the values of those fields are properly read from the database
1844
        $values = DataObject::get(
1845
            DataObjectTest\Team::class,
1846
            "\"DataObjectTest_Team\".\"ID\" IN
1847
			($obj1->ID, $obj2->ID)"
1848
        )->column("SubclassDatabaseField");
1849
        $this->assertEquals(array_intersect($values, array('obj1', 'obj2')), $values);
1850
    }
1851
1852
    public function testClassNameSetForNewObjects()
1853
    {
1854
        $d = new DataObjectTest\Player();
1855
        $this->assertEquals(DataObjectTest\Player::class, $d->ClassName);
1856
    }
1857
1858
    public function testHasValue()
1859
    {
1860
        $team = new DataObjectTest\Team();
1861
        $this->assertFalse($team->hasValue('Title', null, false));
1862
        $this->assertFalse($team->hasValue('DatabaseField', null, false));
1863
1864
        $team->Title = 'hasValue';
1865
        $this->assertTrue($team->hasValue('Title', null, false));
1866
        $this->assertFalse($team->hasValue('DatabaseField', null, false));
1867
1868
        $team->Title = '<p></p>';
1869
        $this->assertTrue(
1870
            $team->hasValue('Title', null, false),
1871
            'Test that an empty paragraph is a value for non-HTML fields.'
1872
        );
1873
1874
        $team->DatabaseField = 'hasValue';
1875
        $this->assertTrue($team->hasValue('Title', null, false));
1876
        $this->assertTrue($team->hasValue('DatabaseField', null, false));
1877
    }
1878
1879
    public function testHasMany()
1880
    {
1881
        $company = new DataObjectTest\Company();
1882
1883
        $this->assertEquals(
1884
            array(
1885
                'CurrentStaff' => DataObjectTest\Staff::class,
1886
                'PreviousStaff' => DataObjectTest\Staff::class
1887
            ),
1888
            $company->hasMany(),
1889
            'has_many strips field name data by default.'
1890
        );
1891
1892
        $this->assertEquals(
1893
            DataObjectTest\Staff::class,
1894
            DataObject::getSchema()->hasManyComponent(DataObjectTest\Company::class, 'CurrentStaff'),
1895
            'has_many strips field name data by default on single relationships.'
1896
        );
1897
1898
        $this->assertEquals(
1899
            array(
1900
                'CurrentStaff' => DataObjectTest\Staff::class . '.CurrentCompany',
1901
                'PreviousStaff' => DataObjectTest\Staff::class . '.PreviousCompany'
1902
            ),
1903
            $company->hasMany(false),
1904
            'has_many returns field name data when $classOnly is false.'
1905
        );
1906
1907
        $this->assertEquals(
1908
            DataObjectTest\Staff::class . '.CurrentCompany',
1909
            DataObject::getSchema()->hasManyComponent(DataObjectTest\Company::class, 'CurrentStaff', false),
1910
            'has_many returns field name data on single records when $classOnly is false.'
1911
        );
1912
    }
1913
1914
    public function testGetRemoteJoinField()
1915
    {
1916
        $schema = DataObject::getSchema();
1917
1918
        // Company schema
1919
        $staffJoinField = $schema->getRemoteJoinField(
1920
            DataObjectTest\Company::class,
1921
            'CurrentStaff',
1922
            'has_many',
1923
            $polymorphic
1924
        );
1925
        $this->assertEquals('CurrentCompanyID', $staffJoinField);
1926
        $this->assertFalse($polymorphic, 'DataObjectTest_Company->CurrentStaff is not polymorphic');
1927
        $previousStaffJoinField = $schema->getRemoteJoinField(
1928
            DataObjectTest\Company::class,
1929
            'PreviousStaff',
1930
            'has_many',
1931
            $polymorphic
1932
        );
1933
        $this->assertEquals('PreviousCompanyID', $previousStaffJoinField);
1934
        $this->assertFalse($polymorphic, 'DataObjectTest_Company->PreviousStaff is not polymorphic');
1935
1936
        // CEO Schema
1937
        $this->assertEquals(
1938
            'CEOID',
1939
            $schema->getRemoteJoinField(
1940
                DataObjectTest\CEO::class,
1941
                'Company',
1942
                'belongs_to',
1943
                $polymorphic
1944
            )
1945
        );
1946
        $this->assertFalse($polymorphic, 'DataObjectTest_CEO->Company is not polymorphic');
1947
        $this->assertEquals(
1948
            'PreviousCEOID',
1949
            $schema->getRemoteJoinField(
1950
                DataObjectTest\CEO::class,
1951
                'PreviousCompany',
1952
                'belongs_to',
1953
                $polymorphic
1954
            )
1955
        );
1956
        $this->assertFalse($polymorphic, 'DataObjectTest_CEO->PreviousCompany is not polymorphic');
1957
1958
        // Team schema
1959
        $this->assertEquals(
1960
            'Favourite',
1961
            $schema->getRemoteJoinField(
1962
                DataObjectTest\Team::class,
1963
                'Fans',
1964
                'has_many',
1965
                $polymorphic
1966
            )
1967
        );
1968
        $this->assertTrue($polymorphic, 'DataObjectTest_Team->Fans is polymorphic');
1969
        $this->assertEquals(
1970
            'TeamID',
1971
            $schema->getRemoteJoinField(
1972
                DataObjectTest\Team::class,
1973
                'Comments',
1974
                'has_many',
1975
                $polymorphic
1976
            )
1977
        );
1978
        $this->assertFalse($polymorphic, 'DataObjectTest_Team->Comments is not polymorphic');
1979
    }
1980
1981
    public function testBelongsTo()
1982
    {
1983
        $company = new DataObjectTest\Company();
1984
        $ceo = new DataObjectTest\CEO();
1985
1986
        $company->Name = 'New Company';
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\Tests\DataObjectTest\Company. Since you implemented __set, consider adding a @property annotation.
Loading history...
1987
        $company->write();
1988
        $ceo->write();
1989
1990
        // Test belongs_to assignment
1991
        $company->CEOID = $ceo->ID;
0 ignored issues
show
Bug Best Practice introduced by
The property CEOID does not exist on SilverStripe\ORM\Tests\DataObjectTest\Company. Since you implemented __set, consider adding a @property annotation.
Loading history...
1992
        $company->write();
1993
1994
        $this->assertEquals($company->ID, $ceo->Company()->ID, 'belongs_to returns the right results.');
0 ignored issues
show
Bug introduced by
The method Company() does not exist on SilverStripe\ORM\Tests\DataObjectTest\CEO. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1994
        $this->assertEquals($company->ID, $ceo->/** @scrutinizer ignore-call */ Company()->ID, 'belongs_to returns the right results.');
Loading history...
1995
1996
        // Test belongs_to can be infered via getNonReciprocalComponent
1997
        // Note: Will be returned as has_many since the belongs_to is ignored.
1998
        $this->assertListEquals(
1999
            [['Name' => 'New Company']],
2000
            $ceo->inferReciprocalComponent(DataObjectTest\Company::class, 'CEO')
0 ignored issues
show
Bug introduced by
It seems like $ceo->inferReciprocalCom...\Company::class, 'CEO') can also be of type SilverStripe\ORM\DataObject; however, parameter $list of SilverStripe\Dev\SapphireTest::assertListEquals() does only seem to accept SilverStripe\ORM\SS_List, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2000
            /** @scrutinizer ignore-type */ $ceo->inferReciprocalComponent(DataObjectTest\Company::class, 'CEO')
Loading history...
2001
        );
2002
2003
        // Test has_one to a belongs_to can be infered via getNonReciprocalComponent
2004
        $this->assertEquals(
2005
            $ceo->ID,
2006
            $company->inferReciprocalComponent(DataObjectTest\CEO::class, 'Company')->ID
0 ignored issues
show
Bug Best Practice introduced by
The property ID does not exist on SilverStripe\ORM\DataList. Since you implemented __get, consider adding a @property annotation.
Loading history...
2007
        );
2008
2009
        // Test automatic creation of class where no assigment exists
2010
        $ceo = new DataObjectTest\CEO();
2011
        $ceo->write();
2012
2013
        $this->assertTrue(
2014
            $ceo->Company() instanceof DataObjectTest\Company,
2015
            'DataObjects across belongs_to relations are automatically created.'
2016
        );
2017
        $this->assertEquals($ceo->ID, $ceo->Company()->CEOID, 'Remote IDs are automatically set.');
2018
2019
        // Write object with components
2020
        $ceo->Name = 'Edward Scissorhands';
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\Tests\DataObjectTest\CEO. Since you implemented __set, consider adding a @property annotation.
Loading history...
2021
        $ceo->write(false, false, false, true);
2022
        $this->assertTrue($ceo->Company()->isInDB(), 'write() writes belongs_to components to the database.');
2023
2024
        $newCEO = DataObject::get_by_id(DataObjectTest\CEO::class, $ceo->ID);
2025
        $this->assertEquals(
2026
            $ceo->Company()->ID,
2027
            $newCEO->Company()->ID,
0 ignored issues
show
Bug introduced by
The method Company() does not exist on SilverStripe\ORM\DataObject. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2027
            $newCEO->/** @scrutinizer ignore-call */ 
2028
                     Company()->ID,
Loading history...
2028
            'belongs_to can be retrieved from the database.'
2029
        );
2030
    }
2031
2032
    public function testBelongsToPolymorphic()
2033
    {
2034
        $company = new DataObjectTest\Company();
2035
        $ceo = new DataObjectTest\CEO();
2036
2037
        $company->write();
2038
        $ceo->write();
2039
2040
        // Test belongs_to assignment
2041
        $company->OwnerID = $ceo->ID;
0 ignored issues
show
Bug Best Practice introduced by
The property OwnerID does not exist on SilverStripe\ORM\Tests\DataObjectTest\Company. Since you implemented __set, consider adding a @property annotation.
Loading history...
2042
        $company->OwnerClass = DataObjectTest\CEO::class;
0 ignored issues
show
Bug Best Practice introduced by
The property OwnerClass does not exist on SilverStripe\ORM\Tests\DataObjectTest\Company. Since you implemented __set, consider adding a @property annotation.
Loading history...
2043
        $company->write();
2044
2045
        $this->assertEquals($company->ID, $ceo->CompanyOwned()->ID, 'belongs_to returns the right results.');
0 ignored issues
show
Bug introduced by
The method CompanyOwned() does not exist on SilverStripe\ORM\Tests\DataObjectTest\CEO. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2045
        $this->assertEquals($company->ID, $ceo->/** @scrutinizer ignore-call */ CompanyOwned()->ID, 'belongs_to returns the right results.');
Loading history...
2046
        $this->assertInstanceOf(
2047
            DataObjectTest\Company::class,
2048
            $ceo->CompanyOwned(),
2049
            'belongs_to returns the right results.'
2050
        );
2051
2052
        // Test automatic creation of class where no assigment exists
2053
        $ceo = new DataObjectTest\CEO();
2054
        $ceo->write();
2055
2056
        $this->assertTrue(
2057
            $ceo->CompanyOwned() instanceof DataObjectTest\Company,
2058
            'DataObjects across polymorphic belongs_to relations are automatically created.'
2059
        );
2060
        $this->assertEquals($ceo->ID, $ceo->CompanyOwned()->OwnerID, 'Remote IDs are automatically set.');
2061
        $this->assertInstanceOf($ceo->CompanyOwned()->OwnerClass, $ceo, 'Remote class is automatically  set');
2062
2063
        // Write object with components
2064
        $ceo->write(false, false, false, true);
2065
        $this->assertTrue($ceo->CompanyOwned()->isInDB(), 'write() writes belongs_to components to the database.');
2066
2067
        $newCEO = DataObject::get_by_id(DataObjectTest\CEO::class, $ceo->ID);
2068
        $this->assertEquals(
2069
            $ceo->CompanyOwned()->ID,
2070
            $newCEO->CompanyOwned()->ID,
0 ignored issues
show
Bug introduced by
The method CompanyOwned() does not exist on SilverStripe\ORM\DataObject. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2070
            $newCEO->/** @scrutinizer ignore-call */ 
2071
                     CompanyOwned()->ID,
Loading history...
2071
            'polymorphic belongs_to can be retrieved from the database.'
2072
        );
2073
    }
2074
2075
    /**
2076
     * @expectedException LogicException
2077
     */
2078
    public function testInvalidate()
2079
    {
2080
        $do = new DataObjectTest\Fixture();
2081
        $do->write();
2082
2083
        $do->delete();
2084
2085
        $do->delete(); // Prohibit invalid object manipulation
2086
        $do->write();
2087
        $do->duplicate();
2088
    }
2089
2090
    public function testToMap()
2091
    {
2092
        $obj = $this->objFromFixture(DataObjectTest\SubTeam::class, 'subteam1');
2093
2094
        $map = $obj->toMap();
2095
2096
        $this->assertArrayHasKey('ID', $map, 'Contains base fields');
2097
        $this->assertArrayHasKey('Title', $map, 'Contains fields from parent class');
2098
        $this->assertArrayHasKey('SubclassDatabaseField', $map, 'Contains fields from concrete class');
2099
2100
        $this->assertEquals(
2101
            $obj->ID,
2102
            $map['ID'],
2103
            'Contains values from base fields'
2104
        );
2105
        $this->assertEquals(
2106
            $obj->Title,
2107
            $map['Title'],
2108
            'Contains values from parent class fields'
2109
        );
2110
        $this->assertEquals(
2111
            $obj->SubclassDatabaseField,
0 ignored issues
show
Bug Best Practice introduced by
The property SubclassDatabaseField does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
2112
            $map['SubclassDatabaseField'],
2113
            'Contains values from concrete class fields'
2114
        );
2115
2116
        $newObj = new DataObjectTest\SubTeam();
0 ignored issues
show
Unused Code introduced by
The assignment to $newObj is dead and can be removed.
Loading history...
2117
        $this->assertArrayHasKey('Title', $map, 'Contains null fields');
2118
    }
2119
2120
    public function testIsEmpty()
2121
    {
2122
        $objEmpty = new DataObjectTest\Team();
2123
        $this->assertTrue($objEmpty->isEmpty(), 'New instance without populated defaults is empty');
2124
2125
        $objEmpty->Title = '0'; //
2126
        $this->assertFalse($objEmpty->isEmpty(), 'Zero value in attribute considered non-empty');
2127
    }
2128
2129
    public function testRelField()
2130
    {
2131
        $captain1 = $this->objFromFixture(DataObjectTest\Player::class, 'captain1');
2132
        // Test traversal of a single has_one
2133
        $this->assertEquals("Team 1", $captain1->relField('FavouriteTeam.Title'));
2134
        // Test direct field access
2135
        $this->assertEquals("Captain", $captain1->relField('FirstName'));
2136
2137
        // Test empty link
2138
        $captain2 = $this->objFromFixture(DataObjectTest\Player::class, 'captain2');
2139
        $this->assertEmpty($captain2->relField('FavouriteTeam.Title'));
2140
        $this->assertNull($captain2->relField('FavouriteTeam.ReturnsNull'));
2141
        $this->assertNull($captain2->relField('FavouriteTeam.ReturnsNull.Title'));
2142
2143
        $player = $this->objFromFixture(DataObjectTest\Player::class, 'player2');
2144
        // Test that we can traverse more than once, and that arbitrary methods are okay
2145
        $this->assertEquals("Team 1", $player->relField('Teams.First.Title'));
2146
2147
        $newPlayer = new DataObjectTest\Player();
2148
        $this->assertNull($newPlayer->relField('Teams.First.Title'));
2149
2150
        // Test that relField works on db field manipulations
2151
        $comment = $this->objFromFixture(DataObjectTest\TeamComment::class, 'comment3');
2152
        $this->assertEquals("PHIL IS A UNIQUE GUY, AND COMMENTS ON TEAM2", $comment->relField('Comment.UpperCase'));
2153
2154
        // relField throws exception on invalid properties
2155
        $this->expectException(LogicException::class);
2156
        $this->expectExceptionMessage("Not is not a relation/field on " . DataObjectTest\TeamComment::class);
2157
        $comment->relField('Not.A.Field');
2158
    }
2159
2160
    public function testRelObject()
2161
    {
2162
        $captain1 = $this->objFromFixture(DataObjectTest\Player::class, 'captain1');
2163
2164
        // Test traversal of a single has_one
2165
        $this->assertInstanceOf(DBVarchar::class, $captain1->relObject('FavouriteTeam.Title'));
2166
        $this->assertEquals("Team 1", $captain1->relObject('FavouriteTeam.Title')->getValue());
2167
2168
        // Test empty link
2169
        $captain2 = $this->objFromFixture(DataObjectTest\Player::class, 'captain2');
2170
        $this->assertEmpty($captain2->relObject('FavouriteTeam.Title')->getValue());
2171
        $this->assertNull($captain2->relObject('FavouriteTeam.ReturnsNull.Title'));
2172
2173
        // Test direct field access
2174
        $this->assertInstanceOf(DBBoolean::class, $captain1->relObject('IsRetired'));
2175
        $this->assertEquals(1, $captain1->relObject('IsRetired')->getValue());
2176
2177
        $player = $this->objFromFixture(DataObjectTest\Player::class, 'player2');
2178
        // Test that we can traverse more than once, and that arbitrary methods are okay
2179
        $this->assertInstanceOf(DBVarchar::class, $player->relObject('Teams.First.Title'));
2180
        $this->assertEquals("Team 1", $player->relObject('Teams.First.Title')->getValue());
2181
2182
        // relObject throws exception on invalid properties
2183
        $this->expectException(LogicException::class);
2184
        $this->expectExceptionMessage("Not is not a relation/field on " . DataObjectTest\Player::class);
2185
        $player->relObject('Not.A.Field');
2186
    }
2187
2188
    public function testLateStaticBindingStyle()
2189
    {
2190
        // Confirm that DataObjectTest_Player::get() operates as excepted
2191
        $this->assertEquals(4, DataObjectTest\Player::get()->count());
2192
        $this->assertInstanceOf(DataObjectTest\Player::class, DataObjectTest\Player::get()->first());
2193
2194
        // You can't pass arguments to LSB syntax - use the DataList methods instead.
2195
        $this->expectException(InvalidArgumentException::class);
2196
2197
        DataObjectTest\Player::get(null, "\"ID\" = 1");
2198
    }
2199
2200
    /**
2201
     * @expectedException \InvalidArgumentException
2202
     */
2203
    public function testBrokenLateStaticBindingStyle()
2204
    {
2205
        // If you call DataObject::get() you have to pass a first argument
2206
        DataObject::get();
2207
    }
2208
2209
    public function testBigIntField()
2210
    {
2211
        $staff = new DataObjectTest\Staff();
2212
        $staff->Salary = PHP_INT_MAX;
0 ignored issues
show
Bug Best Practice introduced by
The property Salary does not exist on SilverStripe\ORM\Tests\DataObjectTest\Staff. Since you implemented __set, consider adding a @property annotation.
Loading history...
2213
        $staff->write();
2214
        $this->assertEquals(PHP_INT_MAX, DataObjectTest\Staff::get()->byID($staff->ID)->Salary);
0 ignored issues
show
Bug Best Practice introduced by
The property Salary does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
2215
    }
2216
2217
    public function testGetOneMissingValueReturnsNull()
2218
    {
2219
2220
        // Test that missing values return null
2221
        $this->assertEquals(null, DataObject::get_one(
2222
            DataObjectTest\TeamComment::class,
2223
            ['"DataObjectTest_TeamComment"."Name"' => 'does not exists']
2224
        ));
2225
    }
2226
2227
    public function testSetFieldWithArrayOnScalarOnlyField()
2228
    {
2229
        $this->expectException(InvalidArgumentException::class);
2230
        $do = Company::singleton();
2231
        $do->FoundationYear = '1984';
2232
        $do->FoundationYear = array('Amount' => 123, 'Currency' => 'CAD');
2233
        $this->assertEmpty($do->FoundationYear);
2234
    }
2235
2236
    public function testSetFieldWithArrayOnCompositeField()
2237
    {
2238
        $do = Company::singleton();
2239
        $do->SalaryCap = array('Amount' => 123456, 'Currency' => 'CAD');
2240
        $this->assertNotEmpty($do->SalaryCap);
2241
    }
2242
}
2243