Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
AdrienPoupa committed Dec 15, 2019
1 parent 30974af commit 1b5b638
Show file tree
Hide file tree
Showing 9 changed files with 603 additions and 0 deletions.
30 changes: 30 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "adrienpoupa/migrate-routines",
"description": "Generate Laravel Migrations from existing MySQL routines: views, procedures, functions and triggers.",
"keywords": ["laravel", "migration", "generator", "migrations", "artisan", "procedure"],
"license": "MIT",
"authors": [
{
"name": "Adrien Poupa",
"email": "[email protected]"
}
],
"require": {
"php": ">=7.0",
"illuminate/support": "^5.5|^6"
},
"autoload": {
"psr-4": {
"AdrienPoupa\\MigrateRoutines\\": "src/"
}
},
"minimum-stability": "dev",
"prefer-stable": true,
"extra": {
"laravel": {
"providers": [
"AdrienPoupa\\MigrateRoutines\\MigrateRoutinesServiceProvider"
]
}
}
}
50 changes: 50 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
## Migrate Routines for Laravel

[![Latest Stable Version](https://poser.pugx.org/adrienpoupa/migrate-routines/version.png)](https://packagist.org/packages/adrienpoupa/migrate-routines)
[![Total Downloads](https://poser.pugx.org/adrienpoupa/migrate-routines/d/total.png)](https://packagist.org/packages/adrienpoupa/migrate-routines)

Generate Laravel Migrations from existing MySQL routines: views, procedures, functions and triggers

### Installation


Require this package with composer. It is recommended to only require the package for development.

```shell
composer require adrienpoupa/migrate-routines --dev
```

### Usage

Convert the existing views into migrations

```shell
php artisan migrate:views
```

Convert the existing procedures into migrations

```shell
php artisan migrate:procedures
```

Convert the existing functions into migrations

```shell
php artisan migrate:functions
```

Convert the existing triggers into migrations

```shell
php artisan migrate:triggers
```

For all the commands, is possible to specify the database from which to retrieve the routines with the `--database` option, like this:

```shell
php artisan migrate:views --database=database_name
```

For this package to work, your database connection should be done with a user privileged enough to run elevated queries
from the information_schema and the mysql.proc tables.
70 changes: 70 additions & 0 deletions src/Console/MigrateFunctionsCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php

namespace AdrienPoupa\MigrateRoutines\Console;

use Illuminate\Support\Facades\DB;
use stdClass;

/**
* Class MigrateFunctionsCommand
* @package AdrienPoupa\MigrateRoutines\Console
*/
class MigrateFunctionsCommand extends MigrateRoutines
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'migrate:functions {--database=default}';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Convert the existing functions into migrations';

/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();

$this->migrationType = 'procedure';
}

/**
* @return array
*/
public function getData()
{
return DB::select("SELECT name, param_list, body, returns FROM mysql.proc WHERE db='$this->database' and type='FUNCTION' ");
}

/**
* Generate the up function
* We use unprepared to avoid error 2014
* @param stdClass $function
* @return string
*/
public function up(stdClass $function)
{
return 'DB::unprepared("CREATE FUNCTION `'.$function->name.'` (' . $function->param_list . ')
RETURNS ' . $function->returns . '
'.$this->escape($function->body).'");';
}

/**
* Generate the down function
* @param stdClass $function
* @return string
*/
public function down(stdClass $function)
{
return 'DB::unprepared("DROP FUNCTION IF EXISTS `'.$function->name.'`");';
}
}
71 changes: 71 additions & 0 deletions src/Console/MigrateProceduresCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

namespace AdrienPoupa\MigrateRoutines\Console;

use Illuminate\Support\Facades\DB;
use stdClass;

/**
* Class MigrateProceduresCommand
* @package AdrienPoupa\MigrateRoutines\Console
*/
class MigrateProceduresCommand extends MigrateRoutines
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'migrate:procedures {--database=default}';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Convert the existing procedures into migrations';

/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();

$this->migrationType = 'procedure';
}

/**
* @return array
*/
public function getData()
{
return DB::select("SELECT name, param_list, body FROM mysql.proc WHERE db='$this->database' and type='PROCEDURE' ");
}

/**
* Generate the up function
* We use unprepared to avoid error 2014
* @param stdClass $routine
* @return string
*/
public function up(stdClass $routine)
{
return 'DB::unprepared("CREATE PROCEDURE `'.$routine->name.'` (
'.$this->escape($routine->param_list).'
)
'.$this->escape($routine->body).'");';
}

