I've created a base class for my migrations. At the moment I run the artisan migrate command and it creates a new migration that extends the Migrations file, however I want to include my BaseMigration and extend it from there. I've been making this changes manualy but I feel like I'm repeating myself unnecessarily.
Any advice on how to have new migrations automatically extend and load my base migration?
I don't think you can, because Laravel takes migrations from the vendor/laravel/framework/src/Illuminate/Database/Migrations/stubs
folder and you cannot change that, but you have some options:
1) Create your own artisan command migrate:makemyown
.
2) Use Jeffrey Way's Laravel Generators. They let you create your migrations by doing:
php artisan generate:migration create_posts_table --fields="title:string, description:text"
If you just have some fields you need to start with and not something more specific than that, it works really fine.
3) Edit Laravel stubs, but the problem is that as soon as you composer update
they might get overwritten by Composer.
It's doable in a fairly logical way, at least in Laravel 5
Subclass MigrationCreator
and override getStubPath()
, just copying the function over from the original class (it will use your subclass's __DIR__
)
<?php
namespace App\Database;
use Illuminate\Database\Migrations\MigrationCreator;
class AppMigrationCreator extends MigrationCreator
{
public function getStubPath()
{
return __DIR__.'/stubs';
}
}
Write a service provider to override migration.creator
with your own subclass (it must be a deferred service provider, because you cannot override a deferred binding with an eager one):
<?php
namespace App\Database;
use Illuminate\Support\ServiceProvider;
class AppMigrationServiceProvider extends ServiceProvider
{
protected $defer = true;
public function register()
{
$this->app->singleton('migration.creator', function ($app) {
return new AppMigrationCreator($app['files']);
});
}
public function provides()
{
return ['migration.creator'];
}
}
Add your service provider to config/app.php
after the default ones.
Finally, copy vendor/laravel/framework/src/Illuminate/Database/Migrations/stubs
alongside your MigrationCreator subclass (in this example it would become app/Database/stubs
) and edit the templates to your needs.
Keep the DummyClass
and DummyTable
names, as they are replaced with str_replace()
to create the actual migrations files.
I believe that there is no way to override this (for now) but I think that you can create your custom command which will use Laravel logic. This was created for Laravel 5.
First you have to create Generator command app/Console/Commands/Generator.php
:
<?php namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Filesystem\Filesystem;
use Symfony\Component\Console\Input\InputArgument;
class Generator extends Command
{
/**
* Command name
*
* @var string
*/
protected $name = 'generate';
/**
* Command description
*
* @var string
*/
protected $description = 'Custom object generator';
/**
* An array with all available generator classes
*
* @var array
*/
protected $types = ['request', 'model', 'middleware'];
/**
* Execute command
*
* @return mixed
*/
public function handle()
{
$type = $this->argument('type');
if (!in_array($type, $this->types)) {
return $this->error('Type must be one of: '.implode(', ', $this->types));
}
// Create new instance
$generatorClass = 'App\Console\Commands\Generators\\'.ucfirst($type);
$generator = new $generatorClass(new Filesystem());
// Each generator has "fire" method
$this->comment($generator->setClassName($this->argument('name'))->fire());
}
/**
* @return array
*/
public function getArguments()
{
return [
['type', InputArgument::REQUIRED, 'Type of class to generate: '.implode(', ', $this->types)],
['name', InputArgument::REQUIRED, 'Name of class to generate'],
];
}
}
Then you have to create an abstract class for all of your Generators classes app/Console/Commands/Generators/Generator.php
:
<?php namespace App\Console\Commands\Generators;
use Illuminate\Console\GeneratorCommand;
abstract class Generator extends GeneratorCommand
{
// Directory name with whole application (by default app)
const APP_PATH = 'app';
/*
* Name and description of command wont be used
* Generators Commands are not loaded via Kernel
* Name and description property has been put just to avoid Exception thrown by Symfony Command class
*/
protected $name = 'fake';
protected $description = 'fake';
/**
* Class name to generate
*
* @var string
*/
protected $className;
/**
* Returns class name to generate
*
* @return string
*/
protected function getNameInput()
{
return $this->className;
}
/**
* Returns path under which class should be generated
*
* @param string $name
* @return string
*/
protected function getPath($name)
{
$name = str_replace($this->getAppNamespace(), '', $name);
return self::APP_PATH.'/'.str_replace('\\', '/', $name).'.php';
}
/**
* Sets class name to generate
*
* @param string $name
* @return $this
*/
public function setClassName($name)
{
$this->className = $name;
return $this;
}
/**
* Execute command
*
* @return string
*/
public function fire()
{
$name = $this->parseName($this->getNameInput());
if ($this->files->exists($path = $this->getPath($name)))
{
return $this->type.' already exists!';
}
$this->makeDirectory($path);
$this->files->put($path, $this->buildClass($name));
return $this->type.' '.$this->className.' created successfully.';
}
}
At the end you can create your first Generator class! app/Console/Commands/Generators/Request.php
<?php namespace App\Console\Commands\Generators;
class Request extends Generator
{
/**
* Class type to generate
*
* @var string
*/
protected $type = 'Request';
/**
* Returns default namespace for objects being generated
*
* @param string $rootNamespace
* @return string
*/
protected function getDefaultNamespace($rootNamespace)
{
return $rootNamespace.'\Http\Requests';
}
/**
* Returns path to custom stub
*
* @return string
*/
public function getStub()
{
return base_path('resources').'/stubs/request.stub';
}
}
Dont forget to add your generate command to Kernel app/Console/Kernel.php
:
<?php namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel {
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
...
'App\Console\Commands\Generator',
...
];
Put your stubs under resources/stubs
directory. Let's create first one for Request Generator resources/stubs/request.stub
:
<?php namespace {{namespace}};
class {{class}} extends Request
{
/**
* @return bool
*/
public function authorize()
{
// CUSTOM LOGIC
return false;
}
/**
* @return array
*/
public function rules()
{
$rules = [];
// CUSTOM LOGIC
return $rules;
}
}
Then call with php artisan generate request MyRequest
.
You can create your custom Model, Middleware, Controller etc. generators, it's very simple - you have to create new generator class under app/Commands/Console/Generators
- take a look at Request.php
generator to see how it works!
For Laravel 5 you'd edit one of the .stub
files in:
vendor/laravel/framework/src/Illuminate/Database/Migrations/stubs
There's no reason why you can't edit those files.
Search in vendor/laravel/framework/src/
for .stub
files to find all of the other stubs (templates) artisan uses.