Total Complexity | 50 |
Total Lines | 409 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like SchemaTest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use SchemaTest, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
33 | class SchemaTest extends LoggedInTest { |
||
34 | |||
35 | protected static $adodb; |
||
36 | protected static $db; |
||
37 | protected static $schema_proc; |
||
38 | protected static $test_app = 'login'; |
||
39 | |||
40 | // define a test-table to create |
||
41 | protected static $test_tables = array( |
||
42 | 'schema_proc_test' => array( |
||
43 | 'fd' => array( |
||
44 | 'test_auto' => array('type' => 'auto'), |
||
45 | 'test_int4' => array('type' => 'int','precision' => '4'), |
||
46 | 'test_varchar' => array('type' => 'varchar','precision' => '128'), |
||
47 | 'test_char' => array('type' => 'char','precision' => '10'), |
||
48 | 'test_timestamp' => array('type' => 'timestamp','default'=>'current_timestamp'), |
||
49 | 'test_text' => array('type' => 'text'), |
||
50 | 'test_blob' => array('type' => 'blob'), |
||
51 | ), |
||
52 | 'pk' => array('test_auto'), |
||
53 | 'fk' => array(), |
||
54 | 'ix' => array(array('test_char','test_varchar'),'test_varchar',array('test_text','options'=>array('mysql'=>'FULLTEXT','sapdb'=>false,'maxdb'=>false,'pgsql'=>false,'mssql'=>false))), |
||
55 | 'uc' => array('test_char') |
||
56 | ), |
||
57 | ); |
||
58 | |||
59 | /** |
||
60 | * Get a database connection |
||
61 | */ |
||
62 | public static function setUpBeforeClass() : void |
||
63 | { |
||
64 | parent::setUpBeforeClass(); |
||
65 | |||
66 | // now we should have a valid db-connection |
||
67 | self::$adodb = $GLOBALS['egw']->ADOdb; |
||
68 | self::$db = $GLOBALS['egw']->db; |
||
69 | |||
70 | // Show lots of debug |
||
71 | //self::$db->query_log = 'php://stdout'; |
||
72 | |||
73 | Db::set_table_definitions(self::$test_app, 'schema_proc_test', self::$test_tables['schema_proc_test']); |
||
74 | |||
75 | // dropping test-tables, if they are there from a previous failed run |
||
76 | self::$schema_proc = new Schema(self::$db->Type); |
||
77 | foreach(self::$adodb->MetaTables() as $table) |
||
78 | { |
||
79 | $table = strtolower($table); |
||
80 | if (strstr($table,'schema_proc')) |
||
81 | { |
||
82 | $aSql = self::$schema_proc->dict->DropTableSQL($table); |
||
83 | self::$schema_proc->ExecuteSqlArray($aSql,1,"DropTableSQL('%1') = %2",$table,$aSql); |
||
84 | } |
||
85 | } |
||
86 | } |
||
87 | |||
88 | /** |
||
89 | * Try to create test tables, check to see if it worked |
||
90 | */ |
||
91 | public function testCreateTable() |
||
92 | { |
||
93 | foreach(self::$test_tables as $name => $definition) |
||
94 | { |
||
95 | self::$schema_proc->CreateTable($name,$definition); |
||
96 | |||
97 | $columns = self::$adodb->MetaColumns($name); |
||
98 | $this->assertNotFalse($columns); |
||
99 | $this->assertGreaterThan(0, count($columns)); |
||
100 | |||
101 | // check if all columns are there |
||
102 | foreach($definition['fd'] as $column => $data) |
||
103 | { |
||
104 | $this->check_column($column,$columns); |
||
105 | } |
||
106 | |||
107 | // check if all indexes are there |
||
108 | $indexes = self::$adodb->MetaIndexes($name,true); |
||
109 | $this->assertNotFalse($indexes); |
||
110 | if ($indexes !== False) |
||
111 | { |
||
112 | foreach(array('ix','uc') as $kind) |
||
113 | { |
||
114 | foreach($definition[$kind] as $key => $idx) |
||
115 | { |
||
116 | $this->check_index($idx,$kind=='uc',$indexes); |
||
117 | } |
||
118 | } |
||
119 | if (count($definition['pk'])) $this->check_index($definition['pk'],True,$indexes); |
||
120 | } |
||
121 | } |
||
122 | } |
||
123 | |||
124 | /** |
||
125 | * Try to insert some content into the created table(s) |
||
126 | * |
||
127 | * @depends testCreateTable |
||
128 | */ |
||
129 | public function testInsertContent() |
||
150 | ), |
||
151 | ) |
||
152 | ); |
||
153 | } |
||
154 | |||
155 | /** |
||
156 | * Try to update existing content |
||
157 | * |
||
158 | * @depends testInsertContent |
||
159 | */ |
||
160 | public function testUpdateContent() |
||
161 | { |
||
162 | // updating blob's and other columns |
||
163 | self::$db->update('schema_proc_test', array( |
||
164 | 'test_int4' => 99, |
||
165 | 'test_char' => 'abcdefghij', |
||
166 | 'test_text' => 'This is a test-value for the text-column', |
||
167 | 'test_blob' => 'This is a test-value for the blob-column', |
||
168 | ), array('test_auto'=>1), __LINE__, __FILE__, self::$test_app); |
||
169 | |||
170 | // updating only the blob's |
||
171 | self::$db->update('schema_proc_test',array( |
||
172 | 'test_text' => 'This is a test-value for the text-column, 2.row', |
||
173 | 'test_blob' => 'This is a test-value for the blob-column, 2.row', |
||
174 | ), array('test_auto'=>2), __LINE__, __FILE__, self::$test_app); |
||
175 | |||
176 | // db::update uses UpdateBlob only for MaxDB at the moment, it works for MySql too, but fails for postgres with text / CLOB's |
||
177 | // $adodb->UpdateBlob('schema_proc_test','test_text','This is a test-value for the text-column, 2.row','test_auto=2','CLOB'); |
||
178 | // $adodb->UpdateBlob('schema_proc_test','test_blob','This is a test-value for the blob-column, 2.row','test_auto=2','BLOB'); |
||
179 | |||
180 | $this->check_content(self::$adodb->GetAll("SELECT * FROM schema_proc_test"),array( |
||
181 | array( |
||
182 | 'test_auto' => 1, 'test_int4' => 99, 'test_varchar' => 'Hallo Ralf','test_char' => 'abcdefghij', |
||
183 | 'test_text' => 'This is a test-value for the text-column', |
||
184 | 'test_blob'=>'This is a test-value for the blob-column', |
||
185 | ), |
||
186 | array( |
||
187 | 'test_auto' => 2, 'test_int4' => 2, 'test_varchar' => 'Hallo wer noch?','test_char' => '9876543210', |
||
188 | 'test_text' => 'This is a test-value for the text-column, 2.row', |
||
189 | 'test_blob'=>'This is a test-value for the blob-column, 2.row', |
||
190 | ), |
||
191 | )); |
||
192 | } |
||
193 | |||
194 | /** |
||
195 | * Drop the test_blob column |
||
196 | * |
||
197 | * @depends testCreateTable |
||
198 | */ |
||
199 | public function testDropColumn() |
||
200 | { |
||
201 | $new_table_def = $test_tables['schema_proc_test']; |
||
|
|||
202 | unset($new_table_def['fd']['test_blob']); |
||
203 | self::$schema_proc->DropColumn('schema_proc_test',$new_table_def,'test_blob'); |
||
204 | $this->check_column('test_blob',self::$adodb->MetaColumns('schema_proc_test'),False); |
||
205 | } |
||
206 | |||
207 | /** |
||
208 | * Alter the test_char column |
||
209 | * |
||
210 | * @depends testCreateTable |
||
211 | */ |
||
212 | public function testAlterColumn() |
||
213 | { |
||
214 | self::$schema_proc->AlterColumn('schema_proc_test','test_char',array('type' => 'varchar','precision' => 32)); |
||
215 | $this->check_column_type('test_char','varchar',32,self::$adodb->MetaColumns('schema_proc_test')); |
||
216 | } |
||
217 | |||
218 | /** |
||
219 | * Add a column |
||
220 | * |
||
221 | * @depends testCreateTable |
||
222 | */ |
||
223 | public function testAddColumn() |
||
224 | { |
||
225 | self::$schema_proc->AddColumn('schema_proc_test','test_bool',array('type' => 'bool')); |
||
226 | $this->check_column('test_bool',self::$adodb->MetaColumns('schema_proc_test')); |
||
227 | } |
||
228 | |||
229 | /** |
||
230 | * Rename a column |
||
231 | * |
||
232 | * @depends testCreateTable |
||
233 | */ |
||
234 | public function testRenameColumn() |
||
235 | { |
||
236 | self::$schema_proc->RenameColumn('schema_proc_test','test_timestamp','test_time'); |
||
237 | $this->check_column('test_timestamp',self::$adodb->MetaColumns('schema_proc_test'),false); |
||
238 | $this->check_column('test_time',self::$adodb->MetaColumns('schema_proc_test')); |
||
239 | } |
||
240 | |||
241 | /** |
||
242 | * Rename a table |
||
243 | * |
||
244 | * @depends testCreateTable |
||
245 | */ |
||
246 | public function testRenameTable() |
||
247 | { |
||
248 | self::$schema_proc->RenameTable('schema_proc_test','schema_proc_renamed'); |
||
249 | $tables = self::$adodb->MetaTables(); |
||
250 | $this->check_table('schema_proc_test',$tables,False); |
||
251 | $this->check_table('schema_proc_renamed',$tables); |
||
252 | } |
||
253 | |||
254 | /** |
||
255 | * @depends testRenameTable |
||
256 | */ |
||
257 | public function testRenameColumnWithIndex() |
||
258 | { |
||
259 | self::$schema_proc->RenameColumn('schema_proc_renamed','test_varchar','test_varchar_renamed'); |
||
260 | $columns = self::$adodb->MetaColumns('schema_proc_renamed'); |
||
261 | $this->check_column('test_varchar',$columns,False); |
||
262 | $this->check_column('test_varchar_renamed',$columns); |
||
263 | $indexes = self::$adodb->MetaIndexes('schema_proc_renamed'); |
||
264 | if ($indexes !== False) |
||
265 | { |
||
266 | $this->check_index('test_varchar',False,$indexes,False); |
||
267 | $this->check_index('test_varchar_renamed',False,$indexes); |
||
268 | } |
||
269 | else |
||
270 | { |
||
271 | $this->markTestIncomplete(); |
||
272 | } |
||
273 | } |
||
274 | |||
275 | /** |
||
276 | * @depends testRenameColumnWithIndex |
||
277 | */ |
||
278 | public function testDropIndex() |
||
279 | { |
||
280 | self::$schema_proc->DropIndex('schema_proc_renamed',array('test_char','test_varchar_renamed')); |
||
281 | $indexes = self::$adodb->MetaIndexes('schema_proc_renamed'); |
||
282 | if ($indexes !== False) |
||
283 | { |
||
284 | $this->check_index(array('test_char','test_varchar_renamed'),False,$indexes,False); |
||
285 | } |
||
286 | else |
||
287 | { |
||
288 | $this->markTestIncomplete(); |
||
289 | } |
||
290 | } |
||
291 | |||
292 | /** |
||
293 | * @depends testDropIndex |
||
294 | */ |
||
295 | public function testInsertMoreContent() |
||
296 | { |
||
297 | self::$db->query("INSERT INTO schema_proc_renamed (test_int4,test_varchar_renamed,test_char) VALUES (10,'Hallo Hallo Hallo ...','12345678901234567890123456789012')"); |
||
298 | $this->check_content(self::$adodb->GetAll("SELECT * FROM schema_proc_renamed"),array( |
||
299 | array('test_auto' => 1, 'test_int4' => 99, 'test_varchar_renamed' => 'Hallo Ralf','test_char' => 'abcdefghij'), |
||
300 | array('test_auto' => 2, 'test_int4' => 2, 'test_varchar_renamed' => 'Hallo wer noch?','test_char' => '9876543210'), |
||
301 | array('test_auto' => 3, 'test_int4' => 10, 'test_varchar_renamed' => 'Hallo Hallo Hallo ...','test_char' => '12345678901234567890123456789012'), |
||
302 | )); |
||
303 | } |
||
304 | |||
305 | /** |
||
306 | * @depends testInsertMoreContent |
||
307 | */ |
||
308 | public function testDropTable() |
||
309 | { |
||
310 | foreach(self::$adodb->MetaTables() as $table) |
||
311 | { |
||
312 | $table = strtolower($table); |
||
313 | if (strstr($table,'schema_proc')) |
||
314 | { |
||
315 | $aSql = self::$schema_proc->dict->DropTableSQL($table); |
||
316 | self::$schema_proc->ExecuteSqlArray($aSql,1,"DropTableSQL('%1') = %2",$table,$aSql); |
||
317 | } |
||
318 | } |
||
319 | } |
||
320 | |||
321 | |||
322 | /** |
||
323 | * Checks if table $table exists or not |
||
324 | * |
||
325 | * @param string $table table-name |
||
326 | * @param array $tables array of table-names from call to MetaTables() |
||
327 | * @param boolean $existence =true should we check for existence or non-existence, default existence |
||
328 | */ |
||
329 | protected function check_table($table,$tables,$existence=True) |
||
334 | } |
||
335 | |||
336 | /** |
||
337 | * Checks if $column exists or not |
||
338 | * |
||
339 | * @param string $column column-name |
||
340 | * @param array $columns array of adodb field objects from MetaColumns($table) |
||
341 | * @param boolean $existence =true should we check for existence or non-existence, default existence |
||
342 | */ |
||
343 | protected function check_column($column,$columns,$existence=True) |
||
344 | { |
||
345 | $exist = isset($columns[$column]) || isset($columns[strtoupper($column)]); |
||
346 | |||
347 | $this->assertEquals($existence, $exist, "Checking for $column"); |
||
348 | } |
||
349 | |||
350 | /** |
||
351 | * Checks the type of a column |
||
352 | * |
||
353 | * @param string $column column-name |
||
354 | * @param string $type column-type as the DB uses it, no eGW type !!! |
||
355 | * @param int $precision precision |
||
356 | * @param array $columns array of adodb field objects from MetaColumns($table) |
||
357 | */ |
||
358 | protected function check_column_type($column,$type,$precision,$columns) |
||
359 | { |
||
360 | static $alternate_types = array( |
||
361 | 'varchar' => array('C'), |
||
362 | 'int' => array('I'), |
||
363 | ); |
||
364 | |||
365 | $data = isset($columns[$column]) ? $columns[$column] : $columns[strtoupper($column)]; |
||
366 | $this->assertInstanceOf('ADOFieldObject', $data, "Column '$column' does not exist."); |
||
367 | $data->type = strtolower($data->type); |
||
368 | |||
369 | $this->assertFalse($data->type != $type && !in_array($data->type,$alternate_types[$type]), |
||
370 | "Column '$column' is NOT of type '$type', but '$data->type'" |
||
371 | ); |
||
372 | |||
373 | if ($precision) |
||
374 | { |
||
375 | $this->assertEquals($precision, $data->max_length, |
||
376 | "Precision of column '$column' is NOT $precision, but $data->precision" |
||
377 | ); |
||
378 | } |
||
379 | } |
||
380 | |||
381 | /** |
||
382 | * Checks if $idx exists or not |
||
383 | * |
||
384 | * @param array $columns array of strings with column-names of that index |
||
385 | * @param boolean $unique unique index or not |
||
386 | * @param array $indexes array of index-describtions from call to MetaIndexes($table) |
||
387 | * @param boolean $_existence =true should we check for existence or none-existence, default existence |
||
388 | */ |
||
389 | protected function check_index($columns,$unique,$indexes,$_existence=True) |
||
390 | { |
||
391 | if (!is_array($columns)) $columns = array($columns); |
||
392 | $existence = $_existence && $columns['options'][$GLOBALS['db']->Type] !== False; |
||
393 | unset($columns['options']); |
||
394 | |||
395 | $exist = False; |
||
396 | $idx_data = array(); |
||
397 | foreach($indexes as $idx_data) |
||
398 | { |
||
399 | if (implode(':',$columns) == strtolower(implode(':',$idx_data['columns']))) |
||
400 | { |
||
401 | $exist = true; |
||
402 | break; |
||
403 | } |
||
404 | } |
||
405 | $this->assertEquals($existence, $exist, |
||
406 | "Index (".implode(', ',$columns).") is ".($existence ? 'missing' : 'still there') |
||
407 | ); |
||
408 | |||
409 | if ($existence) |
||
410 | { |
||
411 | $this->assertEquals($unique, !!$idx_data['unique'], |
||
412 | "Index (".implode(', ',$columns).") is ".($unique ? 'NOT ' : '')."unique" |
||
413 | ); |
||
414 | } |
||
415 | } |
||
416 | |||
417 | /** |
||
418 | * Checks the content written to the table |
||
419 | * |
||
420 | * @param array $is content read from the database via GetAll() |
||
421 | * @param array $should content against which we test |
||
422 | */ |
||
423 | protected function check_content($is,$should) |
||
442 | } |
||
443 | } |