定制 sglusnevs/phpmig 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

sglusnevs/phpmig

Composer 安装命令:

composer require sglusnevs/phpmig

包简介

A fork of phpmig with migrations named <name>_<timestamp>.php for CLI autocompletion

README 文档

README

Build Status

What is it?

This is a fork of Phpmig database migration tool for php by [https://github.com/davedevelopment/phpmig].

It slightly changes filename schema in migrations, allowing for better autocompletion when working with command line.

How does it work?

$ phpmig migrate

Phpmig aims to be vendor/framework independent, and in doing so, requires you to do a little bit of work up front to use it.

Phpmig requires a bootstrap file, that must return an object that implements the ArrayAccess interface with several predefined keys. We recommend returning an instance of Pimple, a simple dependency injection container. This is also an ideal opportunity to expose your own services to the migrations themselves, which have access to the container, such as a schema management abstraction.

Getting Started

The best way to install phpmig is using composer:

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

You can then use the localised version of phpmig for that project

$ bin/phpmig --version

Phpmig can do a little configuring for you to get started, go to the root of your project and:

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

Note that you can move phpmig.php to config/phpmig.php, the commands will look first in the config directory than in the root.

Phpmig can generate migrations using the generate command. Migration files are named versionnumber_name.php, where version number is made up of 0-9 and name is CamelCase or snake_case. Each migration file should contain a class with the same name as the file in CamelCase.

$ phpmig generate AddRatingToLolCats
+f ./migrations/AddRatingToLolCats_20111018171411.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
$ 

Better Persistence

The init command creates a bootstrap file that specifies a flat file to use to track which migrations have been run, which isn't great. You can use the provided adapters to store this information in your database.

<?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

Adds support for qualifying the migrations table with a schema.

<?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;

Or you can use Doctrine's 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;

Setting up migrations with Zend Framework requires a couple additional steps. You first need to prepare the configuration. It might be in any format supported by Zend_Config. Here is an example in YAML for MySQL:

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

In configuration file you need to provide the table name where the migrations will be stored and a create statement. You can use one of the configurations provided in the config folder for some common RDBMS.

Here is how the bootstrap file should look like:

<?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;

Example with 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;

Writing Migrations

The migrations should extend the Phpmig\Migration\Migration class, and have access to the container. For example, assuming you've rewritten your bootstrap file like above:

<?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);
    }
}

Customising the migration template

You can change the default migration template by providing the path to a file in the phpmig.migrations_template_path config value. If the template has a .php extension it is included and parsed as PHP, and the $className variable is replaced:

<?= "<?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();
    }
}

If it uses any other extension (e.g., .stub or .tmpl) it's parsed using the sprintf function, so the class name should be set to %s to ensure it gets replaced:

<?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(); 
    }
}

Module Migrations

If you have an application that consists of different modules and you want to be able to separate the migration, Phpmig has a built-in way to achieve this.

<?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',
        )
    );
};

this way each set has their own migration log and the ability to migrate changes independently of each other.

to run the set migration you just use the command below:

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

For example, if a change was made to the cms migration, you'll type in this command:

$ phpmig up -s cms --2

and the migration tool will run the migration setup for cms.

to downgrade a migration would be:

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

Multi path migrations

By default you have to provide the path to migrations directory, but you can organize your migrations script however you like and have several migrations directory. To do this you can provide an array of migration file paths to the container :

<?php

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

You can then provide a target directory to the generate command. The target directory is mandatory if you haven't provided a phpmig.migrations_path config value.

$ phpmig generate AddRatingToLolCats ./migrations

Rolling Back

You can roll back the last run migration by using the rollback command

$ phpmig rollback

To rollback all migration up to a specific migration you can specify the rollback target

$ phpmig rollback -t 20111101000144

or

$ phpmig rollback --target=20111101000144

By specifying 0 as the rollback target phpmig will revert all migrations

$ phpmig rollback -t 0

You can also rollback only a specific migration using the down command

$ phpmig down 20111101000144

Using Outside CLI

In order to use the migration tool outside the cli context use 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();

Todo

  • Some sort of migration manager, that will take some of the logic out of the commands for calculating which migrations have been run, which need running etc
  • Adapters for Zend_Db and/or Zend_Db_Table and others?
  • Redo and rollback commands
  • Tests!
  • Configuration?
  • Someway of protecting against class definition clashes with regard to the symfony dependencies and the user supplied bootstrap?

Contributing

Feel free to fork and send me pull requests, I try and keep the tool really basic, if you want to start adding tons of features to phpmig, I'd recommend taking a look at robmorgan/phinx.

Inspiration

I basically started copying ActiveRecord::Migrations in terms of the migration features, the bootstrapping was my own idea, the layout of the code was inspired by Symfony and Behat

Copyright

Pimple is copyright Fabien Potencier. Everything I haven't copied from anyone else is Copyright (c) 2011 Dave Marshall. See LICENCE for further details

sglusnevs/phpmig 适用场景与选型建议

sglusnevs/phpmig 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 13 次下载、GitHub Stars 达 0, 最近一次更新时间为 2019 年 03 月 09 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「migrations」 「database migrations」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 sglusnevs/phpmig 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 sglusnevs/phpmig 我们能提供哪些服务?
定制开发 / 二次开发

基于 sglusnevs/phpmig 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 13
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 1
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 1
  • Forks: 92
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2019-03-09