This is the continuation of my where we talked about creating a multi-tenant app using Laravel and Postgres. I recommend you to read that article before moving forward with this one. previous article Since our multi-tenant app is ready, we want to utilize Laravel’s console commands to handle our migrations. In this article, we will see how we can extend Laravel’s migration implementation to gracefully handle migrations for all schemas of our multi-tenant . app Overview provides easy console commands within namespace to handle migrations. eg: Laravel migrate $ php artisan migrate$ php artisan migrate:rollback... But, as you might have noticed, these commands will only run migrations in default schema, which in our case needs to be run for all schemas. We will extend commands provided by Laravel to add 2 new options: --all --schema=[SCHEMA] So, we will be able to: # Run migrations in all available schemas.$ php artisan migrate --all # Run migrations in given schemas.$ php artisan migrate --schema=th,vn,ph # Rollback migrations in all available schemas.$ php artisan migrate:rollback --all # Rollback migrations in given schemas.$ php artisan migrate:rollback --schema=th,vn,ph I am using Laravel 5.5 and PostgreSQL 9.5 for my setup. Laravel Console Commands Console commands implementation in Laravel is basically an implementation of a . Every command has its own method which is fired whenever a command is dispatched. command design pattern handle The command pattern is a behavioral design pattern in which an object is used to represent and encapsulate all the information needed to call a method at a later time. This information includes the method name, the object that owns the method and values for the method parameters. — Wikipedia Database commands in Laravel can be found in namespace. We just need to override them with our own implementations. Illuminate\Database\Console\Migrations Adding New Options Create a folder called inside . We will place all of our migration commands inside this folder. Create a file called . Migration app/Console MigrateCommand.php This class extends which is basically the class that implements command ( ). Notice that in the constructor we are extending its signature by appending our options and . Then we call the parent constructor with required parameter. Illuminate\Database\Console\Migrations\MigrateCommand migrate php artisan migrate --all --schema We now need to register it as Laravel’s default command. For this, create a service provider called inside directory and register it inside . migrate VentureMigrationServiceProvider app/Http/Providers config/app.php Note that this service provider extends Laravel’s migration service provider instead of the default . Illuminate\Database\MigrationServiceProvider Illuminate\Support\ServiceProvider extends the singleton object available in alias and returns our own . alias points to object. So overriding will override Laravel’s default as well. registerMigrateCommand command.migrate MigrateCommand command.migrate Illuminate\Database\Console\Migrations\MigrateCommand command.migrate MigrateCommand Run . You can see the two new options we added earlier. php artisan migrate --help The handle Method The method inside gets executed whenever we run . Let’s make it respond to our newly added options. handle MigrateCommand php artisan migrate The method is straight forward. If option is passed, we run migrations for all ventures available. If option is passed, we run it for given schemas otherwise we will just call default parent handler. The method exists in which I will explain shortly. handle --all --schema runFor MigrationTrait The Migration Trait Since we will use some common methods quite often when we override commands like and , we will extract some of the common methods inside a trait. Let’s name it . migrate:rollback migrate:status MigrationTrait Note that you can create an AbstractClass for this as well. How you want to implement this is up to you. I will go with trait in this tutorial. method switches schema based on the parameter passed. First line inside this method overrides global config and the next line will purge current database connection. Disconnecting the database is necessary as Laravel caches the connection and use it all over again. So changing the global config only will not work in this case. Reconnection is made by Laravel itself so we don’t need to reconnect the database in our method. During reconnection Laravel will use schema based on the config which is currently the schema we passed. connectUsingSchema , as the name suggests, will return all valid schemas from the argument passed. Remember we will pass schema from command line in format. We first need to explode the arguments with comma and return valid schemas from the list of our ventures. getValidSchemas --schema=th,vn,sg method loops through all ventures that we pass in the argument and runs the command (migrate, rollback, etc.). First line of the method saves default schema which is used to reset the schema at the end of the method. We then loop through the ventures, switch schema, and run parent handler for current schema. runFor Testing Migrate Command At this stage, our is ready to handle migrations for all ventures. Let’s run some migrations using option. MigrateCommand --all Note that running will only run the migrations that are in your default schema which can be defined in as mentioned in the . php artisan migrate .env previous article Now, try running migration for specific schemas with . This will run migrations for , and ventures. php artisan migrate --schema=th,sg,vn Thailand Singapore Vietnam The main advantage of extending migration this way is that we can still chain all other options provided by commands in Laravel migrate namespace. For instance, you can run . Cool, huh! php artisan migrate --all --seed Rollback Command Now let’s extend command. Create a file called inside . This class will extend , which is Laravel’s implementation of command. migrate:rollback RollbackCommand.php app/Console Illuminate\Database\Console\Migrations\RollbackCommand migrate:rollback method is same as we discussed earlier. handle Unlike class, we need to override method in class to add new options to the list. MigrateCommand getOptions RollbackCommand You might be thinking why we need to override in and not in . Well, it is implemented that way. Looks like changed it in recent version for some reason. Check out . If you any idea on why he did so, please do answer in comments ;) getOptions RollbackCommand MigrateCommand Taylor Otwell this commit At this point our rollback command is almost ready. All we need to do now is to tell Laravel to use this class instead of the default one. We can do this in our that we created earlier. VentureMigrationServiceProvider extends the singleton object available in alias and returns our own . registerMigrateRollbackCommand command.migrate.rollback RollbackCommand Testing Rollback Command We can now rollback all with . php artisan migrate:rollback --all To rollback specific schemas use . php artisan migrate:rollback --schema=th,sg,vn Status Command Status command shows the status of your migrations. This command is usually helpful when you want to check which migrations already ran and which one is not executed yet. We can extend in same way as we extended . StatusCommand RollbackCommand Again, in , register as Laravel’s default status command. VentureMigrationServiceProvider App\Console\Migration\StatusCommand extends the singleton object available in alias and returns our own . registerMigrateStatusCommand command.migrate.status StatusCommand Testing Status Command To view the status of all of our schemas, run . php artisan migrate:status --all To view the status of specific schemas, run . php artisan migrate:status --schema=th,my,vn Final Words In similar way, we can override remaining commands: , , and . One of the main advantage of extending default migration instead of creating a new one is that we still get the benefit of chaining other useful options like , , , etc. migrate:fresh migrate:reset migrate:refresh migrate:install --force --seed --database Next step: Can you make option work to define different migration path for ventures? Let me know your implementation in comments :) --path All of the codes used in current and can be found in this . previous tutorial Github repo That’s all! Happy Coding!