├── LICENSE ├── composer.json ├── readme-ja.md ├── readme.md ├── sources ├── Commands │ ├── DatabaseAgainCommand.php │ ├── DatabaseCleanCommand.php │ ├── DatabaseCommandTrait.php │ ├── DatabaseRefreshCommand.php │ ├── DatabaseRollbackCommand.php │ ├── DatabaseSeedCommand.php │ ├── DatabaseStatusCommand.php │ ├── DatabaseUpgradeCommand.php │ ├── MigrationMakeCommand.php │ └── SeederMakeCommand.php ├── Migrator.php ├── ServiceProvider.php └── Support │ ├── DatabaseServiceProvider.php │ ├── Migration.php │ └── Seeder.php └── stubs ├── migration-create.stub ├── migration-update.stub ├── migration.stub └── seeder.stub /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Fumio Furukawa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jumilla/laravel-versionia", 3 | "type": "framework-extension", 4 | "description": "Version based database migration system for Laravel 5.", 5 | "license": "MIT", 6 | "keywords": ["Laravel", "Laravel 5", "databaes", "migration"], 7 | "homepage": "http://jumilla.me", 8 | "authors": [ 9 | { 10 | "name": "Fumio Furukawa", 11 | "email": "fumio@jumilla.me" 12 | } 13 | ], 14 | "require": { 15 | "php": "^7.0", 16 | "illuminate/console": "^5.5", 17 | "illuminate/container": "^5.5", 18 | "illuminate/contracts": "^5.5", 19 | "illuminate/database": "^5.5", 20 | "illuminate/support": "^5.5", 21 | "jumilla/laravel-source-generator": "^1.3" 22 | }, 23 | "require-dev": { 24 | "phpunit/phpunit": "^6.0", 25 | "mockery/mockery": "~0.9" 26 | }, 27 | "autoload": { 28 | "psr-4": { 29 | "Jumilla\\Versionia\\Laravel\\": "sources/" 30 | } 31 | }, 32 | "extra": { 33 | "laravel": { 34 | "providers": [ 35 | "Jumilla\\Versionia\\Laravel\\ServiceProvider" 36 | ], 37 | "aliases": { 38 | } 39 | } 40 | }, 41 | "minimum-stability": "stable" 42 | } 43 | -------------------------------------------------------------------------------- /readme-ja.md: -------------------------------------------------------------------------------- 1 | # LARAVEL VERSIONIA 2 | 3 | [![Build Status](https://travis-ci.org/jumilla/laravel-versionia.svg)](https://travis-ci.org/jumilla/laravel-versionia) 4 | [![Quality Score](https://img.shields.io/scrutinizer/g/jumilla/laravel-versionia.svg?style=flat)](https://scrutinizer-ci.com/g/jumilla/laravel-versionia) 5 | [![Code Coverage](https://scrutinizer-ci.com/g/jumilla/laravel-versionia/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/jumilla/laravel-versionia/) 6 | [![Latest Stable Version](https://poser.pugx.org/jumilla/laravel-versionia/v/stable.svg)](https://packagist.org/packages/jumilla/laravel-versionia) 7 | [![Total Downloads](https://poser.pugx.org/jumilla/laravel-versionia/d/total.svg)](https://packagist.org/packages/jumilla/laravel-versionia) 8 | [![Software License](https://poser.pugx.org/jumilla/laravel-versionia/license.svg)](https://packagist.org/packages/jumilla/laravel-versionia) 9 | 10 | Version based database migration system for Laravel 5. 11 | 12 | Laravel Versionia(バージョニア) は、バージョンベースのデータベースマイグレーションシステムです。 13 | Laravel 5 と Lumen 5 で使えます。 14 | 15 | ## コンセプト 16 | 17 | Laravel 4 と 5 には、データベース(RDB)スキーマの管理のために「マイグレーション」という機能が標準搭載されています。 18 | 19 | マイグレーションはスキーマの作成・変更を時系列で管理していく仕組みです。 20 | データベースの初期データを定義する「シード」の実装のためのPHPクラス、artisanコマンドも提供します。 21 | 22 | Versioniaは、標準のマイグレーションをさらに使いやすくします。 23 | 24 | - Laravel 5のマイグレーションに、実装者が明示的に定義する「バージョン」の機能を追加します。 25 | - Laravel 5の`Seeder`クラスを名前で識別できるようにし、複数のシードの切り替えを容易にします。 26 | - Laravel 5のアーキテクチャに沿い、サービスプロバイダで提供します。 27 | - マイグレーション、シードのクラスは`app`ディレクトリ下に配置できます。 28 | 29 | Laravel 5 アプリケーションやComposerパッケージが機能を提供する仕組みとしてサービスプロバイダが用いられます。 30 | サービスプロバイダでルーティングやイベントリスナーの定義などを行いますが、ここにマイグレーション、シードの定義ができるようになります。 31 | 32 | ## インストール方法 33 | 34 | ### [A] Laravel Extension を組み込む (Laravel) 35 | 36 | Laravel 5を使用される場合はこちら推奨です。 37 | Note: パッケージディスカバリーに対応しています。 38 | 39 | [Composer](http://getcomposer.org)を使います。 40 | 41 | ```sh 42 | composer require laravel-plus/extension 43 | ``` 44 | 45 | 詳しくは [Laravel Extension](https://github.com/jumilla/laravel-extension) の説明をお読みください。 46 | 47 | ### [B] Versionia を組み込む (Laravel) 48 | 49 | Note: パッケージディスカバリーに対応しています。 50 | 51 | [Composer](http://getcomposer.org)を使います。 52 | 53 | ```sh 54 | composer require jumilla/laravel-versionia 55 | ``` 56 | 57 | ### [C] Versionia を組み込む (Lumen) 58 | 59 | Lumenを使用される場合はこちらをどうぞ。 60 | 61 | [Composer](http://getcomposer.org)を使います。 62 | 63 | ```sh 64 | composer require jumilla/laravel-versionia 65 | ``` 66 | 67 | 続いて、`boostrap/app.php`に次のコードを追記します。 68 | 69 | ```php 70 | $app->register(Jumilla\Versionia\Laravel\ServiceProvider::class); 71 | ``` 72 | 73 | ## マイグレーションバージョン定義 74 | 75 | 今まではマイグレーションクラスのファイル名に命名規則があり、ファイル名に埋め込まれたファイル生成日時によりマイグレーションの順序が決められていました。 76 | Versioniaでは、マイグレーションクラスごとにグループとバージョンを明示的に付与し、`DatabaseServiceProvider`クラスで定義します。 77 | 78 | ```php 79 | migrations('framework', [ 97 | '1.0' => Migrations\Framework_1_0::class, 98 | ]); 99 | 100 | $this->migrations('app', [ 101 | '1.0' => Migrations\App_1_0::class, 102 | ]); 103 | 104 | // ... seed definition ... 105 | } 106 | } 107 | ``` 108 | 109 | ### DatabaseServiceProvider の登録 110 | 111 | サービスプロバイダを新しく作成した場合は登録してください。 112 | [Laravel Extension](https://github.com/jumilla/laravel-extension) を使用している場合は、既に組み込まれているので追加不要です。 113 | 114 | #### Laravel 115 | 116 | `app\config.php` に `App\Providers\DatabaseServiceProvider::class` を追記します。 117 | 118 | ```php 119 | 'providers' => [ 120 | ... 121 | App\Providers\ConfigServiceProvider::class, 122 | App\Providers\DatabaseServiceProvider::class, 123 | App\Providers\EventServiceProvider::class, 124 | ... 125 | ], 126 | ``` 127 | 128 | #### Lumen 129 | 130 | `bootstrap\app.php` に次のコードを追記します。 131 | 132 | ```php 133 | $app->register(App\Providers\DatabaseServiceProvider::class); 134 | ``` 135 | 136 | ### バージョン番号 137 | 138 | Versioniaはバージョン番号の比較に、PHP標準関数の`version_compare()`を用いています。 139 | バージョン番号は、ドット区切りの**文字列**を指定してください。 140 | 141 | ### マイグレーションクラス 142 | 143 | マイグレーションクラスは、Laravel 5標準の`make:migration`で生成されたものがそのまま使えます。 144 | 145 | 推奨の`app\Database\Migrations`ディレクトリに配置する場合は、`namespace App\Database\Migrations`を追加してください。 146 | 147 | ### マイグレーション定義 148 | 149 | 次のコードはマイグレーション定義のサンプルです。 150 | 151 | ```php 152 | increments('id'); 171 | $table->string('title'); 172 | $table->text('content'); 173 | $table->json('properties'); 174 | $table->timestamps(); 175 | }); 176 | } 177 | 178 | /** 179 | * Migrate the database to backword. 180 | * 181 | * @return void 182 | */ 183 | public function down() 184 | { 185 | Schema::dropIfExists('posts'); 186 | } 187 | } 188 | ``` 189 | 190 | ## シード定義 191 | 192 | 次のサンプルコードでは、シード `test`, `staging`, `production` を定義しています。 193 | `seeds()`メソッドの第2引数はデフォルトシードの指定で、`test`を指定しています。 194 | 195 | ```php 196 | seeds([ 216 | 'test' => Seeds\Test::class, 217 | 'staging' => Seeds\Staging::class, 218 | 'production' => Seeds\Production::class, 219 | ], 'test'); 220 | } 221 | } 222 | ``` 223 | 224 | シードクラスは次のように記述します。 225 | 226 | ```php 227 | table('posts')->truncate(); 246 | 247 | app('db')->table('posts')->insert([ 248 | 'title' => 'Sample post', 249 | 'content' => 'Hello laravel world.', 250 | 'properties' => json_encode([ 251 | 'author' => 'Seeder', 252 | ], JSON_PRETTY_PRINT), 253 | 'created_at' => $now, 254 | 'updated_at' => $now, 255 | ]); 256 | } 257 | } 258 | ``` 259 | 260 | ## コマンド 261 | 262 | ### `database:status` 263 | 264 | マイグレーション、シードの定義とインストール状態を表示します。 265 | 266 | ```sh 267 | php artisan database:status 268 | ``` 269 | 270 | ### `database:upgrade` 271 | 272 | すべてのグループのマイグレーションの`up()`を実行し、最新バージョンにします。 273 | 274 | ```sh 275 | php artisan database:upgrade 276 | ``` 277 | 278 | マイグレーション後にシードを実行させることもできます。 279 | 280 | ```sh 281 | php artisan database:upgrade --seed <シード> 282 | ``` 283 | 284 | ### `database:clean` 285 | 286 | すべてのグループのマイグレーションの`down()`を実行し、クリーン状態に戻します。 287 | 288 | ```sh 289 | php artisan database:clean 290 | ``` 291 | 292 | ### `database:refresh` 293 | 294 | すべてのグループのマイグレーションをやり直します。 295 | 296 | `database:clean`と`database:upgrade`を実行した結果と同じです。 297 | 298 | ```sh 299 | php artisan database:refresh 300 | ``` 301 | 302 | マイグレーション後にシードを実行させることもできます。 303 | 304 | ```sh 305 | php artisan database:refresh --seed <シード> 306 | ``` 307 | 308 | ### `database:rollback` 309 | 310 | 指定グループのバージョンをひとつ戻します。 311 | 312 | ```sh 313 | php artisan database:rollback <グループ> 314 | ``` 315 | 316 | `--all`オプションを付けると、指定グループのすべてのバージョンを削除します。 317 | 318 | ```sh 319 | php artisan database:rollback <グループ> --all 320 | ``` 321 | 322 | ### `database:again` 323 | 324 | 指定グループの最新バージョンを再作成します。 325 | 326 | `database:rollback <グループ>`と`database:upgrade`を実行したときと同じ効果があります。 327 | 328 | ```sh 329 | php artisan database:again <グループ> 330 | ``` 331 | 332 | マイグレーション後にシードを実行させることもできます。 333 | 334 | ```sh 335 | php artisan database:again <グループ> --seed <シード> 336 | ``` 337 | 338 | ### `database:seed` 339 | 340 | 指定のシードを実行します。 341 | 342 | ```sh 343 | php artisan database:seed <シード> 344 | ``` 345 | 346 | `<シード>`を省略した場合、デフォルトのシードを実行します。 347 | 348 | ```sh 349 | php artisan database:seed 350 | ``` 351 | 352 | ## 著作権 353 | 354 | 古川 文生 / Fumio Furukawa (fumio@jumilla.me) 355 | 356 | ## ライセンス 357 | 358 | MIT 359 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # LARAVEL VERSIONIA 2 | 3 | [![Build Status](https://travis-ci.org/jumilla/laravel-versionia.svg)](https://travis-ci.org/jumilla/laravel-versionia) 4 | [![Quality Score](https://img.shields.io/scrutinizer/g/jumilla/laravel-versionia.svg?style=flat)](https://scrutinizer-ci.com/g/jumilla/laravel-versionia) 5 | [![Code Coverage](https://scrutinizer-ci.com/g/jumilla/laravel-versionia/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/jumilla/laravel-versionia/) 6 | [![Latest Stable Version](https://poser.pugx.org/jumilla/laravel-versionia/v/stable.svg)](https://packagist.org/packages/jumilla/laravel-versionia) 7 | [![Total Downloads](https://poser.pugx.org/jumilla/laravel-versionia/d/total.svg)](https://packagist.org/packages/jumilla/laravel-versionia) 8 | [![Software License](https://poser.pugx.org/jumilla/laravel-versionia/license.svg)](https://packagist.org/packages/jumilla/laravel-versionia) 9 | 10 | [日本語ドキュメント - Japanese](readme-ja.md) 11 | 12 | Version based database migration system for Laravel 5. 13 | 14 | Laravel Versionia is version based database migration system. 15 | It can be used in Laravel 5 and Lumen 5. 16 | 17 | ## Concepts 18 | 19 | The feature as "migration" loads standards into Laravel 4 and 5 for management of a database (RDB) schema. 20 | 21 | Migration is the mechanism that making of a schema and change are being managed by time series. 22 | A PHP class for the mounting of "seed" as which data is defined an early stage of a data base and the artisan command are also offered. 23 | 24 | Versionia makes standard migration easier to use. 25 | 26 | - Add the programmer specified "version" to migration of Laravel 5. 27 | - As `Seeder` class of Laravel 5 can be distinguished under the name, more than one seed is changed easily. 28 | - It's offered by a service provider along architecture of Laravel 5. 29 | - Migration and seed classes can be arranged under the `app` directory. 30 | 31 | A service provider is employed as Laravel 5 application and the mechanism that a Composer package offers the function. 32 | The definition which are routing and an event listener by a service provider is given, but migrations and seeds can be defined now here. 33 | 34 | ## Installation method 35 | 36 | ### [A] Include Laravel Extension (Laravel). 37 | 38 | When using Laravel 5, it's recommendation here. 39 | Note: Pacakge Discovery supported. 40 | 41 | Use [Composer](http://getcomposer.org). 42 | 43 | ```sh 44 | composer require laravel-plus/extension 45 | ``` 46 | 47 | Please read the explanation of [Laravel Extension](https://github.com/jumilla/laravel-extension) for more information. 48 | 49 | ### [B] Include Versionia (Laravel) 50 | 51 | Note: Pacakge Discovery supported. 52 | 53 | Use [Composer](http://getcomposer.org). 54 | 55 | ```sh 56 | composer require jumilla/laravel-versionia 57 | ``` 58 | 59 | ### [C] Include Versionia (Lumen) 60 | 61 | When using Lumen, it's recommendation here. 62 | 63 | Use [Composer](http://getcomposer.org). 64 | 65 | ```sh 66 | composer require jumilla/laravel-versionia 67 | ``` 68 | 69 | Next the next code is added to `boostrap/app.php`. 70 | 71 | ```php 72 | $app->register(Jumilla\Versionia\Laravel\ServiceProvider::class); 73 | ``` 74 | 75 | ## Migration version definition 76 | 77 | There was Naming Rule in the file name of migration class so far, and an order of migration had been decided by the file generation date and time when you were embedded in the file name. 78 | A group and the version are given specifically every migration class and it's defined by the `DatabaseServiceProvider` class in Versionia. 79 | 80 | ```php 81 | migrations('framework', [ 99 | '1.0' => Migrations\Framework_1_0::class, 100 | ]); 101 | 102 | $this->migrations('app', [ 103 | '1.0' => Migrations\App_1_0::class, 104 | ]); 105 | 106 | // ... seed definition ... 107 | } 108 | } 109 | ``` 110 | 111 | ### Registration of DatabaseServiceProvider 112 | 113 | When making a service provider newly, please register. 114 | When using [Laravel Extension](https://github.com/jumilla/laravel-extension) it's included already, so addition is unnecessary. 115 | 116 | #### Laravel 117 | 118 | `App\Providers\DatabaseServiceProvider::class` is added to `app\config.php`. 119 | 120 | ```php 121 | 'providers' => [ 122 | ... 123 | App\Providers\ConfigServiceProvider::class, 124 | App\Providers\DatabaseServiceProvider::class, 125 | App\Providers\EventServiceProvider::class, 126 | ... 127 | ], 128 | ``` 129 | 130 | #### Lumen 131 | 132 | The next code is added to `bootstrap\app.php`. 133 | 134 | ```php 135 | $app->register(App\Providers\DatabaseServiceProvider::class); 136 | ``` 137 | 138 | ### Version Number 139 | 140 | Versionia is using PHP standard function `version_compare()` for comparison of a version number. 141 | Please designate a character string of a dot end as a version number. 142 | 143 | ### Migration class 144 | 145 | The one generated by `make:migration` of Laravel 5 standard can use migration class just as it is. 146 | 147 | When arranging in `app\Database\Migrations` directory of recommendation, please add `namespace App\Database\Migrations`. 148 | 149 | The next code is a sample of migration definition. 150 | 151 | ```php 152 | increments('id'); 171 | $table->string('title'); 172 | $table->text('content'); 173 | $table->json('properties'); 174 | $table->timestamps(); 175 | }); 176 | } 177 | 178 | /** 179 | * Migrate the database to backword. 180 | * 181 | * @return void 182 | */ 183 | public function down() 184 | { 185 | Schema::dropIfExists('posts'); 186 | } 187 | } 188 | ``` 189 | 190 | ## Seed class 191 | 192 | A seed defines `test`, `staging`, `production` by the next sample code. 193 | The 2nd argument of method `seeds()` designates `test` by designation of a default seed. 194 | 195 | ```php 196 | seeds([ 216 | 'test' => Seeds\Test::class, 217 | 'staging' => Seeds\Staging::class, 218 | 'production' => Seeds\Production::class, 219 | ], 'test'); 220 | } 221 | } 222 | ``` 223 | 224 | A seed class is described as follows. 225 | 226 | ```php 227 | table('posts')->truncate(); 246 | 247 | app('db')->table('posts')->insert([ 248 | 'title' => 'Sample post', 249 | 'content' => 'Hello laravel world.', 250 | 'properties' => json_encode([ 251 | 'author' => 'Seeder', 252 | ], JSON_PRETTY_PRINT), 253 | 'created_at' => $now, 254 | 'updated_at' => $now, 255 | ]); 256 | } 257 | } 258 | ``` 259 | 260 | ## Commands 261 | 262 | ### `database:status` 263 | 264 | Migration and seed definition, installation state are displayed. 265 | 266 | ```sh 267 | php artisan database:status 268 | ``` 269 | 270 | ### `database:upgrade` 271 | 272 | Run migration method `up()` of all groups, then up-to-date。 273 | 274 | ```sh 275 | php artisan database:upgrade 276 | ``` 277 | 278 | It's possible to make them seed after migration. 279 | 280 | ```sh 281 | php artisan database:upgrade --seed 282 | ``` 283 | 284 | ### `database:clean` 285 | 286 | Run migation method `down()` of all groups, then clean state. 287 | 288 | ```sh 289 | php artisan database:clean 290 | ``` 291 | 292 | ### `database:refresh` 293 | 294 | Migration of all groups is redone. 295 | 296 | It's same run `database:clean` and `database:upgrade`. 297 | 298 | ```sh 299 | php artisan database:refresh 300 | ``` 301 | 302 | It's possible to run seed after migration. 303 | 304 | ```sh 305 | php artisan database:refresh --seed 306 | ``` 307 | 308 | ### `database:rollback` 309 | 310 | The version of the designation group is returned one. 311 | 312 | ```sh 313 | php artisan database:rollback 314 | ``` 315 | 316 | When `--all` option specified, remove all version of group. 317 | 318 | ```sh 319 | php artisan database:rollback --all 320 | ``` 321 | 322 | ### `database:again` 323 | 324 | Re-run latest migration version of group. 325 | 326 | It's same effect as run `database:rollback ` and `database:upgrade`. 327 | 328 | ```sh 329 | php artisan database:again 330 | ``` 331 | 332 | It's possible to run seed after migration. 333 | 334 | ```sh 335 | php artisan database:again --seed 336 | ``` 337 | 338 | ### `database:seed` 339 | 340 | Run specified seed. 341 | 342 | ```sh 343 | php artisan database:seed 344 | ``` 345 | 346 | When omitting ``, run default seed. 347 | 348 | ```sh 349 | php artisan database:seed 350 | ``` 351 | 352 | ## Copyright 353 | 354 | 古川 文生 / Fumio Furukawa (fumio@jumilla.me) 355 | 356 | ## License 357 | 358 | MIT 359 | -------------------------------------------------------------------------------- /sources/Commands/DatabaseAgainCommand.php: -------------------------------------------------------------------------------- 1 | confirmToProceed()) { 43 | return; 44 | } 45 | 46 | $group = $this->argument('group'); 47 | 48 | // check valid group 49 | if (!in_array($group, $migrator->migrationGroups())) { 50 | throw new UnexpectedValueException("Migation group '$group' is not defined."); 51 | } 52 | 53 | $migrator->makeLogTable(); 54 | 55 | $this->doAgain($migrator, $group); 56 | 57 | $seed = $this->option('seed'); 58 | 59 | if ($seed) { 60 | $this->call('database:seed', ['name' => $seed, '--force' => true]); 61 | } 62 | } 63 | 64 | /** 65 | * Execute rollback and upgrade one version. 66 | * 67 | * @param \Jumilla\Versionia\Laravel\Migrator $migrator 68 | * @param string $group 69 | */ 70 | protected function doAgain(Migrator $migrator, $group) 71 | { 72 | // retreive installed versions 73 | $installed_migrations = $migrator->installedLatestMigrations(); 74 | 75 | $installed_version = data_get($installed_migrations, $group.'.version', Migrator::VERSION_NULL); 76 | 77 | $definition_versions = $migrator->migrationVersionsByDesc($group); 78 | 79 | if (!$this->checkInstalledVersion($installed_version, $definition_versions)) { 80 | return; 81 | } 82 | 83 | // remove migration log 84 | $definition_latest_version = array_get(array_keys($definition_versions), 0, Migrator::VERSION_NULL); 85 | if ($migrator->compareMigrationVersion($installed_version, $definition_latest_version) >= 0) { 86 | $this->line("Remove log [$group/$installed_version]"); 87 | $migrator->removeMigrationLog($group, $installed_version); 88 | } 89 | 90 | // downgrade & upgrade 91 | foreach ($definition_versions as $version => $class) { 92 | $this->infoDowngrade($group, $version, $class); 93 | 94 | $migrator->doDowngrade($group, $version, $class); 95 | 96 | $this->infoUpgrade($group, $version, $class); 97 | 98 | $migrator->doUpgrade($group, $version, $class); 99 | 100 | break; 101 | } 102 | } 103 | 104 | /** 105 | * Check installed version. 106 | * 107 | * @param string $installed_version 108 | * @param array $definition_versions 109 | * 110 | * @return bool 111 | */ 112 | protected function checkInstalledVersion($installed_version, array $definition_versions) 113 | { 114 | if ($installed_version === null) { 115 | $this->error('Nothing installed version.'); 116 | $this->line('Please run database:upgrade.'); 117 | 118 | return false; 119 | } 120 | 121 | $index = array_search($installed_version, array_keys($definition_versions)); 122 | 123 | if ($index === false) { 124 | $versions = json_encode(array_keys($definition_versions)); 125 | $this->error("Installed version '{$installed_version}' was not found in definition {$versions}."); 126 | 127 | return false; 128 | } 129 | 130 | if ($index >= 2) { 131 | $this->error("Installed version '$installed_version' was older."); 132 | $this->line('Please run database:upgrade.'); 133 | 134 | return false; 135 | } 136 | 137 | return true; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /sources/Commands/DatabaseCleanCommand.php: -------------------------------------------------------------------------------- 1 | confirmToProceed()) { 40 | return; 41 | } 42 | 43 | $migrator->makeLogTable(); 44 | 45 | $installed_migrations = $migrator->installedMigrationsByDesc(); 46 | 47 | foreach ($installed_migrations as $group => $migrations) { 48 | foreach ($migrations as $data) { 49 | $this->infoDowngrade($group, $data->version, $data->class); 50 | 51 | $migrator->doDowngrade($group, $data->version); 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /sources/Commands/DatabaseCommandTrait.php: -------------------------------------------------------------------------------- 1 | line("Up [{$group}/{$version}] class {$class}"); 15 | } 16 | 17 | /** 18 | * @param string $group 19 | * @param string $version 20 | * @param string $class 21 | */ 22 | protected function infoDowngrade($group, $version, $class) 23 | { 24 | $this->line("Down [{$group}/{$version}] class {$class}"); 25 | } 26 | 27 | /** 28 | * @param string $seed 29 | * @param string $class 30 | */ 31 | protected function infoSeedRun($seed, $class) 32 | { 33 | $this->line("Run [$seed] class {$class}"); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /sources/Commands/DatabaseRefreshCommand.php: -------------------------------------------------------------------------------- 1 | confirmToProceed()) { 41 | return; 42 | } 43 | 44 | $migrator->makeLogTable(); 45 | 46 | $this->doRefresh($migrator); 47 | 48 | $seed = $this->option('seed'); 49 | 50 | if ($seed) { 51 | $this->call('database:seed', ['name' => $seed, '--force' => true]); 52 | } 53 | } 54 | 55 | /** 56 | * Execute clean and upgrade. 57 | * 58 | * @param \Jumilla\Versionia\Laravel\Migrator $migrator 59 | */ 60 | protected function doRefresh(Migrator $migrator) 61 | { 62 | // retreive installed versions 63 | $installed_migrations = $migrator->installedMigrationsByDesc(); 64 | 65 | // downgrade 66 | foreach ($installed_migrations as $group => $migrations) { 67 | foreach ($migrations as $data) { 68 | $this->infoDowngrade($group, $data->version, $data->class); 69 | 70 | $migrator->doDowngrade($group, $data->version); 71 | } 72 | } 73 | 74 | // upgrade 75 | foreach ($migrator->migrationGroups() as $group) { 76 | foreach ($migrator->migrationVersions($group) as $version => $class) { 77 | $this->infoUpgrade($group, $version, $class); 78 | 79 | $migrator->doUpgrade($group, $version, $class); 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /sources/Commands/DatabaseRollbackCommand.php: -------------------------------------------------------------------------------- 1 | confirmToProceed()) { 43 | return; 44 | } 45 | 46 | $group = $this->argument('group'); 47 | 48 | // check valid group 49 | if (!in_array($group, $migrator->migrationGroups())) { 50 | throw new UnexpectedValueException("Migation group '$group' is not defined."); 51 | } 52 | 53 | $version = $this->option('all') ? Migrator::VERSION_NULL : $migrator->migrationLatestVersion($group); 54 | 55 | $migrator->makeLogTable(); 56 | 57 | $this->doRollback($migrator, $group, $version); 58 | } 59 | 60 | /** 61 | * Execute rollback. 62 | * 63 | * @param \Jumilla\Versionia\Laravel\Migrator $migrator 64 | * @param string $target_group 65 | * @param string $target_version 66 | */ 67 | protected function doRollback(Migrator $migrator, $target_group, $target_version) 68 | { 69 | $installed_migrations = $migrator->installedMigrationsByDesc(); 70 | 71 | if (!isset($installed_migrations[$target_group])) { 72 | $this->info("Nothing migrations for group '$target_group'."); 73 | 74 | return; 75 | } 76 | 77 | foreach ($installed_migrations[$target_group] as $data) { 78 | // check version 79 | if ($migrator->compareMigrationVersion($data->version, $target_version) < 0) { 80 | continue; 81 | } 82 | 83 | $this->infoDowngrade($target_group, $data->version, $data->class); 84 | 85 | $migrator->doDowngrade($target_group, $data->version); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /sources/Commands/DatabaseSeedCommand.php: -------------------------------------------------------------------------------- 1 | confirmToProceed()) { 41 | return; 42 | } 43 | 44 | $seed = $this->argument('name') ?: $migrator->defaultSeed(); 45 | 46 | if (!$seed) { 47 | $this->error('Default seed is not defined.'); 48 | 49 | return; 50 | } 51 | 52 | $class = $migrator->seedClass($seed); 53 | 54 | if (!$class) { 55 | $this->error("Seed '$seed' is not defined."); 56 | 57 | return; 58 | } 59 | 60 | $this->infoSeedRun($seed, $class); 61 | 62 | $seeder = new $class(); 63 | 64 | $seeder->setCommand($this)->run(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /sources/Commands/DatabaseStatusCommand.php: -------------------------------------------------------------------------------- 1 | makeLogTable(); 37 | 38 | $this->showMigrations($migrator); 39 | 40 | $this->showSeeds($migrator); 41 | } 42 | 43 | /** 44 | * Show migration infomation. 45 | * 46 | * @param \Jumilla\Versionia\Laravel\Migrator $migrator 47 | */ 48 | protected function showMigrations(Migrator $migrator) 49 | { 50 | $this->line('Migrations'); 51 | 52 | $groups = $migrator->migrationGroups(); 53 | 54 | if (count($groups) > 0) { 55 | // get [$group => $items] 56 | $installed_migrations = $migrator->installedMigrationsByDesc(); 57 | 58 | foreach ($groups as $group) { 59 | // [$items] to [$installed_versions] 60 | $installed_versions = $installed_migrations->get($group, collect())->pluck('version'); 61 | 62 | // [$versions] to $latest_version 63 | $latest_installed_version = $installed_versions->get(0, Migrator::VERSION_NULL); 64 | 65 | // enum definition 66 | foreach ($migrator->migrationVersionsByDesc($group) as $version => $class) { 67 | $installed = $installed_versions->contains($version); 68 | 69 | if ($version === $latest_installed_version) { 70 | $mark = '*'; 71 | } else { 72 | $mark = $installed ? '-' : ' '; 73 | } 74 | 75 | if (!class_exists($class)) { 76 | $this->line("{$mark} [{$group}/{$version}] {$class}"); 77 | $this->line(''); 78 | $this->error('Error: Class not found.'); 79 | continue; 80 | } 81 | 82 | $migration = new $class(); 83 | 84 | if (!$migration instanceof Migration) { 85 | $this->line("{$mark} [{$group}/{$version}] {$class}"); 86 | $this->line(''); 87 | $this->error('Error: Must inherit from class "Illuminate\Database\Migrations\Migration".'); 88 | continue; 89 | } 90 | 91 | $this->line("{$mark} [{$group}/{$version}] {$class}"); 92 | } 93 | 94 | $this->line(''); 95 | } 96 | } else { 97 | $this->info('Nothing.'); 98 | $this->line(''); 99 | } 100 | } 101 | 102 | /** 103 | * Show seed infomation. 104 | * 105 | * @param \Jumilla\Versionia\Laravel\Migrator $migrator 106 | */ 107 | protected function showSeeds(Migrator $migrator) 108 | { 109 | $this->line('Seeds'); 110 | 111 | $seeds = $migrator->seedNames(); 112 | 113 | if (count($seeds) > 0) { 114 | $default_seed = $migrator->defaultSeed(); 115 | 116 | foreach ($seeds as $seed) { 117 | $class = $migrator->seedClass($seed); 118 | 119 | $status_mark = ' '; 120 | $default_mark = $seed == $default_seed ? '(default)' : ''; 121 | 122 | if (!class_exists($class)) { 123 | $this->line("{$status_mark} [{$seed}] {$class}"); 124 | $this->line(''); 125 | $this->error('Error: Class not found.'); 126 | continue; 127 | } 128 | 129 | $this->line("{$status_mark} {$default_mark}[{$seed}] {$class}"); 130 | } 131 | 132 | if ($default_seed && !in_array($default_seed, $seeds)) { 133 | $this->line(''); 134 | $this->error("Error: default seed '{$default_seed}' is not defined."); 135 | } 136 | } else { 137 | $this->info('Nothing.'); 138 | } 139 | 140 | $this->line(''); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /sources/Commands/DatabaseUpgradeCommand.php: -------------------------------------------------------------------------------- 1 | confirmToProceed()) { 41 | return; 42 | } 43 | 44 | $migrator->makeLogTable(); 45 | 46 | $this->migrateToLatest($migrator); 47 | 48 | $seed = $this->option('seed'); 49 | 50 | if ($seed) { 51 | $this->call('database:seed', ['name' => $seed, '--force' => true]); 52 | } 53 | } 54 | 55 | /** 56 | * Migrate dataase to latest version. 57 | * 58 | * @param \Jumilla\Versionia\Laravel\Migrator $migrator 59 | */ 60 | protected function migrateToLatest(Migrator $migrator) 61 | { 62 | $installed_migrations = $migrator->installedLatestMigrations(); 63 | 64 | $migration_count = 0; 65 | 66 | foreach ($migrator->migrationGroups() as $group) { 67 | // [$group => ['version'=>$version, 'class'=>$class]] to $version 68 | $latest_installed_version = data_get($installed_migrations, $group.'.version', Migrator::VERSION_NULL); 69 | 70 | foreach ($migrator->migrationVersions($group) as $version => $class) { 71 | if ($migrator->compareMigrationVersion($version, $latest_installed_version) > 0) { 72 | $this->line("Up [$group/$version] Run class $class"); 73 | 74 | $migrator->doUpgrade($group, $version, $class); 75 | 76 | ++$migration_count; 77 | } 78 | } 79 | } 80 | 81 | if ($migration_count == 0) { 82 | $this->line('Nothing to migrate.'); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /sources/Commands/MigrationMakeCommand.php: -------------------------------------------------------------------------------- 1 | setStubDirectory(__DIR__.'/../../stubs'); 43 | } 44 | 45 | /** 46 | * Get the default namespace for the class. 47 | * 48 | * @return string 49 | */ 50 | protected function getDefaultNamespace() 51 | { 52 | return $this->getRootNamespace().'\\Database\\Migrations'; 53 | } 54 | 55 | /** 56 | * Get the stub file for the generator. 57 | * 58 | * @return string 59 | */ 60 | protected function getStub() 61 | { 62 | if ($this->option('create')) { 63 | return 'migration-create.stub'; 64 | } elseif ($this->option('update')) { 65 | return 'migration-update.stub'; 66 | } else { 67 | return 'migration.stub'; 68 | } 69 | } 70 | 71 | /** 72 | * Generate file. 73 | * 74 | * @param FileGenerator $generator 75 | * @param string $path 76 | * @param string $fqcn 77 | * 78 | * @return bool 79 | */ 80 | protected function generateFile(FileGenerator $generator, $path, $fqcn) 81 | { 82 | list($namespace, $class) = $this->splitFullQualifyClassName($fqcn); 83 | 84 | return $generator->file($path)->template($this->getStub(), [ 85 | 'namespace' => $namespace, 86 | 'class' => $class, 87 | 'table' => $this->option('create') ?: $this->option('update'), 88 | ]); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /sources/Commands/SeederMakeCommand.php: -------------------------------------------------------------------------------- 1 | setStubDirectory(__DIR__.'/../../stubs'); 41 | } 42 | 43 | /** 44 | * Get the default namespace for the class. 45 | * 46 | * @return string 47 | */ 48 | protected function getDefaultNamespace() 49 | { 50 | return $this->getRootNamespace().'\\Database\\Seeds'; 51 | } 52 | 53 | /** 54 | * Get the stub file for the generator. 55 | * 56 | * @return string 57 | */ 58 | protected function getStub() 59 | { 60 | return 'seeder.stub'; 61 | } 62 | 63 | /** 64 | * Generate file. 65 | * 66 | * @param FileGenerator $generator 67 | * @param string $path 68 | * @param string $fqcn 69 | * 70 | * @return bool 71 | */ 72 | protected function generateFile(FileGenerator $generator, $path, $fqcn) 73 | { 74 | list($namespace, $class) = $this->splitFullQualifyClassName($fqcn); 75 | 76 | return $generator->file($path)->template($this->getStub(), [ 77 | 'namespace' => $namespace, 78 | 'class' => $class, 79 | ]); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /sources/Migrator.php: -------------------------------------------------------------------------------- 1 | db = $db; 46 | if ($config) { 47 | $this->table = $config->get('database.migrations', $this->table); 48 | } 49 | } 50 | 51 | /** 52 | * @return string 53 | */ 54 | public function getTable() 55 | { 56 | return $this->table; 57 | } 58 | 59 | /** 60 | * @param string $a 61 | * @param string $b 62 | * 63 | * @return int 64 | */ 65 | public function compareMigrationVersion($a, $b) 66 | { 67 | return version_compare($a, $b); 68 | } 69 | 70 | /** 71 | * @param string $group 72 | * @param string $version 73 | * @param string $class 74 | */ 75 | public function registerMigration($group, $version, $class) 76 | { 77 | $this->registerMigrations($group, [ 78 | $version => $class, 79 | ]); 80 | } 81 | 82 | /** 83 | * @param string $group 84 | * @param array $versions 85 | */ 86 | public function registerMigrations($group, array $versions) 87 | { 88 | foreach ($versions as $version => $class) { 89 | $this->migrations[$group][$version] = $class; 90 | } 91 | } 92 | 93 | /** 94 | * @return array 95 | */ 96 | public function migrationGroups() 97 | { 98 | $groups = array_keys($this->migrations); 99 | 100 | sort($groups); 101 | 102 | return $groups; 103 | } 104 | 105 | /** 106 | * @param string $group 107 | * @param bool $descending 108 | * 109 | * @return array 110 | */ 111 | public function migrationVersions($group, $descending = false) 112 | { 113 | $versions = array_get($this->migrations, $group, []); 114 | 115 | uksort($versions, [$this, 'compareMigrationVersion']); 116 | 117 | return $descending ? array_reverse($versions, true) : $versions; 118 | } 119 | 120 | /** 121 | * @param string $group 122 | * 123 | * @return array 124 | */ 125 | public function migrationVersionsByDesc($group) 126 | { 127 | return $this->migrationVersions($group, true); 128 | } 129 | 130 | /** 131 | * @param string $group 132 | * 133 | * @return string 134 | */ 135 | public function migrationLatestVersion($group) 136 | { 137 | foreach ($this->migrationVersionsByDesc($group) as $version => $class) { 138 | return $version; 139 | } 140 | 141 | return self::VERSION_NULL; 142 | } 143 | 144 | /** 145 | * @param string $group 146 | * @param string $version 147 | * 148 | * @return string 149 | */ 150 | public function migrationClass($group, $version) 151 | { 152 | $versions = array_get($this->migrations, $group, []); 153 | 154 | return array_get($versions, $version, null); 155 | } 156 | 157 | /** 158 | * @param string $name 159 | * @param string $class 160 | */ 161 | public function registerSeed($name, $class) 162 | { 163 | $this->registerSeeds([ 164 | $name => $class, 165 | ]); 166 | } 167 | 168 | /** 169 | * @param array $seeds 170 | */ 171 | public function registerSeeds(array $seeds) 172 | { 173 | $this->seeds = array_merge($this->seeds, $seeds); 174 | } 175 | 176 | /** 177 | * @return string 178 | */ 179 | public function defaultSeed() 180 | { 181 | return $this->default_seed; 182 | } 183 | 184 | /** 185 | * @param string $seed 186 | */ 187 | public function setDefaultSeed($seed) 188 | { 189 | $this->default_seed = $seed; 190 | } 191 | 192 | /** 193 | * @return array 194 | */ 195 | public function seedNames() 196 | { 197 | return array_keys($this->seeds); 198 | } 199 | 200 | /** 201 | * @param string $name 202 | * 203 | * @return string 204 | */ 205 | public function seedClass($name) 206 | { 207 | return array_get($this->seeds, $name); 208 | } 209 | 210 | /** 211 | */ 212 | public function makeLogTable() 213 | { 214 | if (!Schema::hasTable($this->table)) { 215 | Schema::create($this->table, function (Blueprint $table) { 216 | $table->string('group'); 217 | $table->string('version'); 218 | $table->string('class'); 219 | 220 | $table->unique(['group', 'version']); 221 | }); 222 | } 223 | } 224 | 225 | /** 226 | * @param bool $descending 227 | * 228 | * @return \Illuminate\Support\Collection 229 | */ 230 | public function installedMigrations($descending = false) 231 | { 232 | return collect($this->db->table($this->table)->get())->sort(function ($a, $b) use ($descending) { 233 | return $this->compareMigrationVersion($a->version, $b->version) * ($descending ? -1 : 1); 234 | })->groupBy('group'); 235 | } 236 | /** 237 | * @return \Illuminate\Support\Collection 238 | */ 239 | public function installedMigrationsByDesc() 240 | { 241 | return $this->installedMigrations(true); 242 | } 243 | 244 | /** 245 | * @return \Illuminate\Support\Collection 246 | */ 247 | public function installedLatestMigrations() 248 | { 249 | return collect($this->db->table($this->table)->get())->reduce(function ($result, $item) { 250 | if (isset($result[$item->group])) { 251 | if ($this->compareMigrationVersion($item->version, $result[$item->group]->version) > 0) { 252 | $result[$item->group] = $item; 253 | } 254 | } else { 255 | $result[$item->group] = $item; 256 | } 257 | 258 | return $result; 259 | }, collect()); 260 | } 261 | 262 | /** 263 | * @param string $group 264 | * @param string $version 265 | * @param string $class 266 | */ 267 | public function addMigrationLog($group, $version, $class) 268 | { 269 | $this->db->table($this->table)->insert([ 270 | 'group' => $group, 271 | 'version' => $version, 272 | 'class' => $class, 273 | ]); 274 | } 275 | 276 | /** 277 | * @param string $group 278 | * @param string $version 279 | */ 280 | public function removeMigrationLog($group, $version) 281 | { 282 | $this->db->table($this->table)->where('group', $group)->where('version', $version)->delete(); 283 | } 284 | 285 | /** 286 | * @param string $group 287 | * @param string $version 288 | * @param string $class 289 | */ 290 | public function doUpgrade($group, $version, $class) 291 | { 292 | $migration = new $class(); 293 | 294 | $migration->up(); 295 | 296 | $this->addMigrationLog($group, $version, $class); 297 | } 298 | 299 | /** 300 | * @param string $group 301 | * @param string $version 302 | * @param string $class 303 | */ 304 | public function doDowngrade($group, $version, $class = null) 305 | { 306 | if ($class === null) { 307 | $class = $this->migrationClass($group, $version); 308 | } 309 | 310 | $migration = new $class(); 311 | 312 | $migration->down(); 313 | 314 | $this->removeMigrationLog($group, $version); 315 | } 316 | } 317 | -------------------------------------------------------------------------------- /sources/ServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->singleton('database.migrator', function ($app) { 15 | return new Migrator($app['db'], $app['config']); 16 | }); 17 | $this->app->alias('database.migrator', Migrator::class); 18 | 19 | $this->registerCommands(); 20 | } 21 | 22 | /** 23 | * Register the cache related console commands. 24 | */ 25 | public function registerCommands() 26 | { 27 | $this->app->singleton('command.database.status', function ($app) { 28 | return new Commands\DatabaseStatusCommand(); 29 | }); 30 | 31 | $this->app->singleton('command.database.upgrade', function ($app) { 32 | return new Commands\DatabaseUpgradeCommand(); 33 | }); 34 | 35 | $this->app->singleton('command.database.clean', function ($app) { 36 | return new Commands\DatabaseCleanCommand(); 37 | }); 38 | 39 | $this->app->singleton('command.database.refresh', function ($app) { 40 | return new Commands\DatabaseRefreshCommand(); 41 | }); 42 | 43 | $this->app->singleton('command.database.rollback', function ($app) { 44 | return new Commands\DatabaseRollbackCommand(); 45 | }); 46 | 47 | $this->app->singleton('command.database.again', function ($app) { 48 | return new Commands\DatabaseAgainCommand(); 49 | }); 50 | 51 | $this->app->singleton('command.database.seed', function ($app) { 52 | return new Commands\DatabaseSeedCommand(); 53 | }); 54 | 55 | $this->app->singleton('command.migration.make', function ($app) { 56 | return new Commands\MigrationMakeCommand(); 57 | }); 58 | 59 | $this->app->singleton('command.seeder.make', function ($app) { 60 | return new Commands\SeederMakeCommand(); 61 | }); 62 | 63 | $this->commands([ 64 | 'command.database.status', 65 | 'command.database.upgrade', 66 | 'command.database.clean', 67 | 'command.database.refresh', 68 | 'command.database.rollback', 69 | 'command.database.again', 70 | 'command.database.seed', 71 | 'command.migration.make', 72 | 'command.seeder.make', 73 | ]); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /sources/Support/DatabaseServiceProvider.php: -------------------------------------------------------------------------------- 1 | app['database.migrator']->registerMigration($group, $version, $class); 25 | } 26 | 27 | /** 28 | * @param string $group 29 | * @param array $versions 30 | */ 31 | protected function migrations($group, array $versions) 32 | { 33 | $this->app['database.migrator']->registerMigrations($group, $versions); 34 | } 35 | 36 | /** 37 | * @param string $name 38 | * @param string $class 39 | * @param bool $is_default 40 | */ 41 | protected function seed($name, $class, $is_default = false) 42 | { 43 | $this->app['database.migrator']->registerSeed($name, $class); 44 | 45 | if ($is_default) { 46 | $this->app['database.migrator']->setDefaultSeed($name); 47 | } 48 | } 49 | 50 | /** 51 | * @param array $seeds 52 | * @param bool|string $default 53 | */ 54 | protected function seeds(array $seeds, $default = null) 55 | { 56 | $this->app['database.migrator']->registerSeeds($seeds); 57 | 58 | if ($default === true) { 59 | $default = array_keys($seeds)[0]; 60 | } 61 | 62 | $this->app['database.migrator']->setDefaultSeed($default); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /sources/Support/Migration.php: -------------------------------------------------------------------------------- 1 | increments('id'); 20 | $table->timestamps(); 21 | }); 22 | } 23 | 24 | /** 25 | * Reverse the migrations. 26 | * 27 | * @return void 28 | */ 29 | public function down() 30 | { 31 | Schema::dropIfExists('{$table}'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /stubs/migration-update.stub: -------------------------------------------------------------------------------- 1 |