In Laravel, one of the big questions is how best install packages. Traditionally, we would create a nasty bit of readme that included a script that looks like this:

php artisan config:publish rtablada/laravel-faq

While this isn't that tough, it can be a bit confusing and is a bit long. I much prefer to run something like this:

php artisan faq:config

It is shorter, sweeter and gives that extra comfort.

So, to start we will create a console namespace for our commands to go into. In src/Rtablada/LaravelFaq/Console/ConfigureCommand.php start with a command skeleton:

<?php namespace Rtablada\LaravelFaq\Console;

use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;

class ConfigureCommand extends Command {

    /**
     * The console command name.
     *
     * @var string
     */
    protected $name = 'command:name';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '';

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

    /**
     * Execute the console command.
     *
     * @return void
     */
    public function fire()
    {
        //
    }

}

Then we will create a simple command by filling things in and using the call method which can be used to call any artisan command.

class ConfigureCommand extends Command {
    protected $name = 'faq:config';

    protected $description = 'Publishes configuration for Laravel FAQ.';

    public function fire()
    {
        $this->call('config:publish', array('package' => 'rtablada/laravel-faq'));
    }
}

Now, on to trickier fish. Yesterday, we made the database interactions for our models flexible. While, this is very cool, it makes things a bit awkward when running migrations. We could create funny looking migrations which change the default connection but this gets a bit messy and process intensive. Luckily, the artisan migrate command has a --database flag that designates what connection to use. So the migration command for our package would be

php artisan migrate --package="rtablada/laravel-faq" --database="faq"

Still completely readable, but let's make it php artisan faq:migrate

class MigrateCommand extends Command {
    protected $name = 'faq:migrate';

    protected $description = 'Migrates the database for Laravel FAQ.';

    public function fire()
    {
        $this->call('migrate', array('--package' => 'rtablada/laravel-faq', '--database' => 'faq'));
    }
}

The last minor command I want to add is php artisan asset:publish rtablada/laravel-faq

class AssetsCommand extends Command {
    protected $name = 'faq:assets';

    protected $description = 'Publishes assets for Laravel FAQ.';

    public function fire()
    {
        $this->call('asset:publish', array('package' => 'rtablada/laravel-faq'));
    }
}

Finally, lets wrap this into a single install command

class InstallCommand extends Command {
    protected $name = 'faq:assets';

    protected $description = 'Publishes assets for Laravel FAQ.';

    public function fire()
    {
        $this->call('faq:config');
        $this->call('faq:assets');
        if ($this->confirm('Have you configured your database yet?')) {
            $this->call('faq:config');
        } else {
            $this->comment('Your database has not been migrated, run artisan faq:migrate before use');
        }
    }
}

One added feature is the confirm in the installer. This will pause running the migration command while a user is configuring the database. If the user responds no, then it will tell them to migrate manually before use.

Now that we have our commands, we have to register them in our src/rtablada/LaravelFaq/LaravelFaqServiceProvider

public function register()
{
    $this->registerCommands();
}

public function registerCommands()
{
    $this->registerMigrateCommand();
    $this->registerConfigureCommand();
    $this->registerAssetsCommand();
    $this->registerInstallCommand();

    $this->commands(
        'laravel-faq::commands.migrate',
        'laravel-faq::commands.config',
        'laravel-faq::commands.assets',
        'laravel-faq::commands.install'
    );
}

public function registerMigrateCommand()
{
    $this->app['laravel-faq::commands.migrate'] = $this->app->share(function($app)
    {
        return new Console\MigrateCommand;
    });
}

public function registerConfigureCommand()
{
    $this->app['laravel-faq::commands.config'] = $this->app->share(function($app)
    {
        return new Console\ConfigureCommand;
    });
}

public function registerAssetsCommand()
{
    $this->app['laravel-faq::commands.assets'] = $this->app->share(function($app)
    {
        return new Console\AssetsCommand;
    });
}

public function registerInstallCommand()
{
    $this->app['laravel-faq::commands.install'] = $this->app->share(function($app)
    {
        return new Console\InstallCommand;
    });
}

Now we have created an easier, more flexible, less error prone installation process than before in just a few minutes.