Passed
Push — 4 ( 58a846...ebeaf3 )
by Daniel
08:20
created

DataObjectSchemaGenerationTest   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 311
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 311
rs 10
c 0
b 0
f 0
wmc 8

8 Methods

Rating   Name   Duplication   Size   Complexity  
B testIndexesDontRerequestChanges() 0 31 1
A testSortFieldBecomeIndexes() 0 59 1
A testClassNameSpecGeneration() 0 59 1
B testTableCaseFixed() 0 33 1
A testFieldsDontRerequestChanges() 0 16 1
A setUpBeforeClass() 0 12 1
B testFieldsRequestChanges() 0 24 1
B testIndexesRerequestChanges() 0 26 1
1
<?php
2
3
namespace SilverStripe\ORM\Tests;
4
5
use SilverStripe\Core\Config\Config;
6
use SilverStripe\ORM\Connect\MySQLSchemaManager;
7
use SilverStripe\ORM\DB;
8
use SilverStripe\ORM\FieldType\DBClassName;
9
use SilverStripe\ORM\DataObject;
10
use SilverStripe\Dev\SapphireTest;
11
use SilverStripe\ORM\Tests\DataObjectSchemaGenerationTest\SortedObject;
12
use SilverStripe\ORM\Tests\DataObjectSchemaGenerationTest\TestIndexObject;
13
use SilverStripe\ORM\Tests\DataObjectSchemaGenerationTest\TestObject;
14
15
class DataObjectSchemaGenerationTest extends SapphireTest
16
{
17
    protected static $extra_dataobjects = array(
18
        TestObject::class,
19
        TestIndexObject::class,
20
        SortedObject::class,
21
    );
22
23
    public static function setUpBeforeClass()
24
    {
25
        // Start tests
26
        static::start();
27
28
        // enable fulltext option on this table
29
        TestIndexObject::config()->update(
30
            'create_table_options',
31
            array(MySQLSchemaManager::ID => 'ENGINE=MyISAM')
32
        );
33
34
        parent::setUpBeforeClass();
35
    }
36
37
    /**
38
     * @skipUpgrade
39
     */
40
    public function testTableCaseFixed()
41
    {
42
        DB::quiet();
43
44
        // Modify table case
45
        DB::get_schema()->renameTable(
46
            'DataObjectSchemaGenerationTest_DO',
47
            '__TEMP__DataOBJECTSchemaGenerationTest_do'
48
        );
49
        DB::get_schema()->renameTable(
50
            '__TEMP__DataOBJECTSchemaGenerationTest_do',
51
            'DataOBJECTSchemaGenerationTest_do'
52
        );
53
54
        // Check table
55
        $tables = DB::table_list();
56
        $this->assertEquals(
57
            'DataOBJECTSchemaGenerationTest_do',
58
            $tables['dataobjectschemagenerationtest_do']
59
        );
60
61
        // Rebuild table
62
        DB::get_schema()->schemaUpdate(
63
            function () {
64
                TestObject::singleton()->requireTable();
65
            }
66
        );
67
68
        // Check table
69
        $tables = DB::table_list();
70
        $this->assertEquals(
71
            'DataObjectSchemaGenerationTest_DO',
72
            $tables['dataobjectschemagenerationtest_do']
73
        );
74
    }
75
76
    /**
77
     * Check that once a schema has been generated, then it doesn't need any more updating
78
     */
79
    public function testFieldsDontRerequestChanges()
80
    {
81
        $schema = DB::get_schema();
82
        $test = $this;
83
        DB::quiet();
84
85
        // Table will have been initially created by the $extraDataObjects setting
86
87
        // Verify that it doesn't need to be recreated
88
        $schema->schemaUpdate(
89
            function () use ($test, $schema) {
90
                $obj = new TestObject();
91
                $obj->requireTable();
92
                $needsUpdating = $schema->doesSchemaNeedUpdating();
93
                $schema->cancelSchemaUpdate();
94
                $test->assertFalse($needsUpdating);
95
            }
96
        );
97
    }
98
99
    /**
100
     * Check that updates to a class fields are reflected in the database
101
     */
102
    public function testFieldsRequestChanges()
103
    {
104
        $schema = DB::get_schema();
105
        $test = $this;
106
        DB::quiet();
107
108
        // Table will have been initially created by the $extraDataObjects setting
109
110
        // Let's insert a new field here
111
        TestObject::config()->update(
112
            'db',
113
            array(
114
            'SecretField' => 'Varchar(100)'
115
            )
116
        );
117
118
        // Verify that the above extra field triggered a schema update
119
        $schema->schemaUpdate(
120
            function () use ($test, $schema) {
121
                $obj = new TestObject();
122
                $obj->requireTable();
123
                $needsUpdating = $schema->doesSchemaNeedUpdating();
124
                $schema->cancelSchemaUpdate();
125
                $test->assertTrue($needsUpdating);
126
            }
127
        );
128
    }
129
130
    /**
131
     * Check that indexes on a newly generated class do not subsequently request modification
132
     */
133
    public function testIndexesDontRerequestChanges()
134
    {
135
        $schema = DB::get_schema();
136
        $test = $this;
137
        DB::quiet();
138
139
        // Table will have been initially created by the $extraDataObjects setting
140
141
        // Verify that it doesn't need to be recreated
142
        $schema->schemaUpdate(
143
            function () use ($test, $schema) {
144
                $obj = new TestIndexObject();
145
                $obj->requireTable();
146
                $needsUpdating = $schema->doesSchemaNeedUpdating();
147
                $schema->cancelSchemaUpdate();
148
                $test->assertFalse($needsUpdating);
149
            }
150
        );
151
152
        // Test with alternate index format, although these indexes are the same
153
        $config = TestIndexObject::config();
154
        $config->set('indexes', $config->get('indexes_alt'));
155
156
        // Verify that it still doesn't need to be recreated
157
        $schema->schemaUpdate(
158
            function () use ($test, $schema) {
159
                $obj2 = new TestIndexObject();
160
                $obj2->requireTable();
161
                $needsUpdating = $schema->doesSchemaNeedUpdating();
162
                $schema->cancelSchemaUpdate();
163
                $test->assertFalse($needsUpdating);
164
            }
165
        );
166
    }
167
168
    /**
169
     * Check that updates to a dataobject's indexes are reflected in DDL
170
     */
171
    public function testIndexesRerequestChanges()
172
    {
173
        $schema = DB::get_schema();
174
        $test = $this;
175
        DB::quiet();
176
177
        // Table will have been initially created by the $extraDataObjects setting
178
179
        // Update the SearchFields index here
180
        TestIndexObject::config()->update(
181
            'indexes',
182
            [
183
                'SearchFields' => [
184
                    'columns' => ['Title'],
185
                ],
186
            ]
187
        );
188
189
        // Verify that the above index change triggered a schema update
190
        $schema->schemaUpdate(
191
            function () use ($test, $schema) {
192
                $obj = new TestIndexObject();
193
                $obj->requireTable();
194
                $needsUpdating = $schema->doesSchemaNeedUpdating();
195
                $schema->cancelSchemaUpdate();
196
                $test->assertTrue($needsUpdating);
197
            }
198
        );
199
    }
200
201
    /**
202
     * Tests the generation of the ClassName spec and ensure it's not unnecessarily influenced
203
     * by the order of classnames of existing records
204
     * @skipUpgrade
205
     */
206
    public function testClassNameSpecGeneration()
207
    {
208
        $schema = DataObject::getSchema();
209
210
        // Test with blank entries
211
        DBClassName::clear_classname_cache();
212
        $do1 = new TestObject();
213
        $fields = $schema->databaseFields(TestObject::class, false);
214
        $this->assertEquals("DBClassName", $fields['ClassName']);
215
        $this->assertEquals(
216
            [
217
                TestObject::class,
218
                TestIndexObject::class,
219
            ],
220
            $do1->dbObject('ClassName')->getEnum()
0 ignored issues
show
Bug introduced by
The method getEnum() does not exist on SilverStripe\ORM\FieldType\DBField. 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

220
            $do1->dbObject('ClassName')->/** @scrutinizer ignore-call */ getEnum()
Loading history...
221
        );
222
223
224
        // Test with instance of subclass
225
        $item1 = new TestIndexObject();
226
        $item1->write();
227
        DBClassName::clear_classname_cache();
228
        $this->assertEquals(
229
            [
230
                TestObject::class,
231
                TestIndexObject::class,
232
            ],
233
            $item1->dbObject('ClassName')->getEnum()
234
        );
235
        $item1->delete();
236
237
        // Test with instance of main class
238
        $item2 = new TestObject();
239
        $item2->write();
240
        DBClassName::clear_classname_cache();
241
        $this->assertEquals(
242
            [
243
                TestObject::class,
244
                TestIndexObject::class,
245
            ],
246
            $item2->dbObject('ClassName')->getEnum()
247
        );
248
        $item2->delete();
249
250
        // Test with instances of both classes
251
        $item1 = new TestIndexObject();
252
        $item1->write();
253
        $item2 = new TestObject();
254
        $item2->write();
255
        DBClassName::clear_classname_cache();
256
        $this->assertEquals(
257
            [
258
                TestObject::class,
259
                TestIndexObject::class,
260
            ],
261
            $item1->dbObject('ClassName')->getEnum()
262
        );
263
        $item1->delete();
264
        $item2->delete();
265
    }
266
267
    public function testSortFieldBecomeIndexes()
268
    {
269
        $indexes = DataObject::getSchema()->databaseIndexes(SortedObject::class);
270
        $this->assertContains([
271
            'type' => 'index',
272
            'columns' => ['Sort'],
273
        ], $indexes);
274
        DataObject::getSchema()->reset();
275
        Config::inst()->update(SortedObject::class, 'default_sort', 'Sort ASC');
0 ignored issues
show
Bug introduced by
The method update() does not exist on SilverStripe\Config\Coll...nfigCollectionInterface. It seems like you code against a sub-type of SilverStripe\Config\Coll...nfigCollectionInterface such as SilverStripe\Config\Coll...\MemoryConfigCollection. ( Ignorable by Annotation )

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

275
        Config::inst()->/** @scrutinizer ignore-call */ update(SortedObject::class, 'default_sort', 'Sort ASC');
Loading history...
276
        $indexes = DataObject::getSchema()->databaseIndexes(SortedObject::class);
277
        $this->assertContains([
278
            'type' => 'index',
279
            'columns' => ['Sort'],
280
        ], $indexes);
281
        DataObject::getSchema()->reset();
282
        Config::inst()->update(SortedObject::class, 'default_sort', 'Sort DESC');
283
        $indexes = DataObject::getSchema()->databaseIndexes(SortedObject::class);
284
        $this->assertContains([
285
            'type' => 'index',
286
            'columns' => ['Sort'],
287
        ], $indexes);
288
        DataObject::getSchema()->reset();
289
        Config::inst()->update(SortedObject::class, 'default_sort', '"Sort" DESC');
290
        $indexes = DataObject::getSchema()->databaseIndexes(SortedObject::class);
291
        $this->assertContains([
292
            'type' => 'index',
293
            'columns' => ['Sort'],
294
        ], $indexes);
295
        DataObject::getSchema()->reset();
296
        Config::inst()->update(SortedObject::class, 'default_sort', '"DataObjectSchemaGenerationTest_SortedObject"."Sort" ASC');
297
        $indexes = DataObject::getSchema()->databaseIndexes(SortedObject::class);
298
        $this->assertContains([
299
            'type' => 'index',
300
            'columns' => ['Sort'],
301
        ], $indexes);
302
        DataObject::getSchema()->reset();
303
        Config::inst()->update(SortedObject::class, 'default_sort', '"Sort" DESC, "Title" ASC');
304
        $indexes = DataObject::getSchema()->databaseIndexes(SortedObject::class);
305
        $this->assertContains([
306
            'type' => 'index',
307
            'columns' => ['Sort'],
308
        ], $indexes);
309
        $this->assertContains([
310
            'type' => 'index',
311
            'columns' => ['Title'],
312
        ], $indexes);
313
        DataObject::getSchema()->reset();
314
        // make sure that specific indexes aren't overwritten
315
        Config::inst()->update(SortedObject::class, 'indexes', [
316
            'Sort' => [
317
                'type' => 'unique',
318
                'columns' => ['Sort'],
319
            ],
320
        ]);
321
        $indexes = DataObject::getSchema()->databaseIndexes(SortedObject::class);
322
        $this->assertContains([
323
            'type' => 'unique',
324
            'columns' => ['Sort'],
325
        ], $indexes);
326
    }
327
}
328