⚙️
Laravel スキーマから Model を一括作成
既製のライブラリがありますが、微妙に痒いところに届かないので、コマンドを自作しています。
前提条件
以下のような命名規則である。
テーブル名 m_users
主キー user_id
モデル User
条件が合わない場合は、適宜カスタマイズして使ってください。
特徴
- 全テーブル分一気に作成(既に存在すればスキップ)
- テーブルコメントをクラスコメントに反映
- @property アノテーションを自動生成
- casts を自動生成
- dates を自動生成
使い方
php artisan dev:make-models
ソース
app/Console/Commands/DevMakeModels.php
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
/**
* スキーマからモデルを作成
*/
class DevMakeModels extends Command
{
protected $signature = 'dev:make-models';
protected $description = 'Make Models FromSchema';
public function handle()
{
//スタブを取得
$template = file_get_contents(app_path("Console/Commands/resources/Model.stub"));
//テーブル一覧取得
$tables = DB::select("show tables");
foreach ($tables as $table) {
$table = (array) $table;
$table_name = array_values($table)[0];
//カラム取得
$columns = DB::select("show columns from {$table_name}");
//先頭をプライマリキーとみなす
$primary_key = $columns[0]->Field;
//プライマリーキー名から _id をとったものをモデル名にする
$model_name = $this->getModelNameFromPrimaryKey($primary_key);
//生成するファイル名
$path = app_path("Models/{$model_name}.php");
//ファイルが存在すればスキップ
if (file_exists($path)) {
$this->info("{$model_name} already exists");
continue;
}
//コメント取得
$status = DB::select("show table status like '{$table_name}'");
$table_comment = $status[0]->Comment;
//置換
$body = $template;
$body = str_replace("{TableComment}", $table_comment, $body);
$body = str_replace("{Properties}", $this->makePropertiesString($columns), $body);
$body = str_replace("{ModelName}", $model_name, $body);
$body = str_replace("{TableName}", $table_name, $body);
$body = str_replace("{PrimaryKey}", $primary_key, $body);
$body = str_replace("{Dates}", $this->makeDatesString($columns), $body);
$body = str_replace("{Casts}", $this->makeCastsString($columns), $body);
//ファイル出力
file_put_contents($path, $body);
$this->info("{$model_name} created !!");
}
$this->comment('END');
}
private function getModelNameFromPrimaryKey($primary_key)
{
//末尾の _id を取る
$snake = substr($primary_key, 0, -3);
$words = explode('_', $snake);
$camel = join('', array_map(function ($word) {
return ucfirst($word);
}, $words));
return $camel;
}
private function makePropertiesString($columns)
{
$properties = [];
foreach ($columns as $column) {
if (strpos($column->Type, "int") === 0) {
$properties[$column->Field] = 'integer';
} elseif (strpos($column->Type, "tinyint") === 0) {
$properties[$column->Field] = 'integer';
} elseif (strpos($column->Type, "decimal") === 0) {
$properties[$column->Field] = 'float';
} elseif (strpos($column->Type, "varchar") === 0) {
$properties[$column->Field] = 'string';
} elseif (strpos($column->Type, "text") === 0) {
$properties[$column->Field] = 'string';
} elseif (strpos($column->Type, "datetime") === 0) {
$properties[$column->Field] = '\Illuminate\Support\Carbon';
} elseif (strpos($column->Type, "timestamp") === 0) {
$properties[$column->Field] = '\Illuminate\Support\Carbon';
} elseif (strpos($column->Type, "date") === 0) {
$properties[$column->Field] = '\Illuminate\Support\Carbon';
} else {
$properties[$column->Field] = 'string';
}
}
return join("\n * ", array_map(function ($key, $value) {
return "@property {$value} \${$key}";
}, array_keys($properties), array_values($properties)));
}
private function makeDatesString($columns)
{
$date_columns = array_filter($columns, function ($column) {
return ($column->Type === 'date' || $column->Type === 'datetime');
});
return join("\n ", array_map(function ($date_column) {
return "'{$date_column->Field}',";
}, $date_columns));
}
private function makeCastsString($columns)
{
$casts = [];
foreach ($columns as $column) {
if (strpos($column->Type, "int") === 0) {
$casts[$column->Field] = 'integer';
} elseif (strpos($column->Type, "tinyint") === 0) {
$casts[$column->Field] = 'integer';
} elseif (strpos($column->Type, "decimal") === 0) {
$length_str = substr($column->Type, 8, -1);
$length = explode(',', $length_str);
$casts[$column->Field] = 'decimal:' . $length[1];
} elseif (strpos($column->Type, "datetime") === 0) {
$casts[$column->Field] = 'date:Y-m-d H:i:s';
} elseif (strpos($column->Type, "timestamp") === 0) {
$casts[$column->Field] = 'date:Y-m-d H:i:s';
} elseif (strpos($column->Type, "date") === 0) {
$casts[$column->Field] = 'date:Y-m-d';
}
}
return join("\n ", array_map(function ($key, $value) {
return "'{$key}' => '{$value}',";
}, array_keys($casts), array_values($casts)));
}
}
app/Console/Commands/resources/Model.stub
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* {TableComment}
*
* {Properties}
*/
class {ModelName} extends Model
{
use SoftDeletes;
protected $table = "{TableName}";
protected $primaryKey = '{PrimaryKey}';
protected $hidden = [];
protected $appends = [];
protected $dates = [
{Dates}
];
protected $casts = [
{Casts}
];
}
Discussion