Search code examples
phpyii2

How to switch from environment with dotenv in yii 2?


I am using yii 2 and

I installed the package:

 "vlucas/phpdotenv": "^5.6"

And in the root directory I have a folder env/dev/.env.dev

So I changed the web/index.php file like:

<?php
// phpcs:ignoreFile
$path = dirname(__DIR__) . '/env/dev';
require $path . '/vendor/autoload.php';
$dotEnv = Dotenv\Dotenv::createImmutable($path, '.env.dev');
$dotEnv->load();

defined('YII_DEBUG') or define('YII_DEBUG', $_ENV['YII_DEBUG']);
defined('YII_ENV') or define('YII_ENV', $_ENV['YII_ENV']);

require $path . '/vendor/yiisoft/yii2/Yii.php';

$config = require $path . '/config/web.php';

try {
    (new yii\web\Application($config))->run();
} catch (yii\base\InvalidConfigException $exception) {
    echo $exception->getMessage();
}

I just see that __DIR__ links to the directory:

c:\\repos\\internet_backend\\web"

and

'env/dev'

to:

c:\repos\internet_backend\env\dev

But then I get this error:

#Michal. Thank you for your contribution. But then I get this error: <br />
<b>Warning</b>: require(C:\repos\internet_backend/env/dev/vendor/autoload.php): Failed to open stream: No such
file or directory in <b>C:\repos\internet_backend\web\index.php</b> on line <b>4</b><br />
<br />
<b>Fatal error</b>: Uncaught Error: Failed opening required
'C:\repos\internet_2.0_backend/env/dev/vendor/autoload.php' (include_path='C:\xampp\php\PEAR') in
C:\repos\internet_2.0_backend\web\index.php:4
Stack trace:
#0 {main}
thrown in <b>C:\repos\internet_2.0_backend\web\index.php</b> on line <b>4</b><br />

So what I tried. Is to follow this link: https://matthewsetter.com/set-environment-variables-php-dotenv/

And to implement the recomondations of it

Question: how to run the .env.dev file?


Solution

  • Function dirname() takes path as first argument. It returns path to parent directory to the given path. You can optionally supply the second argument $levels, but it must be int and it represents how many levels up the dirname() should go before returning the result.

    The __DIR__ magic constant contains path to the directory the current file is in.

    So if you are in /path/to/my/project/web/index.php. Then dirname(__DIR__) would return /path/to/my/project. Calling it like this dirname(__DIR__, 2) would return /path/to/my instead.

    If you want to get path to /path/to/my/project/env/dev inside /path/to/my/project/web/index.php you can use:

    $path = dirname(__DIR__) . '/env/dev';
    

    If your config file is named .env.dev instead of .env you can't specify it as part of path to directory but rather you have to provide filename as second parameter in Dotenv\Dotenv::createImmutable($path, '.env.dev') call.

    EDIT: based on your edited question it looks like you don't have your vendor folder in your /env/dev folder. My guess is that your /env folder only contains .env configuration files.

    So the whole code can look like this:

    <?php
    // phpcs:ignoreFile
    $path = dirname(__DIR__);
    require $path . '/vendor/autoload.php';
    $dotEnv = Dotenv\Dotenv::createImmutable($path . '/env/dev', '.env.dev');
    $dotEnv->load();
    
    defined('YII_DEBUG') or define('YII_DEBUG', $_ENV['YII_DEBUG']);
    defined('YII_ENV') or define('YII_ENV', $_ENV['YII_ENV']);
    
    require $path . '/vendor/yiisoft/yii2/Yii.php';
    
    // I have no idea if your config file is in /config/web.php
    // or in /env/dev/config/web.php so you need to adjust this as needed.
    $config = require $path . '/config/web.php'; 
    
    try {
        (new yii\web\Application($config))->run();
    } catch (yii\base\InvalidConfigException $exception) {
        echo $exception->getMessage();
    }
    

    If you want to change project environment without the need to modify entry point files like index.php you can do following:

    1. Create a global .env file in project root where you will only set up the environment:
    YII_ENV=dev
    YII_DEBUG=1
    
    1. Create environment specific .env files in /env/... folders as needed. Personally, I would recommend to name the files only .env without the .dev, .test or .prod extensions. You already have them in folders /env/dev, /env/test or /env/prod and you wouldn't need to worry about passing proper filename when loading file.

    2. In entry point files like /web/index.php or /yii first load the global .env file then use the set up variables to load environment specific files. For example like this

    <?php
    // phpcs:ignoreFile
    $path = dirname(__DIR__);
    require $path . '/vendor/autoload.php';
    
    // load global .env file
    $dotEnv = Dotenv\Dotenv::createImmutable($path);
    $dotEnv->load();
    
    // load envirnoment specific .env file
    $dotEnv = Dotenv\Dotenv::createImmutable($path . '/env/' . $_ENV['YII_ENV']);
    // or if you have different file names based on env, you need to specify filename in second argument
    // $dotEnv = Dotenv\Dotenv::createImmutable($path . '/env/' . $_ENV['YII_ENV'], '.env.' . $_ENV['YII_ENV']);
    $dotEnv->load();
    
    defined('YII_DEBUG') or define('YII_DEBUG', $_ENV['YII_DEBUG']);
    defined('YII_ENV') or define('YII_ENV', $_ENV['YII_ENV']);
    
    require $path . '/vendor/yiisoft/yii2/Yii.php';
    
    // I have no idea if your config file is in /config/web.php
    // or in /env/dev/config/web.php so you need to adjust this as needed.
    $config = require $path . '/config/web.php'; 
    
    try {
        (new yii\web\Application($config))->run();
    } catch (yii\base\InvalidConfigException $exception) {
        echo $exception->getMessage();
    }