Completed
Pull Request — master (#6203)
by Damian
25:45 queued 16:48
created

testIndexesRerequestChanges()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 13
nc 1
nop 0
dl 0
loc 23
rs 9.0856
c 0
b 0
f 0
1
<?php
2
3
4
use SilverStripe\ORM\Connect\MySQLSchemaManager;
5
use SilverStripe\ORM\DB;
6
use SilverStripe\ORM\FieldType\DBClassName;
7
use SilverStripe\ORM\DataObject;
8
use SilverStripe\Core\Config\Config;
9
use SilverStripe\Dev\SapphireTest;
10
use SilverStripe\Dev\TestOnly;
11
12
13
14
15
class DataObjectSchemaGenerationTest extends SapphireTest {
16
	protected $extraDataObjects = array(
17
		'DataObjectSchemaGenerationTest_DO',
18
		'DataObjectSchemaGenerationTest_IndexDO'
19
	);
20
21
	public function setUpOnce() {
22
23
		// enable fulltext option on this table
24
		Config::inst()->update('DataObjectSchemaGenerationTest_IndexDO', 'create_table_options',
25
			array(MySQLSchemaManager::ID => 'ENGINE=MyISAM'));
26
27
		parent::setUpOnce();
28
	}
29
30
	public function testTableCaseFixed() {
31
		DB::quiet();
32
33
		// Modify table case
34
		DB::get_schema()->renameTable(
35
			'DataObjectSchemaGenerationTest_DO',
36
			'__TEMP__DataOBJECTSchemaGenerationTest_do'
37
		);
38
		DB::get_schema()->renameTable(
39
			'__TEMP__DataOBJECTSchemaGenerationTest_do',
40
			'DataOBJECTSchemaGenerationTest_do'
41
		);
42
43
		// Check table
44
		$tables = DB::table_list();
45
		$this->assertEquals(
46
			'DataOBJECTSchemaGenerationTest_do',
47
			$tables['dataobjectschemagenerationtest_do']
48
		);
49
50
		// Rebuild table
51
		DB::get_schema()->schemaUpdate(function() {
52
			DataObjectSchemaGenerationTest_DO::singleton()->requireTable();
53
		});
54
55
		// Check table
56
		$tables = DB::table_list();
57
		$this->assertEquals(
58
			'DataObjectSchemaGenerationTest_DO',
59
			$tables['dataobjectschemagenerationtest_do']
60
		);
61
	}
62
63
	/**
64
	 * Check that once a schema has been generated, then it doesn't need any more updating
65
	 */
66
	public function testFieldsDontRerequestChanges() {
67
		$schema = DB::get_schema();
68
		$test = $this;
69
		DB::quiet();
70
71
		// Table will have been initially created by the $extraDataObjects setting
72
73
		// Verify that it doesn't need to be recreated
74
		$schema->schemaUpdate(function() use ($test, $schema) {
75
			$obj = new DataObjectSchemaGenerationTest_DO();
76
			$obj->requireTable();
77
			$needsUpdating = $schema->doesSchemaNeedUpdating();
78
			$schema->cancelSchemaUpdate();
79
			$test->assertFalse($needsUpdating);
80
		});
81
	}
82
83
	/**
84
	 * Check that updates to a class fields are reflected in the database
85
	 */
86
	public function testFieldsRequestChanges() {
87
		$schema = DB::get_schema();
88
		$test = $this;
89
		DB::quiet();
90
91
		// Table will have been initially created by the $extraDataObjects setting
92
93
		// Let's insert a new field here
94
		Config::inst()->update('DataObjectSchemaGenerationTest_DO', 'db', array(
95
			'SecretField' => 'Varchar(100)'
96
		));
97
98
		// Verify that the above extra field triggered a schema update
99
		$schema->schemaUpdate(function() use ($test, $schema) {
100
			$obj = new DataObjectSchemaGenerationTest_DO();
101
			$obj->requireTable();
102
			$needsUpdating = $schema->doesSchemaNeedUpdating();
103
			$schema->cancelSchemaUpdate();
104
			$test->assertTrue($needsUpdating);
105
		});
106
	}
107
108
	/**
109
	 * Check that indexes on a newly generated class do not subsequently request modification
110
	 */
111
	public function testIndexesDontRerequestChanges() {
112
		$schema = DB::get_schema();
113
		$test = $this;
114
		DB::quiet();
115
116
		// Table will have been initially created by the $extraDataObjects setting
117
118
		// Verify that it doesn't need to be recreated
119
		$schema->schemaUpdate(function() use ($test, $schema) {
120
			$obj = new DataObjectSchemaGenerationTest_IndexDO();
121
			$obj->requireTable();
122
			$needsUpdating = $schema->doesSchemaNeedUpdating();
123
			$schema->cancelSchemaUpdate();
124
			$test->assertFalse($needsUpdating);
125
		});
126
127
		// Test with alternate index format, although these indexes are the same
128
		Config::inst()->remove('DataObjectSchemaGenerationTest_IndexDO', 'indexes');
129
		Config::inst()->update('DataObjectSchemaGenerationTest_IndexDO', 'indexes',
130
			Config::inst()->get('DataObjectSchemaGenerationTest_IndexDO', 'indexes_alt')
131
		);
132
133
		// Verify that it still doesn't need to be recreated
134
		$schema->schemaUpdate(function() use ($test, $schema) {
135
			$obj2 = new DataObjectSchemaGenerationTest_IndexDO();
136
			$obj2->requireTable();
137
			$needsUpdating = $schema->doesSchemaNeedUpdating();
138
			$schema->cancelSchemaUpdate();
139
			$test->assertFalse($needsUpdating);
140
		});
141
	}
142
143
	/**
144
	 * Check that updates to a dataobject's indexes are reflected in DDL
145
	 */
146
	public function testIndexesRerequestChanges() {
147
		$schema = DB::get_schema();
148
		$test = $this;
149
		DB::quiet();
150
151
		// Table will have been initially created by the $extraDataObjects setting
152
153
		// Update the SearchFields index here
154
		Config::inst()->update('DataObjectSchemaGenerationTest_IndexDO', 'indexes', array(
155
			'SearchFields' => array(
156
				'value' => 'Title'
157
			)
158
		));
159
160
		// Verify that the above index change triggered a schema update
161
		$schema->schemaUpdate(function() use ($test, $schema) {
162
			$obj = new DataObjectSchemaGenerationTest_IndexDO();
163
			$obj->requireTable();
164
			$needsUpdating = $schema->doesSchemaNeedUpdating();
165
			$schema->cancelSchemaUpdate();
166
			$test->assertTrue($needsUpdating);
167
		});
168
	}
169
170
	/**
171
	 * Tests the generation of the ClassName spec and ensure it's not unnecessarily influenced
172
	 * by the order of classnames of existing records
173
	 */
174
	public function testClassNameSpecGeneration() {
175
		$schema = DataObject::getSchema();
176
177
		// Test with blank entries
178
		DBClassName::clear_classname_cache();
179
		$do1 = new DataObjectSchemaGenerationTest_DO();
180
		$fields = $schema->databaseFields(DataObjectSchemaGenerationTest_DO::class, false);
181
		/** @skipUpgrade */
182
		$this->assertEquals("DBClassName", $fields['ClassName']);
183
		$this->assertEquals(
184
			array(
185
				'DataObjectSchemaGenerationTest_DO' => 'DataObjectSchemaGenerationTest_DO',
186
				'DataObjectSchemaGenerationTest_IndexDO' => 'DataObjectSchemaGenerationTest_IndexDO'
187
			),
188
			$do1->dbObject('ClassName')->getEnum()
189
		);
190
191
192
		// Test with instance of subclass
193
		$item1 = new DataObjectSchemaGenerationTest_IndexDO();
194
		$item1->write();
195
		DBClassName::clear_classname_cache();
196
		$this->assertEquals(
197
			array(
198
				'DataObjectSchemaGenerationTest_DO' => 'DataObjectSchemaGenerationTest_DO',
199
				'DataObjectSchemaGenerationTest_IndexDO' => 'DataObjectSchemaGenerationTest_IndexDO'
200
			),
201
			$item1->dbObject('ClassName')->getEnum()
202
		);
203
		$item1->delete();
204
205
		// Test with instance of main class
206
		$item2 = new DataObjectSchemaGenerationTest_DO();
207
		$item2->write();
208
		DBClassName::clear_classname_cache();
209
		$this->assertEquals(
210
			array(
211
				'DataObjectSchemaGenerationTest_DO' => 'DataObjectSchemaGenerationTest_DO',
212
				'DataObjectSchemaGenerationTest_IndexDO' => 'DataObjectSchemaGenerationTest_IndexDO'
213
			),
214
			$item2->dbObject('ClassName')->getEnum()
215
		);
216
		$item2->delete();
217
218
		// Test with instances of both classes
219
		$item1 = new DataObjectSchemaGenerationTest_IndexDO();
220
		$item1->write();
221
		$item2 = new DataObjectSchemaGenerationTest_DO();
222
		$item2->write();
223
		DBClassName::clear_classname_cache();
224
		$this->assertEquals(
225
			array(
226
				'DataObjectSchemaGenerationTest_DO' => 'DataObjectSchemaGenerationTest_DO',
227
				'DataObjectSchemaGenerationTest_IndexDO' => 'DataObjectSchemaGenerationTest_IndexDO'
228
			),
229
			$item1->dbObject('ClassName')->getEnum()
230
		);
231
		$item1->delete();
232
		$item2->delete();
233
	}
234
}
235
236
class DataObjectSchemaGenerationTest_DO extends DataObject implements TestOnly {
237
	private static $db = array(
238
		'Enum1' => 'Enum("A, B, C, D","")',
239
		'Enum2' => 'Enum("A, B, C, D","A")',
240
		'NumberField' => 'Decimal',
241
		'FloatingField' => 'Decimal(10,3,1.1)',
242
		'TextValue' => 'Varchar',
243
		'Date' => 'Datetime',
244
		'MyNumber' => 'Int'
245
	);
246
}
247
248
249
class DataObjectSchemaGenerationTest_IndexDO extends DataObjectSchemaGenerationTest_DO implements TestOnly {
250
	private static $db = array(
251
		'Title' => 'Varchar(255)',
252
		'Content' => 'Text'
253
	);
254
255
	private static $indexes = array(
256
		'NameIndex' => 'unique ("Title")',
257
		'SearchFields' => array(
258
			'type' => 'fulltext',
259
			'name' => 'SearchFields',
260
			'value' => '"Title","Content"'
261
		)
262
	);
263
264
	/** @config */
265
	private static $indexes_alt = array(
266
		'NameIndex' => array(
267
			'type' => 'unique',
268
			'name' => 'NameIndex',
269
			'value' => '"Title"'
270
		),
271
		'SearchFields' => 'fulltext ("Title","Content")'
272
	);
273
}
274