Php 拉拉维尔:移民与移民;生产数据的播种
我的应用程序需要预先注册的数据集才能工作。因此,我需要在设置应用程序时将它们插入数据库中 提出两种机制:Php 拉拉维尔:移民与移民;生产数据的播种,php,database,laravel,laravel-4,database-migration,Php,Database,Laravel,Laravel 4,Database Migration,我的应用程序需要预先注册的数据集才能工作。因此,我需要在设置应用程序时将它们插入数据库中 提出两种机制: :“它们允许团队修改数据库架构并保持当前架构状态的最新状态。” :“Laravel还提供了一种简单的方法,可以使用种子类为数据库中的测试数据种子。” 当我读到这个描述时,这些解决方案似乎都不适用 一个类似的问题已经被提出。答案建议使用数据库播种器通过检测当前环境来填充数据库: <?php class DatabaseSeeder extends Seeder { pub
- :“它们允许团队修改数据库架构并保持当前架构状态的最新状态。”
- :“Laravel还提供了一种简单的方法,可以使用种子类为数据库中的测试数据种子。”
<?php
class DatabaseSeeder extends Seeder {
public function run()
{
Eloquent::unguard();
if (App::environment() === 'production')
{
$this->call('ProductionSeeder');
}
else
{
$this->call('StagingSeeder');
}
}
}
拉威尔的发展是关于自由的。所以,如果您需要为生产数据库播种,并且认为DatabaseSeeder是最好的地方,为什么不呢 好的,seeder主要用于测试数据,但你会看到一些人在使用它 我将这类重要的种子视为迁移的一部分,因为这是我数据库表中无法使用的内容,并且每次部署应用程序的新版本时都会运行
artisan migrate
,所以我就这样做了
php artisan migrate:make seed_models_table
并在其中创建我的seedind内容:
public function up()
{
$models = array(
array('name' => '...'),
);
DB::table('models')->insert($models);
}
我经常想知道这个问题的正确答案是什么。就个人而言,我不会使用种子填充数据库中所需的行,因为您必须在其中放入大量条件逻辑,以确保您不会尝试填充已经存在的内容。(删除和重新创建数据是非常不可取的,因为您可能会导致密钥不匹配,如果您使用级联删除,您可能会意外地删除数据库中的一部分,我的错误!;-) 我将行的“种子”放入迁移脚本中,因为很有可能,数据需要在那里作为卷展过程的一部分 值得注意的是,您应该使用DB类而不是雄辩的模型来填充这些数据,因为您的类结构可能会随着时间的推移而改变,这将阻止您从头开始重新创建数据库(而不重写历史和更改迁移文件,我相信这是一件坏事) 我倾向于这样做:
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();
}
这样,当我第一次创建town表时,我就可以轻松地“播种”它,并且不会干扰在运行时对它所做的任何添加。这是我在生产中使用的 因为我在每个部署上都运行迁移
artisan migrate
我创建了一个播种器(只是为了避免移植中的播种数据,以便以后方便地访问),然后在移植过程中运行该播种器
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');
}
}
我不会将此seed调用添加到seeds/DatabaseSeeder.php,以避免在新安装上运行它两次。Artisan命令解决方案
php artisan make:command UpsertConfigurationTables
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);
}
}
php artisan upsert:configuration
- 升级功能:如果您想要更改任何种子行,只需在模型中更新它们,就可以在下次部署时更新数据库值。它永远不会创建重复的行
- 软删除模型:请注意,您可以通过将
处的
deleted\u设置为
或true
来定义删除。Artisan命令将处理调用正确的方法来删除或恢复记录false
- 播种机:在生产中运行播种机是对播种机的滥用。我担心的是,未来的工程师会改变播种机,认为这是无害的,因为文件中说它们是用来播种测试数据的
- 迁移:在迁移中设定数据种子很奇怪,这是对迁移目的的滥用。它也不允许在迁移运行后更新这些值
migrate:make
不再定义。改用make:migration
。谢谢你的贡献。我现在使用迁移,我也认为它是播种数据的正确地方。我知道这已经有一年多的历史了,但上述方法真的有效吗?我可以想象你会得到一个“非空冲突”,因为你在插入到表中时没有包括“created_at”和“Update_at”字段。@Ryan我尝试过类似的方法,它不会触发冲突。时间戳只分配了“NULL”值值得注意的是,您应该使用DB类而不是雄辩的模型
这是一个非常好的观点,不仅适用于雄辩的模型,而且适用于任何特定于应用程序的代码!您的迁移将在新安装中使用最新代码运行,因此必须是向前兼容的。这是一个很好的答案。一个
<?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
],
];
}