├── sources
├── Support
│ ├── Seeder.php
│ ├── Migration.php
│ └── DatabaseServiceProvider.php
├── Commands
│ ├── DatabaseCommandTrait.php
│ ├── DatabaseCleanCommand.php
│ ├── DatabaseSeedCommand.php
│ ├── SeederMakeCommand.php
│ ├── MigrationMakeCommand.php
│ ├── DatabaseRefreshCommand.php
│ ├── DatabaseUpgradeCommand.php
│ ├── DatabaseRollbackCommand.php
│ ├── DatabaseAgainCommand.php
│ └── DatabaseStatusCommand.php
├── ServiceProvider.php
└── Migrator.php
├── stubs
├── seeder.stub
├── migration.stub
├── migration-update.stub
└── migration-create.stub
├── LICENSE
├── composer.json
├── readme-ja.md
└── readme.md
/sources/Support/Seeder.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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/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/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/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/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/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/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/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/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/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 |
--------------------------------------------------------------------------------
/readme-ja.md:
--------------------------------------------------------------------------------
1 | # LARAVEL VERSIONIA
2 |
3 | [](https://travis-ci.org/jumilla/laravel-versionia)
4 | [](https://scrutinizer-ci.com/g/jumilla/laravel-versionia)
5 | [](https://scrutinizer-ci.com/g/jumilla/laravel-versionia/)
6 | [](https://packagist.org/packages/jumilla/laravel-versionia)
7 | [](https://packagist.org/packages/jumilla/laravel-versionia)
8 | [](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 | [](https://travis-ci.org/jumilla/laravel-versionia)
4 | [](https://scrutinizer-ci.com/g/jumilla/laravel-versionia)
5 | [](https://scrutinizer-ci.com/g/jumilla/laravel-versionia/)
6 | [](https://packagist.org/packages/jumilla/laravel-versionia)
7 | [](https://packagist.org/packages/jumilla/laravel-versionia)
8 | [](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 |
--------------------------------------------------------------------------------