/**
* Generate the down function
* @param stdClass $routine
* @return string
*/
public function down(stdClass $routine)
{
return 'DB::unprepared("DROP PROCEDURE IF EXISTS `'.$this->escape($routine->name).'`");';
}
}
174 changes: 174 additions & 0 deletions src/Console/MigrateRoutines.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
<?php

namespace AdrienPoupa\MigrateRoutines\Console;

use Illuminate\Database\Console\Migrations\BaseCommand;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Str;
use stdClass;

/**
* Class MigrateRoutines
* @package AdrienPoupa\MigrateRoutines\Console
*/
abstract class MigrateRoutines extends BaseCommand
{
/**
* @var string
*/
protected $database;

/**
* @var string
*/
protected $migrationType;

/**
* @var Filesystem
*/
protected $filesystem;

/**
* @var Str
*/
protected $str;

/**
* Create a new command instance.
*
*/
public function __construct()
{
parent::__construct();
}

/**
* Execute the console command.
*
* @param Filesystem $filesystem
* @param Str $str
* @return void
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
public function handle(Filesystem $filesystem, Str $str)
{
$this->filesystem = $filesystem;
$this->str = $str;

$this->database = $this->option('database');

if ($this->database === 'default') {
$this->database = config('database.connections.mysql.database');
}

$this->convert();
}

/**
* Convert the existing routines
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
private function convert()
{
$routines = $this->getData();

if (!$routines) {
$this->info('Nothing to migrate.');
return;
}

foreach ($routines as $routine) {
$migrationName = $this->str->snake($routine->name);
$up = $this->up($routine);
$down = $this->down($routine);
$this->write($migrationName, $up, $down);
}
}

/**
* @return array
*/
abstract public function getData();

/**
* Generate the up function
* We use unprepared to avoid error 2014
* @param stdClass $routine
* @return string
*/
abstract public function up(stdClass $routine);

/**
* Generate the down function
* @param stdClass $routine
* @return string
*/
abstract public function down(stdClass $routine);

/**
* Write the migration
* @param string $migrationName
* @param string $up
* @param string $down
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
public function write(string $migrationName, string $up, string $down)
{
$filename = date('Y_m_d_His') . '_create_' . $this->migrationType . '_' . $migrationName . '.php';

$path = $this->getMigrationPath() . '/' . $filename;

$content = $this->generateMigrationContent($migrationName, $up, $down);

$this->filesystem->put($path, $content);

$this->line("<info>Created Migration:</info> {$filename}");
}

/**
* Insert the migration information into the stub
* @param string $migrationName
* @param string $up
* @param string $down
* @return string|string[]
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
public function generateMigrationContent(string $migrationName, string $up, string $down)
{
return str_replace(
['DummyClass', 'schema_up', 'schema_down'],
[$this->getClassName($migrationName), $this->indent($up), $this->indent($down)],
$this->filesystem->get(__DIR__ . '/stubs/migration.stub')
);
}

/**
* Get the class name of the new migration file
* @param string $migrationName
* @return string
*/
protected function getClassName(string $migrationName)
{
return 'Create' . ucfirst($this->migrationType) . str_replace('_', '', $this->str->title($migrationName));
}

/**
* Indent the migration
* @param string $text
* @return mixed
*/
protected function indent(string $text)
{
return str_replace("\n", "\n ", $text);
}

/**
* Escape the double quotes
* @param string $text
* @return mixed
*/
protected function escape(string $text)
{
return str_replace('"', '\"', $text);
}
}
Loading

0 comments on commit 1b5b638

Please sign in to comment.