Open Preprint Systems  3.3.0
xmlSchemaToMigration.php
1 <?php
2 
14 require(dirname(dirname(dirname(dirname(__FILE__)))) . '/tools/bootstrap.inc.php');
15 
18  protected $source;
19 
21  protected $className;
22 
26  function __construct($argv = array()) {
27  parent::__construct($argv);
28 
29  array_shift($argv); // Shift the tool name off the top
30 
31  $this->source = array_shift($argv);
32  $this->className = array_shift($argv);
33 
34  // The source file/directory must be specified and exist.
35  if (empty($this->source) || !file_exists($this->source)) {
36  $this->usage();
37  exit(2);
38  }
39 
40  if (empty($this->className) | !preg_match('/^[a-zA-Z]+$/', $this->className)) {
41  $this->usage();
42  exit(3);
43  }
44  }
45 
49  function usage() {
50  echo "Script to convert ADODB XMLSchema-based schema descriptors to Illuminate migrations\n\n"
51  . "Usage: {$this->scriptName} input-schema-file.xml GenerateClassNamed\n\n";
52  }
53 
57  function execute() {
58  $doc = new DOMDocument();
59  $doc->preserveWhiteSpace = false;
60  $doc->loadXML(file_get_contents($this->source));
61  if ($doc->documentElement->nodeName != 'schema') throw new Exception('Invalid document element ' . $this->documentElement->nodeName);
62 
63  echo "<?php
64 
76 use Illuminate\Database\Migrations\Migration;
77 use Illuminate\Database\Schema\Builder;
78 use Illuminate\Database\Schema\Blueprint;
79 use Illuminate\Database\Capsule\Manager as Capsule;
80 
81 class $this->className extends Migration {
86  public function up() {\n";
87  foreach ($doc->documentElement->childNodes as $tableNode) {
88  if ($tableNode->nodeType == XML_COMMENT_NODE) continue; // Skip comments
89  if ($tableNode->nodeName != 'table') throw new Exception('Unexpected table node name ' . $tableNode->nodeName);
90  foreach ($tableNode->childNodes as $tableChild) {
91  if ($tableChild->nodeName == 'descr') echo "\t\t// " . $tableChild->nodeValue . "\n";
92  }
93  echo "\t\tCapsule::schema()->create('" . $tableNode->getAttribute('name') . "', function (Blueprint \$table) {\n";
94  $keys = [];
95  $hasAutoIncrementNamed = null;
96  foreach ($tableNode->childNodes as $tableChild) switch (true) {
97  case $tableChild->nodeType == XML_COMMENT_NODE: throw new Exception('Unexpected comment in table ' . $tableNode->getAttribute('name') . '!');
98  case $tableChild->nodeName == 'field':
99  // Preprocess comments
100  foreach ($tableChild->childNodes as $fieldChild) switch (true) {
101  case $fieldChild->nodeType == XML_COMMENT_NODE:
102  echo "\t\t\t// " . $fieldChild->nodeValue . "\n";
103  break;
104  }
105  echo "\t\t\t";
106  $allowDefault = true;
107  switch ($tableChild->getAttribute('type')) {
108  case 'XL':
109  echo "\$table->longText('" . $tableChild->getAttribute('name') . "')";
110  $allowDefault = false;
111  break;
112  case 'X':
113  echo "\$table->text('" . $tableChild->getAttribute('name') . "')";
114  $allowDefault = false;
115  break;
116  case 'I1':
117  echo "\$table->tinyInteger('" . $tableChild->getAttribute('name') . "')";
118  break;
119  case 'I2':
120  echo "\$table->smallInteger('" . $tableChild->getAttribute('name') . "')";
121  break;
122  case 'I4':
123  echo "\$table->integer('" . $tableChild->getAttribute('name') . "')";
124  break;
125  case 'I8':
126  echo "\$table->bigInteger('" . $tableChild->getAttribute('name') . "')";
127  break;
128  case 'F':
129  echo "\$table->float('" . $tableChild->getAttribute('name') . "', 8, 2)";
130  break;
131  case 'T':
132  echo "\$table->datetime('" . $tableChild->getAttribute('name') . "')";
133  break;
134  case 'D':
135  echo "\$table->date('" . $tableChild->getAttribute('name') . "')";
136  break;
137  case 'C':
138  echo "\$table->string('" . $tableChild->getAttribute('name') . "', " . (int) $tableChild->getAttribute('size') . ")";
139  break;
140  case 'C2':
141  echo "\$table->string('" . $tableChild->getAttribute('name') . "', " . (int) $tableChild->getAttribute('size') . ")";
142  break;
143  default: throw new Exception('Unspecified or unknown table type ' . $tableChild->getAttribute('type') . ' in column ' . $tableChild->getAttribute('name') . ' of table ' . $tableNode->getAttribute('name'));
144  }
145  $nullable = true;
146  $autoIncrement = false;
147  foreach ($tableChild->childNodes as $fieldChild) switch (true) {
148  case $fieldChild->nodeType == XML_COMMENT_NODE: break; // Already processed above
149  case $fieldChild->nodeName == 'NOTNULL': $nullable = false; break;
150  case $fieldChild->nodeName == 'AUTOINCREMENT':
151  $autoIncrement = true;
152  $hasAutoIncrementNamed = $tableChild->getAttribute('name');
153  $nullable = false;
154  break;
155  case $fieldChild->nodeName == 'KEY': $keys[] = $tableChild->getAttribute('name'); break;
156  case $fieldChild->nodeName == 'DEFAULT':
157  if ($allowDefault) {
158  $value = $fieldChild->getAttribute('VALUE');
159  if (is_string($value) && ctype_digit($value)) $value = (int) $value;
160  echo "->default(" . var_export($value, true) . ")";
161  }
162  break;
163  case $fieldChild->nodeName == 'descr': echo "->comment(" . var_export($fieldChild->nodeValue, true) . ")"; break;
164  case $fieldChild->nodeType == XML_TEXT_NODE:
165  if (trim($fieldChild->nodeValue) !== '') throw new Exception('Unexpected content in field node!');
166  break;
167  default: throw new Exception('Unhandled child node (type ' . $fieldChild->nodeType . ') to column ' . $tableChild->getAttribute('name') . ' of table ' . $tableNode->getAttribute('name'));
168  }
169  if ($autoIncrement) echo "->autoIncrement()";
170  if ($nullable && !in_array($tableChild->getAttribute('name'), $keys)) echo "->nullable()";
171  echo ";\n";
172  break;
173  case $tableChild->nodeName == 'index':
174  if (!$tableChild->hasAttribute('name')) throw new Exception('Unnamed index on table ' . $tableNode->getAttribute('name'));
175  $indexType = 'index';
176  $columns = [];
177  foreach ($tableChild->childNodes as $indexChild) switch (true) {
178  case $indexChild->nodeType == XML_COMMENT_NODE:
179  echo "\t\t\t// " . $indexChild->nodeValue . "\n";
180  break;
181  case $indexChild->nodeName == 'UNIQUE': $indexType = 'unique'; break;
182  case $indexChild->nodeName == 'col': $columns[] = trim($indexChild->nodeValue);
183  break;
184  default: throw new Exception('Unhandled index node child ' . $indexChild->nodeName);
185  }
186  if (empty($columns)) throw new Exception('Empty column list for index on table ' . $tableNode->getAttribute('name') . '))!');
187  echo "\t\t\t\$table->$indexType(['" . implode("', '", $columns) . "'], '" . $tableChild->getAttribute('name') . "');\n";
188  break;
189  case $tableChild->nodeName == 'descr': break; // Handled above.
190  break;
191  default: throw new Exception('Don\'t know how to handle this table child node (' . $tableChild->nodeName . '))!');
192  }
193  echo "\t\t});\n\n";
194  if (count($keys)>1 && $hasAutoIncrementNamed !== null) {
195  echo "\t\t// Work-around for compound primary key\n";
196  echo "\t\tswitch (Capsule::connection()->getDriverName()) {\n";
197  echo "\t\t\tcase 'mysql': Capsule::connection()->unprepared(\"ALTER TABLE " . $tableNode->getAttribute('name') . " DROP PRIMARY KEY, ADD PRIMARY KEY (" . implode(", ", $keys) . ")\"); break;\n";
198  echo "\t\t\tcase 'pgsql': Capsule::connection()->unprepared(\"ALTER TABLE " . $tableNode->getAttribute('name') . " DROP CONSTRAINT " . $tableNode->getAttribute('name') . "_pkey; ALTER TABLE " . $tableNode->getAttribute('name') . " ADD PRIMARY KEY (" . implode(", ", $keys) . ");\"); break;\n";
199  echo "\t\t}\n";
200  } elseif (count($keys)==1 && $hasAutoIncrementNamed !== null) {
201  // Handled well by autoIncrement
202  } elseif ($hasAutoIncrementNamed === null) {
203  // No autoincrement specified; we're OK without further consideration
204  } elseif (count($keys)==0) {
205  // No primary keys specified; we're OK without further consideration
206  } else {
207  throw new Exception('Not sure how to handle primary key setup for table ' . $tableNode->getAttribute('name') . '.');
208  }
209  }
210  echo "\t}\n}";
211  }
212 }
213 
214 $tool = new xmlSchemaToMigration(isset($argv) ? $argv : array());
215 $tool->execute();
216 
CommandLineTool
Initialization code for command-line scripts.
Definition: CliTool.inc.php:44
xmlSchemaToMigration\usage
usage()
Definition: xmlSchemaToMigration.php:55
$tool
$tool
Definition: mergeCoverageReportTool.php:120
xmlSchemaToMigration\execute
execute()
Definition: xmlSchemaToMigration.php:63
xmlSchemaToMigration\$className
$className
Definition: xmlSchemaToMigration.php:27
xmlSchemaToMigration\__construct
__construct($argv=array())
Definition: xmlSchemaToMigration.php:32
xmlSchemaToMigration\$source
$source
Definition: xmlSchemaToMigration.php:21
xmlSchemaToMigration
Definition: xmlSchemaToMigration.php:16
CommandLineTool\$argv
$argv
Definition: CliTool.inc.php:53