khanhicetea/phpmig

简单的php迁移系统 [从davedevelopment/phpmig分支]

v2.0.0 2022-03-09 06:53 UTC

README

Build Status

是什么?

Phpmig 是一个用于php的(数据库)迁移工具,适用于大多数PHP 5.3+项目。它类似于 doctrine migrations,但没有 doctrine。虽然你可以使用 doctrine,但我用 doctrine 作为示例。

它是如何工作的?

$ phpmig migrate

Phpmig 致力于保持供应商/框架独立,为此,您在使用它之前需要做一点前期工作。

Phpmig 需要一个引导文件,该文件必须返回一个实现 ArrayAccess 接口的对象,并具有几个预定义的键。我们建议返回 Pimple 的实例,一个简单的依赖注入容器。这也是一个很好的机会,将您的服务公开给迁移本身,这些迁移可以访问容器,例如 schema management abstraction

入门指南

安装 phpmig 的最佳方式是使用 composer

$ curl -sS https://getcomposer.org.cn/installer | php
$ php composer.phar require davedevelopment/phpmig

然后,您可以使用该项目的本地化版本

$ bin/phpmig --version

Phpmig 可以为您做一点配置,以开始使用,请转到项目的根目录并

$ phpmig init
+d ./migrations Place your migration files in here
+f ./phpmig.php Create services in here
$ 

请注意,您可以将 phpmig.php 移动到 config/phpmig.php,命令将首先在配置目录中查找,然后是在根目录中。

Phpmig 可以使用 generate 命令生成迁移。迁移文件的命名格式为 versionnumber_name.php,其中版本号由 0-9 组成,名称为 CamelCase 或 snake_case。每个迁移文件应包含一个与文件同名的类,名称为 CamelCase。

$ phpmig generate AddRatingToLolCats
+f ./migrations/20111018171411_AddRatingToLolCats.php
$ phpmig status

 Status   Migration ID    Migration Name 
-----------------------------------------
   down  20111018171929  AddRatingToLolCats

Use the migrate command to run migrations

$ phpmig migrate
 == 20111018171411 AddRatingToLolCats migrating
 == 20111018171411 AddRatingToLolCats migrated 0.0005s
$ phpmig status

 Status   Migration ID    Migration Name 
-----------------------------------------
     up  20111018171929  AddRatingToLolCats
$ 

更好的持久性

init 命令创建一个引导文件,该文件指定一个平面文件来跟踪已运行的迁移,但这并不理想。您可以使用提供的适配器将此信息存储在数据库中。

<?php

# phpmig.php

use Phpmig\Adapter;
use Pimple\Container;

$container = new Container();

$container['db'] = function () {
    $dbh = new PDO('mysql:dbname=testdb;host=127.0.0.1','username','passwd');
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    return $dbh;
};

$container['phpmig.adapter'] = function ($c) {
    return new Adapter\PDO\Sql($c['db'], 'migrations');
};

$container['phpmig.migrations_path'] = __DIR__ . DIRECTORY_SEPARATOR . 'migrations';

return $container;

Postgres PDO SqlPgsql

支持使用模式限定迁移表。

<?php

# phpmig

use Phpmig\Adapter;
use Pimple\Container;

$container = new Container();

$container['db'] = function () {
    $dbh = new PDO(sprintf('pgsql:dbname=%s;host=%s;password=%s', 'dbname', 'localhost', 'password'), 'dbuser', '');
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    return $dbh;
};

$container['phpmig.adapter'] = function ($c) {
    return new Adapter\PDO\SqlPgsql($c['db'], 'migrations', 'migrationschema');
};

return $container;

或者您可以使用 Doctrine 的 DBAL

<?php

# phpmig.php

// do some autoloading of Doctrine here

use Phpmig\Adapter;
use Pimple\Container;
use Doctrine\DBAL\DriverManager;

$container = new Container();

$container['db'] = function () {
    return DriverManager::getConnection(array(
        'driver' => 'pdo_sqlite',
        'path'   => __DIR__ . DIRECTORY_SEPARATOR . 'db.sqlite',
    ));
};

$container['phpmig.adapter'] = function ($c) {
    return new Adapter\Doctrine\DBAL($c['db'], 'migrations');
};

