Migrations are like version control for your database, allowing your team to modify and share the application's database schema. Migrations are typically paired with Laravel's schema builder to build your application's database schema.
Advantages and Disadvantages of Laravel MigrationWeb applications can be built on it quickly. It is easy to learn. The documentation is easily available. Fulfils almost every criterion demanded by modern web application build up.
To create a new migration, you can run the make:migration Artisan command and that will bootstrap a new class on your Laravel application, in the database/migrations folder. This class will contain a default boilerplate code.
Creating Migrations The migration will be placed in your app/database/migrations folder, and will contain a timestamp which allows the framework to determine the order of the migrations.
Laravel development is about freedom. So, if you need to seed your production database and think DatabaseSeeder is the best place to do so, why not?
Okay, seeder is mainly to be used with test data, but you'll see some folks using it as you are.
I see this important kind of seed as part of my migration, since this is something that cannot be out of my database tables and artisan migrate
is ran everytime I deploy a new version of my application, so I just do
php artisan migrate:make seed_models_table
And create my seedind stuff in it:
public function up()
{
$models = array(
array('name' => '...'),
);
DB::table('models')->insert($models);
}
I've often found myself wondering what the right answer to this is. Personally, I'd steer clear of using seeding to populate required rows in the database as you'll have to put a load of conditional logic in to ensure that you don't attempt to populate something that's already there. (Deleting and recreating the data is very inadvisable as you could end up with key mismatches and if you're using cascading deletes you may accidentally wipe a load of your database my mistake! ;-)
I put the 'seeding' of rows into the migration script as the chances are, the data will need to be there as part of the rollout process.
It's worth noting that you should use the DB class instead of Eloquent models to populate this data as your class structure could change over time which will then prevent you from re-creating the database from scratch (without rewriting history and changing you migration files, which I'm sure is a bad thing.)
I'd tend to go with something like this:
public function up()
{
DB::beginTransaction();
Schema::create(
'town',
function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
}
);
DB::table('town')
->insert(
array(
array('London'),
array('Paris'),
array('New York')
)
);
Schema::create(
'location',
function (Blueprint $table) {
$table->increments('id');
$table->integer('town_id')->unsigned()->index();
$table->float('lat');
$table->float('long');
$table->timestamps();
$table->foreign('town_id')->references('id')->on('town')->onDelete('cascade');
}
);
DB::commit();
}
This then allows me to 'seed' the town table easily when I first create it, and wont interfere with any additions made to it at run time.
This is what I use in production.
Since I run migration on each deployment
artisan migrate
I create a seeder (just to keep seeding data out of migration for easy access later) and then run that seeder along with the migration
class YourTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
//migrate your table // Example
Schema::create('test_table', function(Blueprint $table)
{
$table->increments('id');
$table->timestamps();
$table->softDeletes();
});
//seed this table
$seeder = new YourTableSeeder();
$seeder->run();
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('test_table');
}
}
I do not add this seed call to seeds/DatabaseSeeder.php to avoid running it twice on a new installation.
The Artisan Command Solution
Create a new artisan command
php artisan make:command UpsertConfigurationTables
Paste this into the newly generated file: UpsertConfigurationTables.php
<?php
namespace App\Console\Commands;
use Exception;
use Illuminate\Console\Command;
class UpsertConfigurationTables extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'upsert:configuration';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Upserts the configuration tables.';
/**
* The models we want to upsert configuration data for
*
* @var array
*/
private $_models = [
'App\ExampleModel'
];
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
foreach ($this->_models as $model) {
// check that class exists
if (!class_exists($model)) {
throw new Exception('Configuration seed failed. Model does not exist.');
}
// check that seed data exists
if (!defined($model . '::CONFIGURATION_DATA')) {
throw new Exception('Configuration seed failed. Data does not exist.');
}
/**
* seed each record
*/
foreach ($model::CONFIGURATION_DATA as $row) {
$record = $this->_getRecord($model, $row['id']);
foreach ($row as $key => $value) {
$this->_upsertRecord($record, $row);
}
}
}
}
/**
* _fetchRecord - fetches a record if it exists, otherwise instantiates a new model
*
* @param string $model - the model
* @param integer $id - the model ID
*
* @return object - model instantiation
*/
private function _getRecord ($model, $id)
{
if ($this->_isSoftDeletable($model)) {
$record = $model::withTrashed()->find($id);
} else {
$record = $model::find($id);
}
return $record ? $record : new $model;
}
/**
* _upsertRecord - upsert a database record
*
* @param object $record - the record
* @param array $row - the row of update data
*
* @return object
*/
private function _upsertRecord ($record, $row)
{
foreach ($row as $key => $value) {
if ($key === 'deleted_at' && $this->_isSoftDeletable($record)) {
if ($record->trashed() && !$value) {
$record->restore();
} else if (!$record->trashed() && $value) {
$record->delete();
}
} else {
$record->$key = $value;
}
}
return $record->save();
}
/**
* _isSoftDeletable - Determines if a model is soft-deletable
*
* @param string $model - the model in question
*
* @return boolean
*/
private function _isSoftDeletable ($model)
{
$uses = array_merge(class_uses($model), class_uses(get_parent_class($model)));
return in_array('Illuminate\Database\Eloquent\SoftDeletes', $uses);
}
}
Populate $_models
with the Eloquent models you want to seed.
Define the seed rows in the model: const CONFIGURATION_DATA
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class ExampleModel extends Model
{
use SoftDeletes;
const CONFIG_VALUE_ONE = 1;
const CONFIG_VALUE_TWO = 2;
const CONFIGURATION_DATA = [
[
'id' => self::CONFIG_VALUE_ONE,
'col1' => 'val1',
'col2' => 'val2',
'deleted_at' => false
],
[
'id' => self::CONFIG_VALUE_TWO,
'col1' => 'val1',
'col2' => 'val2',
'deleted_at' => true
],
];
}
Add the command to your Laravel Forge deployment script (or any other CI deployment script): php artisan upsert:configuration
Other noteworthy things:
deleted_at
to true
or false
. The Artisan command will handle calling the correct method to delete or recover your record.Problems With Other Mentioned Solutions:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With