Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 拉拉维尔:移民与移民;生产数据的播种_Php_Database_Laravel_Laravel 4_Database Migration - Fatal编程技术网

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命令解决方案

  • 创建新的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);
        }
    }
    
  • 将该命令添加到Laravel Forge部署脚本(或任何其他CI部署脚本):
    php artisan upsert:configuration

  • 其他值得注意的事项:

    • 升级功能:如果您想要更改任何种子行,只需在模型中更新它们,就可以在下次部署时更新数据库值。它永远不会创建重复的行
    • 软删除模型:请注意,您可以通过将
      处的
      deleted\u设置为
      true
      false
      来定义删除。Artisan命令将处理调用正确的方法来删除或恢复记录
    其他提到的解决方案的问题:

    • 播种机:在生产中运行播种机是对播种机的滥用。我担心的是,未来的工程师会改变播种机,认为这是无害的,因为文件中说它们是用来播种测试数据的
    • 迁移:在迁移中设定数据种子很奇怪,这是对迁移目的的滥用。它也不允许在迁移运行后更新这些值

    在Laravel中,迁移是关于模式管理,而不是数据管理。播种机用于提供测试数据,但我不认为它们的目的是作为生产数据加载机制。是的,文档中是这么说的。这就是我问这个问题的原因。也许这个软件包会对@KarolFiturski有帮助是的,它看起来很有希望。在laravel 5中,我也尝试将播种机和迁移结合起来。在投入生产之前,一切都是好的。生产与此冻结。请看我的详细信息。谢谢你的回答。我将使用迁移进行播种。这是一个很好的答案。迁移管理模式,但有时需要移动数据。这一切都需要按照严格的顺序进行,迁移能够强制执行这一顺序。我尝试在迁移中调用种子设定,但在投入生产之前一切都正常。生产与此冻结。详情请参阅我的网站。✏️ 请注意,
    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
            ],
        ];
    }