Artisan server for Lumen
Tags: laravel, lumen, artisan
Published: 2021-02-15 20:44:00

I came across many suggestions for implementing the **`php artisan serve`** command in Lumen, however sometimes in development, especially with the popularization of microservices, that is, there may be situations where different applications need to communicate, usually in a development environment using only ports as access.

So starting application by application with `php -S host:port -t public` can be a little tricky or just annoying.

Fortunately if we have the value of APP_URL in env we can facilitate part of the process.

First create a file called `ServeCommand.php` in the `./app/Console/Commands/` folder, after edit `app/Console/Kernel.php` and put `ServerCommand`, like this:

```php
<?php

namespace App\Console;

use Illuminate\Console\Scheduling\Schedule;
use Laravel\Lumen\Console\Kernel as ConsoleKernel;

class Kernel extends ConsoleKernel
{
    protected $commands = [
        Commands\ServeCommand::class,
    ];
```

The class `Illuminate\Console\Command` has a protected method called `getOptions()`, with it we can define default values for parameters in a command, or also inform if a parameter is optional (`Symfony\Component\Console\Input\InputOption::VALUE_OPTIONAL`) or required (`Symfony\Component\Console\Input\InputArgument::REQUIRED`).

> More details in: https://symfony.com/doc/current/console/input.html

The proposal is to use as an option, that is, allow the user to change the host or port if desired when entering a command, or else use the value of `APP_URL`. To get the default host and port values I used [`parse_url`](https://www.php.net/manual/en/function.parse-url.php), example usage:

``` php
protected function getOptions()
{
    $url = env('APP_URL');

    return [
        [
            'host', null, InputOption::VALUE_OPTIONAL, 'The host address to serve the application on.', parse_url($url, PHP_URL_HOST)
        ], [
            'port', null, InputOption::VALUE_OPTIONAL, 'The port to serve the application on.', parse_url($url, PHP_URL_PORT)
        ],
    ];
}
```

to obtain the host and port (defined via command line or `.env`) use:

``` php
$host = $this->input->getOption('host');

$port = $this->input->getOption('port');
```

However there is still a detail, it is possible for the user to start the `artisan serve` from a different folder level so we set the `-t` ([php built in webserver](https://www.php.net/manual/en/features.commandline.webserver.php)) to start the `public` directory. To get the project directory use:

``` php
$base = $this->laravel->basePath();
```
The command call should look like this:

```php
passthru('"' . PHP_BINARY . '"' . " -S {$host}:{$port} -t \"{$base}/public\"");
```

Source on gist: https://gist.github.com/brcontainer/44f47d35f47cd4e33f14023f8521bea1

Full source code:

```php
<?php

namespace App\Console\Commands;

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

class ServeCommand extends Command {

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

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = "Serve the application on the PHP development server";

    /**
     * Execute the console command.
     *
     * @return void
     */
    public function handle()
    {
        $host = $this->input->getOption('host');

        $port = $this->input->getOption('port');

        $base = $this->laravel->basePath();

        $this->info("Lumen development server started on http://{$host}:{$port}/");

        passthru('"' . PHP_BINARY . '"' . " -S {$host}:{$port} -t \"{$base}/public\"");
    }

    /**
     * Get the console command options.
     *
     * @return array
     */
    protected function getOptions()
    {
        $url = env('APP_URL');

        return [
            [
                'host', null, InputOption::VALUE_OPTIONAL, 'The host address to serve the application on.', parse_url($url, PHP_URL_HOST)
            ], [
                'port', null, InputOption::VALUE_OPTIONAL, 'The port to serve the application on.', parse_url($url, PHP_URL_PORT)
            ],
        ];
    }

}

```