Skip to content

Commit 1b5b638

Browse files
committed
Initial commit
1 parent 30974af commit 1b5b638

File tree

9 files changed

+603
-0
lines changed

9 files changed

+603
-0
lines changed

composer.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "adrienpoupa/migrate-routines",
3+
"description": "Generate Laravel Migrations from existing MySQL routines: views, procedures, functions and triggers.",
4+
"keywords": ["laravel", "migration", "generator", "migrations", "artisan", "procedure"],
5+
"license": "MIT",
6+
"authors": [
7+
{
8+
"name": "Adrien Poupa",
9+
"email": "[email protected]"
10+
}
11+
],
12+
"require": {
13+
"php": ">=7.0",
14+
"illuminate/support": "^5.5|^6"
15+
},
16+
"autoload": {
17+
"psr-4": {
18+
"AdrienPoupa\\MigrateRoutines\\": "src/"
19+
}
20+
},
21+
"minimum-stability": "dev",
22+
"prefer-stable": true,
23+
"extra": {
24+
"laravel": {
25+
"providers": [
26+
"AdrienPoupa\\MigrateRoutines\\MigrateRoutinesServiceProvider"
27+
]
28+
}
29+
}
30+
}

readme.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
## Migrate Routines for Laravel
2+
3+
[![Latest Stable Version](https://poser.pugx.org/adrienpoupa/migrate-routines/version.png)](https://packagist.org/packages/adrienpoupa/migrate-routines)
4+
[![Total Downloads](https://poser.pugx.org/adrienpoupa/migrate-routines/d/total.png)](https://packagist.org/packages/adrienpoupa/migrate-routines)
5+
6+
Generate Laravel Migrations from existing MySQL routines: views, procedures, functions and triggers
7+
8+
### Installation
9+
10+
11+
Require this package with composer. It is recommended to only require the package for development.
12+
13+
```shell
14+
composer require adrienpoupa/migrate-routines --dev
15+
```
16+
17+
### Usage
18+
19+
Convert the existing views into migrations
20+
21+
```shell
22+
php artisan migrate:views
23+
```
24+
25+
Convert the existing procedures into migrations
26+
27+
```shell
28+
php artisan migrate:procedures
29+
```
30+
31+
Convert the existing functions into migrations
32+
33+
```shell
34+
php artisan migrate:functions
35+
```
36+
37+
Convert the existing triggers into migrations
38+
39+
```shell
40+
php artisan migrate:triggers
41+
```
42+
43+
For all the commands, is possible to specify the database from which to retrieve the routines with the `--database` option, like this:
44+
45+
```shell
46+
php artisan migrate:views --database=database_name
47+
```
48+
49+
For this package to work, your database connection should be done with a user privileged enough to run elevated queries
50+
from the information_schema and the mysql.proc tables.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php
2+
3+
namespace AdrienPoupa\MigrateRoutines\Console;
4+
5+
use Illuminate\Support\Facades\DB;
6+
use stdClass;
7+
8+
/**
9+
* Class MigrateFunctionsCommand
10+
* @package AdrienPoupa\MigrateRoutines\Console
11+
*/
12+
class MigrateFunctionsCommand extends MigrateRoutines
13+
{
14+
/**
15+
* The name and signature of the console command.
16+
*
17+
* @var string
18+
*/
19+
protected $signature = 'migrate:functions {--database=default}';
20+
21+
/**
22+
* The console command description.
23+
*
24+
* @var string
25+
*/
26+
protected $description = 'Convert the existing functions into migrations';
27+
28+
/**
29+
* Create a new command instance.
30+
*
31+
* @return void
32+
*/
33+
public function __construct()
34+
{
35+
parent::__construct();
36+
37+
$this->migrationType = 'procedure';
38+
}
39+
40+
/**
41+
* @return array
42+
*/
43+
public function getData()
44+
{
45+
return DB::select("SELECT name, param_list, body, returns FROM mysql.proc WHERE db='$this->database' and type='FUNCTION' ");
46+
}
47+
48+
/**
49+
* Generate the up function
50+
* We use unprepared to avoid error 2014
51+
* @param stdClass $function
52+
* @return string
53+
*/
54+
public function up(stdClass $function)
55+
{
56+
return 'DB::unprepared("CREATE FUNCTION `'.$function->name.'` (' . $function->param_list . ')
57+
RETURNS ' . $function->returns . '
58+
'.$this->escape($function->body).'");';
59+
}
60+
61+
/**
62+
* Generate the down function
63+
* @param stdClass $function
64+
* @return string
65+
*/
66+
public function down(stdClass $function)
67+
{
68+
return 'DB::unprepared("DROP FUNCTION IF EXISTS `'.$function->name.'`");';
69+
}
70+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
namespace AdrienPoupa\MigrateRoutines\Console;
4+
5+
use Illuminate\Support\Facades\DB;
6+
use stdClass;
7+
8+
/**
9+
* Class MigrateProceduresCommand
10+
* @package AdrienPoupa\MigrateRoutines\Console
11+
*/
12+
class MigrateProceduresCommand extends MigrateRoutines
13+
{
14+
/**
15+
* The name and signature of the console command.
16+
*
17+
* @var string
18+
*/
19+
protected $signature = 'migrate:procedures {--database=default}';
20+
21+
/**
22+
* The console command description.
23+
*
24+
* @var string
25+
*/
26+
protected $description = 'Convert the existing procedures into migrations';
27+
28+
/**
29+
* Create a new command instance.
30+
*
31+
* @return void
32+
*/
33+
public function __construct()
34+
{
35+
parent::__construct();
36+
37+
$this->migrationType = 'procedure';
38+
}
39+
40+
/**
41+
* @return array
42+
*/
43+
public function getData()
44+
{
45+
return DB::select("SELECT name, param_list, body FROM mysql.proc WHERE db='$this->database' and type='PROCEDURE' ");
46+
}
47+
48+
/**
49+
* Generate the up function
50+
* We use unprepared to avoid error 2014
51+
* @param stdClass $routine
52+
* @return string
53+
*/
54+
public function up(stdClass $routine)
55+
{
56+
return 'DB::unprepared("CREATE PROCEDURE `'.$routine->name.'` (
57+
'.$this->escape($routine->param_list).'
58+
)
59+
'.$this->escape($routine->body).'");';
60+
}
61+
62+
/**
63+
* Generate the down function
64+
* @param stdClass $routine
65+
* @return string
66+
*/
67+
public function down(stdClass $routine)
68+
{
69+
return 'DB::unprepared("DROP PROCEDURE IF EXISTS `'.$this->escape($routine->name).'`");';
70+
}
71+
}

src/Console/MigrateRoutines.php

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
<?php
2+
3+
namespace AdrienPoupa\MigrateRoutines\Console;
4+
5+
use Illuminate\Database\Console\Migrations\BaseCommand;
6+
use Illuminate\Filesystem\Filesystem;
7+
use Illuminate\Support\Str;
8+
use stdClass;
9+
10+
/**
11+
* Class MigrateRoutines
12+
* @package AdrienPoupa\MigrateRoutines\Console
13+
*/
14+
abstract class MigrateRoutines extends BaseCommand
15+
{
16+
/**
17+
* @var string
18+
*/
19+
protected $database;
20+
21+
/**
22+
* @var string
23+
*/
24+
protected $migrationType;
25+
26+
/**
27+
* @var Filesystem
28+
*/
29+
protected $filesystem;
30+
31+
/**
32+
* @var Str
33+
*/
34+
protected $str;
35+
36+
/**
37+
* Create a new command instance.
38+
*
39+
*/
40+
public function __construct()
41+
{
42+
parent::__construct();
43+
}
44+
45+
/**
46+
* Execute the console command.
47+
*
48+
* @param Filesystem $filesystem
49+
* @param Str $str
50+
* @return void
51+
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
52+
*/
53+
public function handle(Filesystem $filesystem, Str $str)
54+
{
55+
$this->filesystem = $filesystem;
56+
$this->str = $str;
57+
58+
$this->database = $this->option('database');
59+
60+
if ($this->database === 'default') {
61+
$this->database = config('database.connections.mysql.database');
62+
}
63+
64+
$this->convert();
65+
}
66+
67+
/**
68+
* Convert the existing routines
69+
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
70+
*/
71+
private function convert()
72+
{
73+
$routines = $this->getData();
74+
75+
if (!$routines) {
76+
$this->info('Nothing to migrate.');
77+
return;
78+
}
79+
80+
foreach ($routines as $routine) {
81+
$migrationName = $this->str->snake($routine->name);
82+
$up = $this->up($routine);
83+
$down = $this->down($routine);
84+
$this->write($migrationName, $up, $down);
85+
}
86+
}
87+
88+
/**
89+
* @return array
90+
*/
91+
abstract public function getData();
92+
93+
/**
94+
* Generate the up function
95+
* We use unprepared to avoid error 2014
96+
* @param stdClass $routine
97+
* @return string
98+
*/
99+
abstract public function up(stdClass $routine);
100+
101+
/**
102+
* Generate the down function
103+
* @param stdClass $routine
104+
* @return string
105+
*/
106+
abstract public function down(stdClass $routine);
107+
108+
/**
109+
* Write the migration
110+
* @param string $migrationName
111+
* @param string $up
112+
* @param string $down
113+
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
114+
*/
115+
public function write(string $migrationName, string $up, string $down)
116+
{
117+
$filename = date('Y_m_d_His') . '_create_' . $this->migrationType . '_' . $migrationName . '.php';
118+
119+
$path = $this->getMigrationPath() . '/' . $filename;
120+
121+
$content = $this->generateMigrationContent($migrationName, $up, $down);
122+
123+
$this->filesystem->put($path, $content);
124+
125+
$this->line("<info>Created Migration:</info> {$filename}");
126+
}
127+
128+
/**
129+
* Insert the migration information into the stub
130+
* @param string $migrationName
131+
* @param string $up
132+
* @param string $down
133+
* @return string|string[]
134+
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
135+
*/
136+
public function generateMigrationContent(string $migrationName, string $up, string $down)
137+
{
138+
return str_replace(
139+
['DummyClass', 'schema_up', 'schema_down'],
140+
[$this->getClassName($migrationName), $this->indent($up), $this->indent($down)],
141+
$this->filesystem->get(__DIR__ . '/stubs/migration.stub')
142+
);
143+
}
144+
145+
/**
146+
* Get the class name of the new migration file
147+
* @param string $migrationName
148+
* @return string
149+
*/
150+
protected function getClassName(string $migrationName)
151+
{
152+
return 'Create' . ucfirst($this->migrationType) . str_replace('_', '', $this->str->title($migrationName));
153+
}
154+
155+
/**
156+
* Indent the migration
157+
* @param string $text
158+
* @return mixed
159+
*/
160+
protected function indent(string $text)
161+
{
162+
return str_replace("\n", "\n ", $text);
163+
}
164+
165+
/**
166+
* Escape the double quotes
167+
* @param string $text
168+
* @return mixed
169+
*/
170+
protected function escape(string $text)
171+
{
172+
return str_replace('"', '\"', $text);
173+
}
174+
}

0 commit comments

Comments
 (0)