As others have pointed out: this is not how Laravel, or the Eloquent ORM to be exact, works. Normally you'd first create a table (i.e. make a migration) and then create your model. A lot of time can be saved by adhering to Laravels model conventions.
However, you already have one or more models that seem to be missing a migration. I'd advice you to simply add migrations for these models. Unfortunately this will be a lot of work if you have a lot of models and, especially (as is the case with your example model) when you didn't adhere to the table name, and other, conventions.
On the other hand, you already have a lot of the information that's going to go into your migration, available in your Model. You could extract this information from the DocComments and properties like $table
, $primaryKey
, $fillable
, etc. This could be done automatically. I've put together an example that's far from complete, but should at least get you started with the base of your migration. You can then decide to do the remaining parts manually or add functionality to the automatic process. I'd personally only do the latter if I had a lot of models.
Example
I've based this example of the model included in your question.
As I said; it's far from complete, the following additions/improvements come to mind:
- Determine relations and base foreign keys on that. (Take a look at this post to get some inspiration.)
- Add more data types to the
switch
.
- ...
Save the following trait as app/SchemaBuilder.php
:
<?php
namespace App;
trait SchemaBuilder
{
public function printMigration()
{
echo '<pre>';
echo htmlspecialchars($this->generateMigration());
echo '</pre>';
}
public function makeMigrationFile()
{
if ($this->migrationFileExists()) {
die('It appears that a migration for this model already exists. Please check it out.');
}
$filename = date('Y_m_t_His') . '_create_' . $this->table . '_table.php';
if (file_put_contents(database_path('migrations/') . $filename, $this->generateMigration())) {
return true;
}
return false;
}
protected function generateMigration()
{
return sprintf($this->getSchemaTemplate(),
ucfirst($this->table), $this->table,
implode("\n\t\t\t", $this->generateFieldCreationFunctions()),
$this->table
);
}
protected function getSchemaTemplate()
{
$schema = "<?php\n";
$schema .= "\n";
$schema .= "use Illuminate\\Support\\Facades\\Schema;\n";
$schema .= "use Illuminate\\Database\\Schema\\Blueprint;\n";
$schema .= "use Illuminate\\Database\\Migrations\\Migration;\n";
$schema .= "\n";
$schema .= "class Create%sTable extends Migration\n";
$schema .= "{\n";
$schema .= "\t/**\n";
$schema .= "\t* Run the migrations.\n";
$schema .= "\t*\n";
$schema .= "\t* @return void\n";
$schema .= "\t*/\n";
$schema .= "\tpublic function up()\n";
$schema .= "\t{\n";
$schema .= "\t\tSchema::create('%s', function (Blueprint \$table) {\n";
$schema .= "\t\t\t%s\n"; # Actual database fields will be added here.
$schema .= "\t\t});\n";
$schema .= "\t}\n";
$schema .= "\n";
$schema .= "\t/**\n";
$schema .= "\t* Reverse the migrations.\n";
$schema .= "\t*\n";
$schema .= "\t* @return void\n";
$schema .= "\t*/\n";
$schema .= "\tpublic function down()\n";
$schema .= "\t{\n";
$schema .= "\t\tSchema::drop('%s');\n";
$schema .= "\t}\n";
$schema .= "}";
return $schema;
}
protected function generateFieldCreationFunctions()
{
$functions = [];
if (isset($this->primaryKey)) {
$functions[] = "\$table->increments('$this->primaryKey');";
}
$featuresFromDoc = $this->extractFieldDataFromCommentDoc();
$functions[] = ""; # Hack our way to an empty line.
foreach ($this->fillable as $fillableField) {
if (in_array($fillableField, $this->dates)) { # We'll handle fields in $dates later.
continue;
}
if (!isset($featuresFromDoc[$fillableField])) {
$functions[] = "//Manually do something with $fillableField";
}
switch ($featuresFromDoc[$fillableField]) {
case 'string':
$functions[] = "\$table->string('$fillableField'); //TODO: check whether varchar is the correct field type.";
break;
case 'int':
$functions[] = "\$table->integer('$fillableField'); //TODO: check whether integer is the correct field type.";
break;
case 'float':
$functions[] = "\$table->float('$fillableField', 12, 10);";
break;
default:
$functions[] = "//Manually do something with $fillableField";
}
}
$functions[] = ""; # Empty line.
foreach ($this->dates as $dateField) {
$functions[] = "\$table->dateTime('$dateField');";
}
$functions[] = ""; # Empty line.
if (!empty($this->timestamps)) {
$functions[] = "\$table->timestamps();";
}
return $functions;
}
protected function extractFieldDataFromCommentDoc()
{
$doc_comment = (new \ReflectionClass(get_parent_class($this)))->getDocComment();
preg_match_all('/@property (.+) \$(.+)/', $doc_comment, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$features[$match[2]] = $match[1];
}
return $features;
}
protected function migrationFileExists()
{
$path = database_path('migrations');
if ($handle = opendir($path)) {
while (false !== ($file = readdir($handle))) {
if (strpos($file, 'create_' . $this->table . '_table') !== false) {
return true;
}
}
closedir($handle);
}
return false;
}
}
Create the following controller and register a route so that you can access it:
<?php
namespace App\Http\Controllers;
use App\PdTcountry;
use Illuminate\Http\Request;
class TestController extends Controller
{
public function index()
{
# Specify for which model you'd like to build a migration.
$buildSchemaFor = 'App\PdTcountry';
eval(sprintf('class MigrationBuilder extends %s{use \App\SchemaBuilder;}', $buildSchemaFor));
if ((new \MigrationBuilder)->makeMigrationFile()) {
echo 'Migration file successfully created.';
}
else {
echo 'Encountered error while making migration file.';
}
# Or alternatively, print the migration file to the browser:
// (new \MigrationBuilder)->printMigration();
}
}