lumen-framework: Generating URLs for named routes on commands is missing hostname and port

Hi,

Seems like the route helper is not working properly on commands. I would like to generate a URL to a named route with parameters but it seems to be always missing the hostname and port. It works fine on controllers and route closures but not on commands.

routes.php which returns http://localhost:12345/user/1

<?php
$app->get('user/{id}', ['as' => 'user', function ($id) {
    return route('user', ['id' => 1]);
}]);

Same route helper on the command:

/**
 * Execute the console command.
 *
 * @return mixed
 */
public function handle()
{
    $url = route('user', ['id' => 1]);
    $this->info($url);
}
vagrant@homestead:~/Code/lumen_route_helper$ php artisan test:url
http://:/user/1

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 12
  • Comments: 26 (10 by maintainers)

Commits related to this issue

Most upvoted comments

As a temporary solution to this problem, i added this to my console kernel file:

protected function prepareConsoleUrl()
{
    $url = env('APP_URL', 'http://localhost');
    $urlParts = parse_url($url);

    if (isset($urlParts['path']) && mb_strlen($urlParts['path']) > 1) {
        $_SERVER['SCRIPT_NAME'] = $urlParts['path'].DIRECTORY_SEPARATOR.'index.php';
        $_SERVER['SCRIPT_FILENAME'] = getenv('PWD').DIRECTORY_SEPARATOR.$urlParts['path'].DIRECTORY_SEPARATOR.'index.php';
    }
    $this->app->instance('request', Request::create($url, 'GET', [], [], [], $_SERVER));
}

and to the constructor i added $this->prepareConsoleUrl();, but if you don’t have the constructor there already, you can do it like this:

public function __construct(Application $app)
{
    parent::__construct($app);

    $this->prepareConsoleUrl();
}

I fetched the code from this commit: https://github.com/j3j5/framework/commit/920f023e1bd11de1a6a2a0e923a0cce7481110d9

That should do it until a real solution is added to lumen

This should work (do not forget to provide a proper APP_URL in .env config):

// Assuming $app is an instance of \Laravel\Lumen\Application
$app->make('url')->forceRootUrl(env('APP_URL', 'http://localhost/'));

Or you can enable the AppServiceProvider and put into register method to force the root url only in certain evironment.

Testing Environment

In testing environment it might be better to edit the createApplication method in tests/TestCase.php like this:

public function createApplication()
{
    $app = require __DIR__.'/../bootstrap/app.php';

    $app->make('url')->forceRootUrl(env('APP_URL', 'http://localhost/'));

    return $app;
}

Console Environment

In the same way, to fix the issue in console you can place the same code in the constructor of the Console Kernel as shown below:

public function __construct(\Laravel\Lumen\Application $app)
{
    parent::__construct($app);

    $this->app->make('url')->forceRootUrl(env('APP_URL', 'http://localhost/'));
}

We’re open to PRs to fix it.

Still getting this problem anywhere outside of immediate routes…

For some reason the Symfony base request class isn’t constructed/configured the same way it is with Laravel. In Laravel, it uses the ‘HOST’ header to determine the host for the root URL. All of the headers seem to be empty in Lumen while the URLGenerator is interacting with it…

If you try dd’ing inside here you’ll notice the following:

// Line: 1258 in vendor/symfony/http-foundation/Request.php
public function getHost()
{
    // Laravel: 'foo.bar'
    // Lumen: ''
    dd($this->headers->get('HOST'));
}

I’ll keep digging…

Sweet. Thanks man!

Yeah, just like here: https://github.com/laravel/lumen/blob/master/bootstrap/app.php#L46-L49

We’ll need a base test class which bootstraps the app with this binding before it’ll properly work. This is probably something for a new major release. I’ll ask some input from @taylorotwell on this.

@driesvints The route helper works in regular commands and queues in my tests. However, it doesn’t work in Phpunit because the kernel is never bootstrapped when running tests. If you call this:

app('Illuminate\Contracts\Console\Kernel');

right before you call the route helper in your test, it’ll work.

I’m not sure how you’d want to see this fixed, because it can be done in multiple ways. The kernel has to be bootstrapped somewhere within the instantiation of the tests.