I have the following migration that aims to make two new columns (parent_id; parent_type) and fill them with data from four current columns (page_id; post_id; global_id; event_id) from the same table. The latter four columns cannot be at the same time non-null, if one has a value, the others are null, therefore there needs to be some kind of if functionality.
Is this the right way to do it? I have run this migration, I have replaced the places in the codebase where there was a refference to any of the four previous columns and replaced them with their appropiate parent_id/parent_type but Laravel is still looking for block.page_id.
public function up()
{
Schema::table('blocks', function (Blueprint $table) {
$table->integer('parent_id')->nullable()->after('type');
$table->string('parent_type')->nullable()->after('parent_id');
});
$blocks = Block::select('id', 'page_id', 'post_id', 'event_id', 'global_id')->get();
foreach ($blocks as $block) {
if ($block['post_id'] !== null) {
$block->parent_id = $block['post_id'];
$block->parent_type = 'post';
} elseif ($block['page_id'] !== null) {
$block->parent_id = $block['page_id'];
$block->parent_type = 'page';
} elseif ($block['event_id'] !== null) {
$block->parent_id = $block['event_id'];
$block->parent_type = 'post';
} elseif ($block['global_id'] !== null) {
$block->parent_id = $block['global_id'];
$block->parent_type = 'global';
} else {
$block->parent_id = null;
}
$block->save();
}
}
After this migration, I have another one that drops the four columns:
public function up()
{
Schema::table('blocks', function (Blueprint $table) {
$table->dropColumn('page_id');
$table->dropColumn('post_id');
$table->dropColumn('event_id');
$table->dropColumn('global_id');
});
}
The relationships in the models:
Block.php
public function blocks()
{
return $this->hasMany('App\Block')->orderby('section');
}
Page.php
public function page()
{
return $this->belongsTo('App\Page', 'parent_id');
}
CodePudding user response:
I don't think this is a proper solution, You may avoid using the eloquent logic inside a migration file
You may use the seed (If you are attending to run this multiple times regarding tests/dummy data...etc.), besides the code seems a bit confusing.
What I'll do, instead, is the following:
- create new
seed
file:
php artisan make:seed MigrationSeed
Inside the MigrationSeed
do the following:
public function run()
{
$columns = collect(['page_id', 'post_id', 'event_id', 'global_id']);
$columns->each(function ($column) {
$this->updateColumn($column);
});
}
private function updateColumn(string $column)
{
$blocks = Block::whereNotNull($column)->get();
$blocks->each(function (Block $block) use ($column) {
$block->update([
'parent_id' => $block->{$column},
'parent_type' => $column,
]);
});
}
Here, you'll create a list of columns you want to change, then make a separate method to get the NOT NULL
column, and returns the data, then it will update the parent_id
& parent_type
.
It seems a bit complicated, but cleaner/extendable way to use in the present and the future.
Finally, run:
php artisan db:seed