laravel / lumen-framework

The Laravel Lumen Framework.
https://lumen.laravel.com
MIT License
1.48k stars 419 forks source link

php artisan --env= doesn't affect execution #1055

Closed efinder2 closed 4 years ago

efinder2 commented 4 years ago

Description:

the command artisan --env=testing doesn't affect the environment of the current call.

Steps To Reproduce:

Create an empty lumen application in windows. Configure a sqlite connection in .env:

DB_CONNECTION=sqlite
DB_DATABASE=C:\test.sqlite
  1. php artisan migrate => no errors.
  2. copy the .env to .env.testing.
  3. Change the Path to an invalid value in the .env
  4. php artisan migrate --env=testing =>path from the .env.testing should be taken

What happens instead? the value from the .env is taken. in laravel this works without problems.

driesvints commented 4 years ago

I'll mark this as a bug for now. Appreciating help with this.

kanidjar commented 4 years ago

It looks like this option is never taken into account, whatever the command executed.

Dumping app()->environment() in "execute" function

namespace Illuminate\Console;

class Command 
{
   ...

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        dd(app()->environment());

        return $this->laravel->call([$this, 'handle']);
    }

   ...
}

gives

 $ php artisan migrate --env=testing
^ "local"
$ php artisan make:mail MyMail --env=testing
^ "local"
kanidjar commented 4 years ago

@driesvints

After analyzing the issue, it seems that dynamically loading an environment file has not been implemented in Lumen.

In Lumen, the env file is loaded by manually instantiating a new LoadEnvironmentVariables object in bootstrap/app.php

// boostrap.php

(new Laravel\Lumen\Bootstrap\LoadEnvironmentVariables(
    \dirname(__DIR__),
))->bootstrap();
class LoadEnvironmentVariables
{
    protected $filePath;
    protected $fileName;

    public function __construct($path, $name = null)
    {
        $this->filePath = $path;
        $this->fileName = $name;
    }

$name corresponding to the .env filename

Moreover, the "environment" method in the "Application" class never reads the --env option from the command-line:

public function environment()
    {
        $env = env('APP_ENV', config('app.env', 'production'));

        if (func_num_args() > 0) {
            $patterns = is_array(func_get_arg(0)) ? func_get_arg(0) : func_get_args();

            foreach ($patterns as $pattern) {
                if (Str::is($pattern, $env)) {
                    return true;
                }
            }

            return false;
        }

        return $env;
    }

To summarize, we have two issues here:

1) Taking the command-line environment option into account 2) Reading a .env dynamically (--env based)

The first issue is quite easy to fix:

 public function environment()
    {
        if (app()->runningInConsole() && ($input = new ArgvInput)->hasParameterOption('--env')) {
            $env = $input->getParameterOption('--env');
        }
        else {
            $env = env('APP_ENV', config('app.env', 'production'));
        }

        if (func_num_args() > 0) {
            $patterns = is_array(func_get_arg(0)) ? func_get_arg(0) : func_get_args();

            foreach ($patterns as $pattern) {
                if (Str::is($pattern, $env)) {
                    return true;
                }
            }

            return false;
        }

        return $env;
    }
  1. would need a deeper investigation based on what is done in Laravel...
bytestream commented 4 years ago

Laravel uses this:

    /**
     * Detect if a custom environment file matching the APP_ENV exists.
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @return void
     */
    protected function checkForSpecificEnvironmentFile($app)
    {
        if ($app->runningInConsole() && ($input = new ArgvInput)->hasParameterOption('--env')) {
            if ($this->setEnvironmentFilePath(
                $app, $app->environmentFile().'.'.$input->getParameterOption('--env')
            )) {
                return;
            }
        }

        $environment = Env::get('APP_ENV');

        if (! $environment) {
            return;
        }

        $this->setEnvironmentFilePath(
            $app, $app->environmentFile().'.'.$environment
        );
    }
driesvints commented 4 years ago

As said on the PR we won't be supporting this I'm afraid.