/[drupal]/contributions/modules/deadwood/deadwood.schemaapi.inc
ViewVC logotype

Contents of /contributions/modules/deadwood/deadwood.schemaapi.inc

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.8 - (show annotations) (download) (as text)
Thu Aug 6 20:57:58 2009 UTC (3 months, 2 weeks ago) by solotandem
Branch: MAIN
CVS Tags: DRUPAL-6--1-6, HEAD
Changes since 1.7: +9 -9 lines
File MIME type: text/x-php
Replace messages to screen with writes to a log file; Add .test as a file extension to convert and sort all extensions; Rename 'files' key to to 'deadwood_files' in hook_requirements(); Removing trailing spaces in all files.
1 <?php
2 // $Id: deadwood.schemaapi.inc,v 1.7 2009/03/28 15:13:43 solotandem Exp $
3
4 /**
5 * @file
6 * Generate version upgrade code from 5.x to 6.x.
7 *
8 * The functions in this file match up with the topics in the roadmaps at
9 * http://drupal.org/node/146843 and http://drupal.org/node/114774.
10 *
11 * The functions herein assume the MySQL database is being used. This affects
12 * the type names for table fields. If using a different database, then add
13 * an a require_once statement to the database.mysql-common.inc file.
14 *
15 * Copyright 2008 by Jim Berry ("solotandem", http://drupal.org/user/240748)
16 */
17
18 /**
19 * Find the module name from a function block.
20 *
21 * TODO Move this to coversions.inc.
22 *
23 * @param string $function The function block.
24 * @return string The module name.
25 */
26 function deadwood_get_module_name($function, $hook) {
27 // Get the module name
28 $pattern = '/^function\s*(\w+)_' . $hook . '\s*\(/m';
29 if (!preg_match($pattern, $function, $matches)) {
30 return;
31 }
32 return isset($matches[1]) ? $matches[1] : 'module-name';
33 }
34
35 /*
36 * Read install hook
37 * Parse function name for the module name
38 * Parse 'mysqli' case block
39 * Write schema hook function
40 * Read install hook
41 * Replace table creation contents with
42 * // Create tables.
43 * drupal_install_schema('module-name');
44 * Read uninstall hook
45 * Replace table destruction contents with
46 * // Remove tables.
47 * drupal_uninstall_schema('module-name');
48 * Remove any hook_update_N functions
49 */
50
51 /**
52 * Write the new hook_schema() function.
53 *
54 * @param string $file The file to convert.
55 */
56 function deadwood_convert_hook_schema(&$file) {
57 $hook = 'install';
58 $cur = deadwood_find_hook($hook, $file);
59 $new = $cur;
60 $module_name = deadwood_get_module_name($cur, $hook);
61
62 // Check for 'mysqli' case block.
63 $pattern = '/case\s*\'mysql[i|]\'\s*:\s*(.*?)break;/s';
64 if (!preg_match($pattern, $cur, $matches)) {
65 return;
66 }
67 $queries = explode('db_query', $matches[1]);
68 // Eliminate the first element (usually blank).
69 array_shift($queries);
70
71 $schema = '';
72 $other = array('primary', 'unique', 'index', 'key');
73 foreach ($queries as $query) {
74 // If a 'mysql' case follows a 'mysqli' case, then the regex returns the
75 // 'mysql' line as part of the stuff to be parsed.
76 if (!preg_match('/{(.*)}/', $query, $matches)) {
77 continue;
78 }
79 $table_name = $matches[1];
80
81 $schema .= " \$schema['" . $table_name . "'] = array(\n";
82 $schema .= " 'description' => t('TODO'),\n";
83 $schema .= " 'fields' => array(\n";
84
85 $fields = explode("\n", $query);
86 // Eliminate the first element (usually the create table line).
87 array_shift($fields);
88 // Check for "CREATE TABLE" on a line after the "db_query" line.
89 if (strpos($fields[0], 'CREATE') !== false) {
90 array_shift($fields);
91 }
92
93 // Initialize the index variables.
94 $primary = '';
95 $uniques = array();
96 $indexes = array();
97
98 // Loop on the fields of this table.
99 $done = FALSE;
100 foreach ($fields as $field) {
101 if ($done) {
102 continue;
103 }
104 $field = trim($field);
105 // With MySQL definitions, remove blank lines and the last line of table definition.
106 if ($field == '' || strpos($field, ')') === 0) {
107 $done = TRUE;
108 continue;
109 }
110 // Clean the string before parsing.
111 $field = deadwood_clean_schema_def($field);
112 $tokens = explode(' ', $field);
113 if (count($tokens) < 2) {
114 deadwood_debug_print('Schema field is not defined', 'warning');
115 continue;
116 }
117 // Handle the non-field items.
118 if (in_array(strtolower($tokens[0]), $other)) {
119 // Get index tokens which may include a multi-field key.
120 $tokens = deadwood_get_index_tokens($field);
121 while (count($tokens)) {
122 $token = strtolower(array_shift($tokens));
123 if (!count($tokens)) {
124 continue;
125 }
126 switch ($token) {
127 case 'primary' :
128 // We can rely on the count because we properly parsed any multi-field keys.
129 if (count($tokens) == 2) {
130 if (strtolower($tokens[0]) == 'key') {
131 $token = array_shift($tokens);
132 }
133 else {
134 continue;
135 }
136 }
137 $token = trim(array_shift($tokens), '(),');
138 $keys = explode(',', $token); // Handle multi-field keys.
139 $keys = deadwood_wrap_keys($keys);
140 $primary = $keys;
141 break;
142 case 'unique' :
143 if (count($tokens) == 3) {
144 if (strtolower($tokens[0]) == 'key') {
145 $token = array_shift($tokens);
146 }
147 else {
148 continue;
149 }
150 }
151 if (count($tokens) == 2) {
152 $index = strtolower(array_shift($tokens));
153 }
154 else {
155 $index = trim(strtolower($tokens[0]), '(),');
156 }
157 $token = trim(array_shift($tokens), '(),');
158 $keys = explode(',', $token); // Handle multi-field keys.
159 $keys = deadwood_wrap_keys($keys);
160 $uniques[$index] = $keys;
161 break;
162 case 'index' :
163 if (count($tokens) == 3) {
164 if (strtolower($tokens[0]) == 'key') {
165 $token = array_shift($tokens);
166 }
167 else {
168 continue;
169 }
170 }
171 case 'key' :
172 if (count($tokens) == 2) {
173 $index = strtolower(array_shift($tokens));
174 }
175 else {
176 $index = trim(strtolower($tokens[0]), '(),');
177 }
178 $token = trim(array_shift($tokens), '(),');
179 $keys = explode(',', $token); // Handle multi-field keys.
180 $keys = deadwood_wrap_keys($keys);
181 $indexes[$index] = $keys;
182 break;
183 }
184 }
185 }
186 else {
187 // Parse a field definition.
188 $name = array_shift($tokens);
189 list($type, $size, $precision, $scale, $length) = deadwood_get_db_type(array_shift($tokens));
190 $unsigned = FALSE;
191 $null = TRUE;
192 $default = '';
193 while (count($tokens)) {
194 $token = trim(strtolower(array_shift($tokens)), ',');
195 switch ($token) {
196 case 'unsigned' :
197 $unsigned = TRUE;
198 break;
199 case 'not' :
200 if (trim(strtolower($tokens[0]), ',') == 'null') {
201 $null = FALSE;
202 $token = array_shift($tokens);
203 }
204 break;
205 case 'default' :
206 if (count($tokens[0])) {
207 $default = trim($tokens[0], ',');
208 deadwood_get_default($type, $default, $null);
209 $token = array_shift($tokens);
210 }
211 break;
212 case 'auto_increment' :
213 $type = 'serial'; // Check that type is int?
214 break;
215 // Keys and indexes could be defined on a field. Do we have any?
216 // case 'primary' :
217 // break;
218 }
219 }
220 // Write this field to schema.
221 $schema .= " '$name' => array(\n";
222 $schema .= " 'description' => t('TODO'),\n";
223 $schema .= " 'type' => '$type',\n";
224 if ($size != '' && $size != 'normal') {
225 $schema .= " 'size' => '$size',\n";
226 }
227 if ($precision != 0) {
228 $schema .= " 'precision' => $precision,\n";
229 $schema .= " 'scale' => $scale,\n";
230 }
231 if ($length != 0) {
232 $schema .= " 'length' => $length,\n";
233 }
234 if ($unsigned) {
235 $schema .= " 'unsigned' => TRUE,\n";
236 }
237 $schema .= " 'not null' => " . ($null ? 'FALSE' : 'TRUE') . ",\n";
238 if ($default != '') {
239 $schema .= " 'default' => $default,\n";
240 }
241 $schema .= " ),\n"; // Close the array for this field.
242 }
243 }
244 $schema .= " ),\n"; // Close the fields array.
245
246 // Write the indexes and keys.
247 if (count($indexes)) {
248 $schema .= " 'indexes' => array(\n";
249 foreach ($indexes as $index => $keys) {
250 $schema .= " '$index' => array($keys),\n";
251 }
252 $schema .= " ),\n";
253 }
254 if (count($uniques)) {
255 $schema .= " 'unique keys' => array(\n";
256 foreach ($uniques as $index => $keys) {
257 $schema .= " '$index' => array($keys),\n";
258 }
259 $schema .= " ),\n";
260 }
261 if ($primary != '') {
262 $schema .= " 'primary key' => array($primary),\n";
263 }
264 $schema .= " );\n\n"; // Close the array for this table.
265 }
266 $schema .= " return \$schema;\n";
267
268 $msg =
269 "/**
270 * Implementation of hook_schema().
271 */
272 function " . $module_name . "_schema() {\n" .
273 $schema .
274 "}";
275
276 $from = array();
277 $to = array();
278
279 // See if the file has an @file comment.
280 $pattern = '/\/\*\*.*?\@file.*?\*\/\s/ms';
281 preg_match_all($pattern, $file, $matches, PREG_PATTERN_ORDER);
282 if (!isset($matches[0][0])) {
283 // Find the Id line in the file.
284 $from[] = '/^(\/\/ \$Id.*\$\s*$)/m';
285 $to[] = "$1\n\n$msg\n";
286 }
287 else {
288 // Find the @file comment.
289 $from[] = '/^(\/\*\*.*?\@file.*?\*\/\s)/ms';
290 $to[] = "$1\n$msg\n";
291 }
292
293 $cur = $file;
294 $new = $cur;
295 $hook = 'hook_schema';
296
297 deadwood_do_conversions($from, $to, $new);
298 deadwood_save_changes($cur, $new, $file, $hook);
299 }
300
301 function deadwood_get_index_tokens($field) {
302 $keys = substr($field, strpos($field, '(')); // Could strip the '()' now
303 $rest = substr($field, 0, strpos($field, '(') - 1);
304 $tokens = explode(' ', $rest);
305 $tokens = array_merge($tokens, array($keys));
306 return $tokens;
307 }
308
309 /**
310 * Clean up schema definitions that may not be exploded on spaces to yield the
311 * desired parts of the definition.
312 * Examples:
313 * Well formed = 'DECIMAL(10,2)' or 'VARCHAR(255)' or 'TEXT(64)'
314 * Poorly formed = 'DECIMAL( 10 , 2 )' or 'VARCHAR( 255 )' or 'TEXT( 64 )'
315 * = '`tid` INT( 10 ) NOT NULL ,'
316 *
317 * On all definitions
318 * Remove '`' characters around field name.
319 * Remove spaces after '(' and before ')'
320 * Replace multiple spaces with a single space.
321 * On field definitions
322 * Remove spaces before '(' and around size elements.
323 *
324 * @param string $field The field definition.
325 * @return the cleaned up field definition.
326 */
327 function deadwood_clean_schema_def($field) {
328 $other = array('primary', 'unique', 'index', 'key');
329 $tokens = explode(' ', $field);
330 $from = array();
331 $to = array();
332
333 $from[] = '/`/';
334 $to[] = '';
335 $from[] = '/\(\s*/';
336 $to[] = '(';
337 $from[] = '/\s*\)/';
338 $to[] = ')';
339 // Handle the field (table column) definitions.
340 if (!in_array(strtolower($tokens[0]), $other)) {
341 $from[] = '/\s*\(\s*/';
342 $to[] = '(';
343 $from[] = '/\s*,\s*/';
344 $to[] = ',';
345 }
346 // Replace multiple spaces with a single space
347 $from[] = '/\s{2,}/';
348 $to[] = ' ';
349 deadwood_do_conversions($from, $to, $field);
350 return $field;
351 }
352
353 /**
354 * Determine the schema API type of a database field.
355 *
356 * @param string $type The MySQL field type.
357 * @return array containing field type and parameters
358 * array($type, $size, $precision, $scale, $length).
359 */
360 function deadwood_get_db_type($type) {
361 static $db_types;
362
363 if (!isset($db_types)) {
364 $db_types = array_flip(db_type_map());
365 }
366
367 // Extract length, precision and scale parameters.
368 // Examples of $type = 'DECIMAL(10,2)' or 'VARCHAR(255)' or 'TEXT(64)'
369 // Trim the type value in case it is the only parameter for the field.
370 // Example: found a file with 'explanation TEXT,' as a field.
371 $parts = explode('(', trim($type, ','));
372 $type = strtoupper(array_shift($parts));
373
374 $precision = 0;
375 $scale = 0;
376 $length = 0;
377
378 if (count($parts) > 0) {
379 $parts = explode(',', $parts[0]);
380 $parts[count($parts) - 1] = trim($parts[count($parts) - 1], ')');
381
382 switch ($type) {
383 case 'DECIMAL' :
384 $precision = $parts[0];
385 $scale = count($parts > 1) ? $parts[1] : 0;
386 break;
387 case 'TEXT' :
388 $length = $parts[0];
389 break;
390 case 'VARCHAR' :
391 $length = $parts[0];
392 break;
393 }
394 }
395
396 if (array_key_exists($type, $db_types)) {
397 list($type, $size) = explode(':', $db_types[$type]);
398 return array($type, $size, $precision, $scale, $length);
399 }
400 return array('unknown', '', 0, 0, 0);
401 }
402
403 /**
404 * Clean the default value of any quotation marks if not a text field.
405 *
406 * @param unknown_type $type
407 * @param unknown_type $default
408 */
409 function deadwood_get_default($type, &$default, &$null) {
410 switch ($type) {
411 case 'text' :
412 case 'varchar' :
413 break;
414 default :
415 $default = trim($default, "'\"");
416 }
417 // Conform to schema module report where 'not null' => FALSE.
418 if ($default == 'NULL') {
419 $null = TRUE;
420 $default = '';
421 }
422 else {
423 $null = 0; // Using FALSE, $null = null?
424 }
425 }
426
427 /**
428 * Get the index key fields wrapped in quotes and separated by commas.
429 *
430 * @param array $keys Array of index names and key fields.
431 * @return string Index key fields wrapped in quotes and separated by commas.
432 */
433 function deadwood_wrap_keys($keys) {
434 foreach ($keys as $key => $value) {
435 $value = trim($value);
436 $keys[$key] = "'$value'";
437 }
438 return implode(', ', $keys);
439 }
440
441 /**
442 * Update the hook_install() function.
443 * Do nothing if hook_schema function is not found. This condition is true when
444 * there are no tables for this module or the schema conversion has not been
445 * called before this routine. Note: A call to drupal_[un]install_schema on a
446 * non-existent schema yields two errors from common.inc as its code does not
447 * test the $schema variable returned from drupal_get_schema_unprocessed.
448 *
449 * @param string $file The file to convert.
450 */
451 function deadwood_convert_hook_install(&$file) {
452 // Do nothing if no hook_schema function.
453 $hook = 'schema';
454 $cur = deadwood_find_hook($hook, $file);
455 if ($cur == '') {
456 return;
457 }
458
459 $hook = 'install';
460 $cur = deadwood_find_hook($hook, $file);
461 $new = $cur;
462 $module_name = deadwood_get_module_name($cur, $hook);
463 $hook = 'hook_install';
464
465 $msg =
466 " // Create tables.
467 drupal_install_schema('" . $module_name . "');";
468
469 $from = array();
470 $to = array();
471 // Replace the case statement.
472 $from[] = '/^\s*switch\s*\(\$GLOBALS\s*.*?break;\s*}\n/ms';
473 $to[] = "$msg\n";
474
475 deadwood_do_conversions($from, $to, $new);
476 deadwood_save_changes($cur, $new, $file, $hook);
477 }
478
479 /**
480 * Update the hook_uninstall() function.
481 * Do nothing if hook_schema function is not found. This condition is true when
482 * there are no tables for this module or the schema conversion has not been
483 * called before this routine. Note: A call to drupal_[un]install_schema on a
484 * non-existent schema yields two errors from common.inc as its code does not
485 * test the $schema variable returned from drupal_get_schema_unprocessed.
486 *
487 * @param string $file The file to convert.
488 */
489 function deadwood_convert_hook_uninstall(&$file) {
490 // Do nothing if no hook_schema function.
491 $hook = 'schema';
492 $cur = deadwood_find_hook($hook, $file);
493 if ($cur == '') {
494 return;
495 }
496
497 $hook = 'uninstall';
498 $cur = deadwood_find_hook($hook, $file);
499 $new = $cur;
500 $module_name = deadwood_get_module_name($cur, $hook);
501 $hook = 'hook_uninstall';
502
503 $msg =
504 " // Remove tables.
505 drupal_uninstall_schema('" . $module_name . "');";
506
507 $from = array();
508 $to = array();
509 // Delete drop table statements.
510 $from[] = '/(^\s*db_query\((\'|\")DROP TABLE.*\n)/m'; // May have double or single quote.
511 $to[] = "";
512 // Add new schema API statement.
513 $from[] = '/^(function.*_uninstall.*)$/m';
514 $to[] = "$1\n$msg\n";
515
516 deadwood_do_conversions($from, $to, $new);
517 deadwood_save_changes($cur, $new, $file, $hook);
518 }
519
520 /**
521 * Delete the hook_upadate_N() functions.
522 *
523 * @param string $file The file to convert.
524 */
525 function deadwood_convert_hook_update(&$file) {
526 $hook = 'update_\d+';
527 // Process file in chunks.
528 $chunks = deadwood_find_hook($hook, $file, TRUE);
529 $hook = 'update';
530 foreach ($chunks as $chunk) {
531 $cur = $chunk;
532 $new = '';
533 deadwood_save_changes($cur, $new, $file, 'hook_' . $hook . '_N');
534 }
535 }

  ViewVC Help
Powered by ViewVC 1.1.2