/** * Generate specified table migration * * @param string $version * @param string $table * @param string $exportData * @return string */ public static function generate($version, $table, $exportData = null) { $oldColumn = null; $allFields = array(); $numericFields = array(); $tableDefinition = array(); $defaultSchema = self::$_connection->getDefaultSchema(); $description = self::$_connection->describeTable($table, $defaultSchema); foreach ($description as $field) { $fieldDefinition = array(); if (preg_match('/([a-z]+)(\\(([0-9]+)(,([0-9]+))*\\)){0,1}/', $field['Type'], $matches)) { switch ($matches[1]) { case 'int': case 'smallint': case 'double': $fieldDefinition[] = "'type' => DbColumn::TYPE_INTEGER"; $numericFields[$field['Field']] = true; break; case 'varchar': $fieldDefinition[] = "'type' => DbColumn::TYPE_VARCHAR"; break; case 'char': $fieldDefinition[] = "'type' => DbColumn::TYPE_CHAR"; break; case 'date': $fieldDefinition[] = "'type' => DbColumn::TYPE_DATE"; break; case 'datetime': $fieldDefinition[] = "'type' => DbColumn::TYPE_DATETIME"; break; case 'decimal': $fieldDefinition[] = "'type' => DbColumn::TYPE_DECIMAL"; $numericFields[$field['Field']] = true; break; case 'mediumblob': case 'text': $fieldDefinition[] = "'type' => DbColumn::TYPE_TEXT"; break; case 'enum': $fieldDefinition[] = "'type' => DbColumn::TYPE_CHAR"; $fieldDefinition[] = "'size' => 1"; break; default: throw new ActiveRecordMigrationException('Tipo de dato no reconocido ' . $matches[1] . ' en la columna ' . $field['Field']); } if (isset($matches[3])) { $fieldDefinition[] = "'size' => " . $matches[3]; } if (isset($matches[5])) { $fieldDefinition[] = "'scale' => " . $matches[5]; } if (strpos($field['Type'], 'unsigned')) { $fieldDefinition[] = "'unsigned' => true"; } } else { throw new ActiveRecordMigrationException('Tipo de dato no reconocido ' . $field['Type']); } if ($field['Key'] == 'PRI') { $fieldDefinition[] = "'primary' => true"; } if ($field['Null'] == 'NO') { $fieldDefinition[] = "'notNull' => true"; } if ($field['Extra'] == 'auto_increment') { $fieldDefinition[] = "'autoIncrement' => true"; } if ($oldColumn != null) { $fieldDefinition[] = "'after' => '" . $oldColumn . "'"; } else { $fieldDefinition[] = "'first' => true"; } $oldColumn = $field['Field']; $tableDefinition[] = "\t\t\t\tnew DbColumn('" . $field['Field'] . "', array(\n\t\t\t\t\t" . join(",\n\t\t\t\t\t", $fieldDefinition) . "\n\t\t\t\t))"; $allFields[] = "'" . $field['Field'] . "'"; } $indexesDefinition = array(); $indexes = self::$_connection->describeIndexes($table, $defaultSchema); foreach ($indexes as $indexName => $indexColumns) { $indexDefinition = array(); foreach ($indexColumns as $indexColumn) { $indexDefinition[] = "'" . $indexColumn . "'"; } $indexesDefinition[] = "\t\t\t\tnew DbIndex('" . $indexName . "', array(\n\t\t\t\t\t" . join(",\n\t\t\t\t\t", $indexDefinition) . "\n\t\t\t\t))"; } $referencesDefinition = array(); $references = self::$_connection->describeReferences($table, $defaultSchema); foreach ($references as $constraintName => $reference) { $columns = array(); foreach ($reference['columns'] as $column) { $columns[] = "'" . $column . "'"; } $referencedColumns = array(); foreach ($reference['referencedColumns'] as $referencedColumn) { $referencedColumns[] = "'" . $referencedColumn . "'"; } $referenceDefinition = array(); $referenceDefinition[] = "'referencedSchema' => '" . $reference['referencedSchema'] . "'"; $referenceDefinition[] = "'referencedTable' => '" . $reference['referencedTable'] . "'"; $referenceDefinition[] = "'columns' => array(" . join(",", $columns) . ")"; $referenceDefinition[] = "'referencedColumns' => array(" . join(",", $referencedColumns) . ")"; $referencesDefinition[] = "\t\t\t\tnew DbReference('" . $constraintName . "', array(\n\t\t\t\t\t" . join(",\n\t\t\t\t\t", $referenceDefinition) . "\n\t\t\t\t))"; } $optionsDefinition = array(); $tableOptions = self::$_connection->tableOptions($table, $defaultSchema); foreach ($tableOptions as $optionName => $optionValue) { $optionsDefinition[] = "\t\t\t\t'{$optionName}' => '" . $optionValue . "'"; } $classVersion = preg_replace('/[^0-9A-Za-z]/', '', $version); $className = Utils::camelize($table) . 'Migration_' . $classVersion; $classData = "class " . $className . " extends ActiveRecordMigration {\n\n" . "\tpublic function up(){\n\t\t\$this->morphTable('" . $table . "', array(" . "\n\t\t\t'columns' => array(\n" . join(",\n", $tableDefinition) . "\n\t\t\t)," . "\n\t\t\t'indexes' => array(\n" . join(",\n", $indexesDefinition) . "\n\t\t\t)," . "\n\t\t\t'references' => array(\n" . join(",\n", $referencesDefinition) . "\n\t\t\t)," . "\n\t\t\t'options' => array(\n" . join(",\n", $optionsDefinition) . "\n\t\t\t)\n" . "\t\t));\n\t}"; if ($exportData == 'always' || $exportData == 'oncreate') { if ($exportData == 'oncreate') { $classData .= "\n\n\tpublic function afterCreateTable(){\n"; } else { $classData .= "\n\n\tpublic function afterUp(){\n"; } $classData .= "\t\t\$this->batchInsert('{$table}', array(\n\t\t\t" . join(",\n\t\t\t", $allFields) . "\n\t\t));"; $fileHandler = fopen(self::$_migrationPath . '/' . $table . '.dat', 'w'); $cursor = self::$_connection->query('SELECT * FROM ' . $table); self::$_connection->setFetchMode(DbBase::DB_ASSOC); while ($row = self::$_connection->fetchArray($cursor)) { $data = array(); foreach ($row as $key => $value) { if (isset($numericFields[$key])) { if ($value === '' || is_null($value)) { $data[] = 'NULL'; } else { $data[] = addslashes($value); } } else { $data[] = "'" . addslashes($value) . "'"; } unset($value); } fputs($fileHandler, join('|', $data) . PHP_EOL); unset($row); unset($data); } fclose($fileHandler); $classData .= "\n\t}"; } $classData .= "\n\n}"; return $classData; }