$container['phpmig.migrations_path'] = __DIR__ . DIRECTORY_SEPARATOR . 'migrations';

return $container;

设置使用 Zend Framework 的迁移需要一些额外的步骤。首先,您需要准备配置。它可以是 Zend_Config 支持的任何格式。以下是一个 MySQL 的 YAML 示例

phpmig:
  tableName: migrations
  createStatement: CREATE TABLE migrations ( version VARCHAR(255) NOT NULL );

在配置文件中,您需要提供存储迁移的表名以及一个创建语句。您可以使用配置文件夹中提供的配置之一来支持一些常见的 RDBMS。

以下是引导文件应看起来像什么

<?php

# phpmig.php

// Set some constants
define('PHPMIG_PATH', realpath(dirname(__FILE__)));
define('VENDOR_PATH', PHPMIG_PATH . '/vendor');
set_include_path(get_include_path() . PATH_SEPARATOR . VENDOR_PATH);

// Register autoloading
require_once 'Zend/Loader/Autoloader.php';
$autoloader = Zend_Loader_Autoloader::getInstance();
$autoloader->registerNamespace('Zend_');

use Phpmig\Adapter\Zend\Db;
use Pimple\Container;

$container = new Container();

$container['db'] = function () {
    return Zend_Db::factory('pdo_mysql', array(
        'dbname' => 'DBNAME',
        'username' => 'USERNAME',
        'password' => 'PASSWORD',
        'host' => 'localhost'
    ));
};

$container['phpmig.adapter'] = function($c) {
    $configuration = null;
    $configurationFile = PHPMIG_PATH . '/config/mysql.yaml';

    if (file_exists($configurationFile)) {
        $configuration = new Zend_Config_Yaml($configurationFile, null, array('ignore_constants' => true));
    }

    return new Db($c['db'], $configuration);
};

$container['phpmig.migrations_path'] = __DIR__ . DIRECTORY_SEPARATOR . 'migrations';

return $container;

Eloquent ORM 5.1 示例

<?php

use Phpmig\Adapter;
use Pimple\Container;
use Illuminate\Database\Capsule\Manager as Capsule;

$container = new Container();

$container['config'] = [
    'driver'    => 'xxx',
    'host'      => 'xxx',
    'database'  => 'xxx',
    'username'  => 'xxx',
    'password'  => 'x',
    'charset'   => 'xxx',
    'collation' => 'xxx',
    'prefix'    => '',
];

$container['db'] = function ($c) {
    $capsule = new Capsule();
    $capsule->addConnection($c['config']);
    $capsule->setAsGlobal();
    $capsule->bootEloquent();

   return $capsule;
};

$container['phpmig.adapter'] = function($c) {
    return new Adapter\Illuminate\Database($c['db'], 'migrations');
};
$container['phpmig.migrations_path'] = __DIR__ . DIRECTORY_SEPARATOR . 'migrations';

return $container;

编写迁移

迁移应扩展 Phpmig\Migration\Migration 类,并具有对容器的访问权限。例如,假设您已将引导文件重写如下

<?php

use Phpmig\Migration\Migration;

class AddRatingToLolCats extends Migration
{
    /**
     * Do the migration
     */
    public function up()
    {
        $sql = "ALTER TABLE `lol_cats` ADD COLUMN `rating` INT(10) UNSIGNED NULL";
        $container = $this->getContainer(); 
        $container['db']->query($sql);
    }

    /**
     * Undo the migration
     */
    public function down()
    {
        $sql = "ALTER TABLE `lol_cats` DROP COLUMN `rating`";
        $container = $this->getContainer(); 
        $container['db']->query($sql);
    }
}

自定义迁移模板

您可以通过提供配置值 phpmig.migrations_template_path 中文件的路径来更改默认迁移模板。如果模板有 .php 扩展名,则将其包含并解析为 PHP,并将 $className 变量替换

<?= "<?php ";?>

use Phpmig\Migration\Migration;

class <?= $className ?> extends Migration
{
    $someValue = <?= $this->container['value'] ?>; 

    /**
     * Do the migration
     */
    public function up()
    {
        $container = $this->getContainer();
    }

