{"id":13610759,"url":"https://github.com/davedevelopment/phpmig","last_synced_at":"2025-05-14T22:08:28.667Z","repository":{"id":409900,"uuid":"2627554","full_name":"davedevelopment/phpmig","owner":"davedevelopment","description":"Simple migrations system for php","archived":false,"fork":false,"pushed_at":"2025-04-29T15:10:45.000Z","size":245,"stargazers_count":568,"open_issues_count":29,"forks_count":95,"subscribers_count":30,"default_branch":"master","last_synced_at":"2025-05-10T16:39:16.634Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/davedevelopment.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2011-10-22T19:36:51.000Z","updated_at":"2025-04-29T15:10:49.000Z","dependencies_parsed_at":"2024-06-18T10:57:47.775Z","dependency_job_id":"c640723e-4a04-48d4-b3ba-2772ea815347","html_url":"https://github.com/davedevelopment/phpmig","commit_stats":{"total_commits":198,"total_committers":56,"mean_commits":"3.5357142857142856","dds":0.7676767676767677,"last_synced_commit":"7563ddc6c0c330d02fd9a863ee72cbda14475d8e"},"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davedevelopment%2Fphpmig","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davedevelopment%2Fphpmig/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davedevelopment%2Fphpmig/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davedevelopment%2Fphpmig/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/davedevelopment","download_url":"https://codeload.github.com/davedevelopment/phpmig/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254227620,"owners_count":22035673,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T19:01:47.701Z","updated_at":"2025-05-14T22:08:23.646Z","avatar_url":"https://github.com/davedevelopment.png","language":"PHP","readme":"Phpmig\n======\n\n[![Build\nStatus](https://travis-ci.org/davedevelopment/phpmig.png)](https://travis-ci.org/davedevelopment/phpmig)\n\nWhat is it?\n-----------\n\nPhpmig is a (database) migration tool for php, that should be adaptable for use\nwith most PHP 5.3+ projects. It's kind of like [doctrine\nmigrations][doctrinemigrations], without the [doctrine][doctrine]. Although you\ncan use doctrine if you want. And ironically, I use doctrine in my examples.\n\nHow does it work?\n-----------------\n\n```bash\n$ phpmig migrate\n```\n\nPhpmig aims to be vendor/framework independent, and in doing so, requires you to\ndo a little bit of work up front to use it.\n\nPhpmig requires a bootstrap file, that must return an object that implements the\nArrayAccess interface with several predefined keys. We recommend returning an\ninstance of [Pimple][pimple], a simple dependency injection container. This is\nalso an ideal opportunity to expose your own services to the migrations\nthemselves, which have access to the container, such as a [schema management\nabstraction][doctrineschemamanager].\n\nGetting Started\n---------------\n\nThe best way to install phpmig is using composer:\n\n```bash\n$ curl -sS https://getcomposer.org/installer | php\n$ php composer.phar require davedevelopment/phpmig\n```\n\nYou can then use the localised version of phpmig for that project\n\n```bash\n$ bin/phpmig --version\n```\n\nPhpmig can do a little configuring for you to get started, go to the root of\nyour project and:\n\n```bash\n$ phpmig init\n+d ./migrations Place your migration files in here\n+f ./phpmig.php Create services in here\n$ \n```\n\nNote that you can move phpmig.php to config/phpmig.php, the commands will look\nfirst in the config directory than in the root.\n\nPhpmig can generate migrations using the generate command. Migration files are named\nversionnumber_name.php, where version number is made up of 0-9 and name is\nCamelCase or snake\\_case. Each migration file should contain a class with the\nsame name as the file in CamelCase.\n\n```bash\n$ phpmig generate AddRatingToLolCats\n+f ./migrations/20111018171411_AddRatingToLolCats.php\n$ phpmig status\n\n Status   Migration ID    Migration Name \n-----------------------------------------\n   down  20111018171929  AddRatingToLolCats\n\nUse the migrate command to run migrations\n\n$ phpmig migrate\n == 20111018171411 AddRatingToLolCats migrating\n == 20111018171411 AddRatingToLolCats migrated 0.0005s\n$ phpmig status\n\n Status   Migration ID    Migration Name \n-----------------------------------------\n     up  20111018171929  AddRatingToLolCats\n$ \n```\n\nBetter Persistence\n------------------\n\nThe init command creates a bootstrap file that specifies a flat file to use to\ntrack which migrations have been run, which isn't great. You can use the\nprovided adapters to store this information in your database.\n\n```php\n\u003c?php\n\n# phpmig.php\n\nuse Phpmig\\Adapter;\nuse Pimple\\Container;\n\n$container = new Container();\n\n$container['db'] = function () {\n    $dbh = new PDO('mysql:dbname=testdb;host=127.0.0.1','username','passwd');\n    $dbh-\u003esetAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);\n    return $dbh;\n};\n\n$container['phpmig.adapter'] = function ($c) {\n    return new Adapter\\PDO\\Sql($c['db'], 'migrations');\n};\n\n$container['phpmig.migrations_path'] = __DIR__ . DIRECTORY_SEPARATOR . 'migrations';\n\nreturn $container;\n\n```\n\n### Postgres PDO `SqlPgsql` \nAdds support for qualifying the migrations table with a schema.\n\n```php\n\u003c?php\n\n# phpmig\n\nuse Phpmig\\Adapter;\nuse Pimple\\Container;\n\n$container = new Container();\n\n$container['db'] = function () {\n    $dbh = new PDO(sprintf('pgsql:dbname=%s;host=%s;password=%s', 'dbname', 'localhost', 'password'), 'dbuser', '');\n    $dbh-\u003esetAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);\n    return $dbh;\n};\n\n$container['phpmig.adapter'] = function ($c) {\n    return new Adapter\\PDO\\SqlPgsql($c['db'], 'migrations', 'migrationschema');\n};\n\nreturn $container;\n```\n\n\n\nOr you can use Doctrine's DBAL:\n\n```php\n\u003c?php\n\n# phpmig.php\n\n// do some autoloading of Doctrine here\n\nuse Phpmig\\Adapter;\nuse Pimple\\Container;\nuse Doctrine\\DBAL\\DriverManager;\n\n$container = new Container();\n\n$container['db'] = function () {\n    return DriverManager::getConnection(array(\n        'driver' =\u003e 'pdo_sqlite',\n        'path'   =\u003e __DIR__ . DIRECTORY_SEPARATOR . 'db.sqlite',\n    ));\n};\n\n$container['phpmig.adapter'] = function ($c) {\n    return new Adapter\\Doctrine\\DBAL($c['db'], 'migrations');\n};\n\n$container['phpmig.migrations_path'] = __DIR__ . DIRECTORY_SEPARATOR . 'migrations';\n\nreturn $container;\n```\n\nSetting up migrations with Zend Framework  requires a couple additional steps. You first need to prepare\nthe configuration. It might be in any format supported by Zend_Config. Here is an\nexample in YAML for MySQL:\n\n```yaml\nphpmig:\n  tableName: migrations\n  createStatement: CREATE TABLE migrations ( version VARCHAR(255) NOT NULL );\n```\n\nIn configuration file you need to provide the table name where the migrations will\nbe stored and a create statement. You can use one of the configurations provided\nin the config folder for some common RDBMS.\n\nHere is how the bootstrap file should look:\n\n```php\n\u003c?php\n\n# phpmig.php\n\n// Set some constants\ndefine('PHPMIG_PATH', realpath(dirname(__FILE__)));\ndefine('VENDOR_PATH', PHPMIG_PATH . '/vendor');\nset_include_path(get_include_path() . PATH_SEPARATOR . VENDOR_PATH);\n\n// Register autoloading\nrequire_once 'Zend/Loader/Autoloader.php';\n$autoloader = Zend_Loader_Autoloader::getInstance();\n$autoloader-\u003eregisterNamespace('Zend_');\n\nuse Phpmig\\Adapter\\Zend\\Db;\nuse Pimple\\Container;\n\n$container = new Container();\n\n$container['db'] = function () {\n    return Zend_Db::factory('pdo_mysql', array(\n        'dbname' =\u003e 'DBNAME',\n        'username' =\u003e 'USERNAME',\n        'password' =\u003e 'PASSWORD',\n        'host' =\u003e 'localhost'\n    ));\n};\n\n$container['phpmig.adapter'] = function($c) {\n    $configuration = null;\n    $configurationFile = PHPMIG_PATH . '/config/mysql.yaml';\n\n    if (file_exists($configurationFile)) {\n        $configuration = new Zend_Config_Yaml($configurationFile, null, array('ignore_constants' =\u003e true));\n    }\n\n    return new Db($c['db'], $configuration);\n};\n\n$container['phpmig.migrations_path'] = __DIR__ . DIRECTORY_SEPARATOR . 'migrations';\n\nreturn $container;\n```\n\nExample with Eloquent ORM 5.1\n------------------\n```php\n\u003c?php\n\nuse Phpmig\\Adapter;\nuse Pimple\\Container;\nuse Illuminate\\Database\\Capsule\\Manager as Capsule;\n\n$container = new Container();\n\n$container['config'] = [\n    'driver'    =\u003e 'xxx',\n    'host'      =\u003e 'xxx',\n    'database'  =\u003e 'xxx',\n    'username'  =\u003e 'xxx',\n    'password'  =\u003e 'x',\n    'charset'   =\u003e 'xxx',\n    'collation' =\u003e 'xxx',\n    'prefix'    =\u003e '',\n];\n\n$container['db'] = function ($c) {\n    $capsule = new Capsule();\n    $capsule-\u003eaddConnection($c['config']);\n    $capsule-\u003esetAsGlobal();\n    $capsule-\u003ebootEloquent();\n\n   return $capsule;\n};\n\n$container['phpmig.adapter'] = function($c) {\n    return new Adapter\\Illuminate\\Database($c['db'], 'migrations');\n};\n$container['phpmig.migrations_path'] = __DIR__ . DIRECTORY_SEPARATOR . 'migrations';\n\nreturn $container;\n```\n\n\nWriting Migrations\n------------------\n\nThe migrations should extend the Phpmig\\Migration\\Migration class, and have\naccess to the container. For example, assuming you've rewritten your bootstrap\nfile like above:\n\n```php\n\u003c?php\n\nuse Phpmig\\Migration\\Migration;\n\nclass AddRatingToLolCats extends Migration\n{\n    /**\n     * Do the migration\n     */\n    public function up()\n    {\n        $sql = \"ALTER TABLE `lol_cats` ADD COLUMN `rating` INT(10) UNSIGNED NULL\";\n        $container = $this-\u003egetContainer(); \n        $container['db']-\u003equery($sql);\n    }\n\n    /**\n     * Undo the migration\n     */\n    public function down()\n    {\n        $sql = \"ALTER TABLE `lol_cats` DROP COLUMN `rating`\";\n        $container = $this-\u003egetContainer(); \n        $container['db']-\u003equery($sql);\n    }\n}\n```\n\nCustomising the migration template\n-----------------------------------\n\nYou can change the default migration template by providing the path to a file \nin the `phpmig.migrations_template_path` config value. If the template has a \n`.php` extension it is included and parsed as PHP, and the `$className` variable \nis replaced: \n\n```php\n\u003c?= \"\u003c?php \";?\u003e\n\nuse Phpmig\\Migration\\Migration;\n\nclass \u003c?= $className ?\u003e extends Migration\n{\n    $someValue = \u003c?= $this-\u003econtainer['value'] ?\u003e; \n\n    /**\n     * Do the migration\n     */\n    public function up()\n    {\n        $container = $this-\u003egetContainer();\n    }\n\n    /**\n     * Undo the migration\n     */\n    public function down()\n    {\n        $container = $this-\u003egetContainer();\n    }\n}\n```\n\nIf it uses any other extension (e.g., `.stub` or `.tmpl`) it's parsed using the \n`sprintf` function, so the class name should be set to `%s` to ensure it gets \nreplaced: \n\n```php\n\u003c?php\n\nuse Phpmig\\Migration\\Migration;\n\nclass %s extends Migration\n{\n    /**\n     * Do the migration\n     */\n    public function up()\n    {\n        $container = $this-\u003egetContainer(); \n    }\n\n    /**\n     * Undo the migration\n     */\n    public function down()\n    {\n        $container = $this-\u003egetContainer(); \n    }\n}\n```\n\nModule Migrations\n---------------------\n\nIf 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.\n\n```php\n\u003c?php\n\n/** @var Pimple\\Container $container */\n$container['phpmig.sets'] = function ($container) {\n    return array(\n        'cms' =\u003e array(\n            'adapter' =\u003e new Adapter\\File\\Flat('modules/migrationLogs/cms_migrations.log'),\n            'migrations_path' =\u003e 'migrations/cms',\n            'migrations_template_path' =\u003e 'PhpmigCmsTemplate.php'\n        ),\n        'blog' =\u003e array(\n            'adapter' =\u003e new Adapter\\File\\Flat('modules/migrationLogs/blog_migrations.log'),\n            'migrations_path' =\u003e 'migrations/blog',\n            'migrations_template_path' =\u003e 'PhpmigBlogTemplate.php',\n        )\n    );\n};\n```\n\nthis way each set has their own migration log and the ability to migrate changes independently of each other.\n\nto run the set migration you just use the command below:\n\n```bash\n$ phpmig up -s \u003cSET NAME HERE\u003e --\u003cVERSION HERE\u003e\n```\n\nFor example, if a change was made to the cms migration, you'll type in this command:\n\n```bash\n$ phpmig up -s cms --2\n```\n\nand the migration tool will run the migration setup for cms.\n\nto downgrade a migration would be:\n\n```bash\n$ phpmig down -s \u003cSET NAME HERE\u003e --\u003cVERSION HERE\u003e\n```\n\nMulti path migrations\n---------------------\n\nBy default you have to provide the path to migrations directory, but you can\norganize your migrations script however you like and have several migrations\ndirectory.  To do this you can provide an array of migration file paths to the\ncontainer :\n\n```php\n\u003c?php\n\n/** @var Pimple\\Container $container */\n$container['phpmig.migrations'] = function () {\n    return array_merge(\n        glob('migrations_1/*.php'),\n        glob('migrations_2/*.php')\n    );\n};\n```\n\nYou can then provide a target directory to the generate command. The target\ndirectory is mandatory if you haven't provided a `phpmig.migrations_path` config\nvalue.\n\n```bash\n$ phpmig generate AddRatingToLolCats ./migrations\n```\n\nRolling Back\n------------\n\nYou can roll back the last run migration by using the rollback command\n\n```bash\n$ phpmig rollback\n```\n\nTo rollback all migration up to a specific migration you can specify the\nrollback target\n\n```bash\n$ phpmig rollback -t 20111101000144\n```\n\nor\n\n```bash\n$ phpmig rollback --target=20111101000144\n```\n\nBy specifying 0 as the rollback target phpmig will revert all migrations \n\n```bash\n$ phpmig rollback -t 0\n```\n\nYou can also rollback only a specific migration using the down command\n\n```bash\n$ phpmig down 20111101000144\n```\n\nUsing Outside CLI\n-----------------\nIn order to use the migration tool outside the cli context use `Phpmig\\Api\\PhpmigApplication`.\n\n```php\n\u003c?php\n\nuse Phpmig\\Api\\PhpmigApplication;\n\n// require the composer autoloader\nrequire __DIR__ . '/vendor/autoload.php';\n\n$output = new \\Symfony\\Component\\Console\\Output\\NullOutput();\n\n// create container from bootstrap file\n$container = require __DIR__ . '/tests/dom/phpmig.php';\n\n$app = new PhpmigApplication($container, $output);\n\n// run the migrations\n$app-\u003eup();\n```\n\nTodo\n----\n\n* Some sort of migration manager, that will take some of the logic out of the\n  commands for calculating which migrations have been run, which need running\n  etc\n* Adapters for Zend\\_Db and/or Zend\\_Db\\_Table and others?\n* Redo and rollback commands\n* Tests!\n* Configuration? \n* Someway of protecting against class definition clashes with regard to the\n  symfony dependencies and the user supplied bootstrap?\n\nContributing\n------------\n\nFeel free to fork and send me pull requests, I try and keep the tool really\nbasic, if you want to start adding tons of features to phpmig, I'd recommend\ntaking a look at [robmorgan/phinx](https://github.com/robmorgan/phinx).\n\nInspiration\n-----------\n\nI basically started copying [ActiveRecord::Migrations][activerecordmigrations]\nin terms of the migration features, the bootstrapping was my own idea, the\nlayout of the code was inspired by [Symfony][symfony] and [Behat][behat]\n\nCopyright\n---------\n\n[Pimple][pimple] is copyright Fabien Potencier. Everything I haven't copied from\nanyone else is Copyright (c) 2011 Dave Marshall. See LICENCE for further details\n\n\n[pimple]:https://github.com/fabpot/Pimple\n[doctrinemigrations]:https://github.com/doctrine/migrations\n[doctrine]:https://github.com/doctrine\n[behat]:http://behat.org/\n[symfony]:http://symfony.com/\n[activerecordmigrations]:http://api.rubyonrails.org/classes/ActiveRecord/Migration.html\n[doctrineschemamanager]:http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/schema-manager.html\n","funding_links":[],"categories":["Table of Contents","迁移","PHP","目录","迁移 Migrations","ORM and Datamapping","Migrations","迁移( Migrations )"],"sub_categories":["Migrations","迁移 Migrations"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavedevelopment%2Fphpmig","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdavedevelopment%2Fphpmig","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavedevelopment%2Fphpmig/lists"}