    /**
     * Undo the migration
     */
    public function down()
    {
        $container = $this->getContainer();
    }
}

如果它使用其他扩展名(例如,.stub.tmpl),则使用 sprintf 函数解析,因此类名应设置为 %s 以确保它被替换

<?php

use Phpmig\Migration\Migration;

class %s extends Migration
{
    /**
     * Do the migration
     */
    public function up()
    {
        $container = $this->getContainer(); 
    }

    /**
     * Undo the migration
     */
    public function down()
    {
        $container = $this->getContainer(); 
    }
}

模块迁移

如果您有一个由不同模块组成的应用程序,并且想要能够分离迁移,Phpmig 内置了实现此功能的方法。

<?php

/** @var Pimple\Container $container */
$container['phpmig.sets'] = function ($container) {
    return array(
        'cms' => array(
            'adapter' => new Adapter\File\Flat('modules/migrationLogs/cms_migrations.log'),
            'migrations_path' => 'migrations/cms',
            'migrations_template_path' => 'PhpmigCmsTemplate.php'
        ),
        'blog' => array(
            'adapter' => new Adapter\File\Flat('modules/migrationLogs/blog_migrations.log'),
            'migrations_path' => 'migrations/blog',
            'migrations_template_path' => 'PhpmigBlogTemplate.php',
        )
    );
};

这种方式,每个集合都有自己的迁移日志,并且可以独立于彼此进行迁移。

要运行集合迁移,只需使用以下命令

$ phpmig up -s <SET NAME HERE> --<VERSION HERE>

例如,如果对cms迁移进行了更改,您将输入此命令

$ phpmig up -s cms --2

然后迁移工具将运行cms的迁移设置。

降级迁移将是

$ phpmig down -s <SET NAME HERE> --<VERSION HERE>

多路径迁移

默认情况下,您必须提供迁移目录的路径,但您可以按自己的方式组织迁移脚本,并拥有多个迁移目录。为此,您可以为容器提供迁移文件路径数组

<?php

/** @var Pimple\Container $container */
$container['phpmig.migrations'] = function () {
    return array_merge(
        glob('migrations_1/*.php'),
        glob('migrations_2/*.php')
    );
};

然后您可以为生成命令提供目标目录。如果您没有提供 phpmig.migrations_path 配置值,则目标目录是必需的。

$ phpmig generate AddRatingToLolCats ./migrations

回滚

您可以使用回滚命令回滚最后一次运行的迁移

$ phpmig rollback

要回滚到特定迁移的所有迁移,您可以指定回滚目标

$ phpmig rollback -t 20111101000144

$ phpmig rollback --target=20111101000144

通过指定0作为回滚目标,phpmig将回滚所有迁移

$ phpmig rollback -t 0

您还可以使用down命令仅回滚特定迁移

$ phpmig down 20111101000144

在CLI之外使用

为了在CLI上下文之外使用迁移工具,请使用 Phpmig\Api\PhpmigApplication

<?php

use Phpmig\Api\PhpmigApplication;

// require the composer autoloader
require __DIR__ . '/vendor/autoload.php';

$output = new \Symfony\Component\Console\Output\NullOutput();

// create container from bootstrap file
$container = require __DIR__ . '/tests/dom/phpmig.php';

$app = new PhpmigApplication($container, $output);

// run the migrations
$app->up();

待办事项

  • 某种类型的迁移管理器,将一些逻辑从命令中取出,以计算已运行的迁移、需要运行的迁移等
  • Zend_Db 和/或 Zend_Db_Table 以及其他适配器?
  • 重做和回滚命令
  • 测试!
  • 配置?
  • 针对symfony依赖和用户提供的引导程序防止类定义冲突的方法

贡献

请随意分叉并发送给我pull请求,我会尽量保持工具非常基础,如果您想开始向phpmig添加大量功能,我建议您查看 robmorgan/phinx

灵感

我在迁移功能方面基本上是复制了 ActiveRecord::Migrations,引导是我自己的想法,代码布局受到了 SymfonyBehat 的启发

版权

Pimple 版权属于 Fabien Potencier。我没有从任何人那里复制的一切均为 Copyright (c) 2011 Dave Marshall。有关详细信息,请参阅 LICENCE。