0

I recently had to run a couple of migrations to move entries from one structure to the other, but had problems when running the migration PHP script being able to get environment variables e.g. DB and stuff in .env. In the end I temporarily replaced my craft/config/db.php and hard coded my DB on local so I could run the script, however this isn't really ideal but did the job. It seemed the script couldn't get the DB environment variables.

I'm wondering what should I be including in my bootstrap migration scripts going forward in order to utilise the environment variables properly. I used a version of the script here:

Move entry from one structure to another with parenting

Slightly modified to take an array of ids, as well as mapping the old and new entry types as an arry, so it could be done in one go.

I essentially tried copying most of the beginning portion of the index.php like this and transplanting it into my migration script

// Composer: https://getcomposer.org/doc/
require_once('../vendor/autoload.php');

// PHP dotenv: https://github.com/vlucas/phpdotenv
if (!getenv('APP_SECRETS'))
{
    $root_dir = dirname(dirname(__FILE__));
    if (file_exists($root_dir . '/.env'))
    {
        Dotenv::load($root_dir);
        Dotenv::required(array('APP_SECRETS', 'CRAFT_ENVIRONMENT'));
    }
}
define('CRAFT_ENVIRONMENT', getenv('CRAFT_ENVIRONMENT'));

However, no matter what I just got a die() error from craft/local/db.php saying the path to the file containing the DB crendentials (secrets.json) couldn't be found, so it seems the environment variables weren't available at runtime. APP_SECRETS is the path to the json file.

Any ideas, what I'm missing for environment variables to be loaded in?

Thanks.

  • Why don't you just use Craft's default index.php as a reference and remove the $app->run() part in order to not start Craft? I don't see any benefit in your way at all. You can even run Craft normally and create a migration file or start your script inside a module / plugin. – Robin Schambach Apr 27 '18 at 14:41
  • @RobinSchambach I figured bootstrap.php was the preferred mechanism to do migrations like this. Given it ships with Craft. – James White Apr 27 '18 at 14:43
  • Yeah but what is the difference between moving your index.php to your bootstrap.php and removing the $app->run from your index.php. You need most parts of the bootstrap anyway so you can't remove that much from it. Thus you can just remove the run function from your index.php and that's basically it – Robin Schambach Apr 27 '18 at 14:51
  • I guess I never really thought about that. I came across the linked article related to migrations between two channels and thought bootstrap.php was preferred method, but if the same can be achieved through the content in the index.php and just removing the Craft app run part, I guess I can just use that! – James White Apr 27 '18 at 15:27
  • @JamesWhite be sure and share your solution as an official answer once you get it working! :) – Brad Bell Apr 30 '18 at 23:59
1

So debugging this a bit, it looks like its to do with the namespace declaration on the original template I was using for the migration. Basically when declaring namespace Craft this causes problems with loading the environment variables that were previously being masked by the die() error, as I was including Bootstrap too early.

Uncaught Error: Class 'Craft\Dotenv' not found

In my case, the phpdotnev stuff is going to need to appear before including Bootstrap otherwise Craft isn't going to be able to connect to the DB.

Moving the vendor and environment variables stuff up before loading the bootstrap file from the Craft folder, seems to work. This a test file I have now:

<?php
namespace Craft;

// Avoid errors when running through console
$_SERVER['HTTP_HOST'] = 'example.craft.localdev';
$_SERVER['REQUEST_URI'] = '/index.php';

// Get the root dir so we can run migrations without worrying about path
$root_dir = dirname(dirname(__FILE__));

// We need to load in phpdotenv stuff before initialising bootstrap.php, otherwise you won't be able to connect to the DB
require_once($root_dir . '/vendor/autoload.php');

// If APP_SECRETS is not set, load in .env file
if (!getenv('APP_SECRETS'))
{
    $envFile = '.env';

    if (file_exists($root_dir . '/' . $envFile))
    {
        // PHP dotenv: https://github.com/vlucas/phpdotenv
        $dotenv = new \Dotenv\Dotenv($root_dir);
        $dotenv->load();
        $dotenv->required(['APP_SECRETS', 'CRAFT_ENVIRONMENT']);
    }
    else
    {
        die("$envFile does not exist.");
    }
}

// Set the Craft environment with the value set in .env
define('CRAFT_ENVIRONMENT', getenv('CRAFT_ENVIRONMENT'));

// Initialize Craft without letting it take over the whole request
$app = require $root_dir . '/craft/app/bootstrap.php';

// Set Craft to Craft Personal so we don't get any errors about Client/Pro-only components not being available
$app->getInfo()->edition = 0;

// CUSTOM CODE FOR MIGRATIONS AND OTHER CRAFT RELATED STUFF GOES BELOW THIS LINE

This then appears to be using the proper environment variables. I tested by editing my db.php file to break one of the variables being pulled from secrets.json to cause the DB connection error and it does appear to be work, as the try and catch statement is responding appropriately.

Not sure if there will be an issue not having the namespace Craft declared or not, but I appear to be able to interact with Craft through $app still. Would this be correct?

| improve this answer | |
  • The namespace doesn't matter. You can include/remove whatever namespace you want as long as you include the correct classes – Robin Schambach May 2 '18 at 8:32
  • @RobinSchambach OK. So looks like this is a working solution then! – James White May 2 '18 at 8:33
  • I'm still not really sure what you did/changed... It finally looks like a normal web/index.php just without the $app->run() part like I suggested from the beginning. Only with the additional $app->getInfo()->edition = 0; part and everything after it. – Robin Schambach May 2 '18 at 8:35
  • @RobinSchambach. Basically removed the namespace Craft from the script. Moved up the vendor/phpdotenv stuff up before including the bootstrap.php. I never had $app->run() in my script. The main problem seemed to be the namespace Craft, but because the environment variable stuff wasn't being loaded, it was just masking the overall issue by throwing the die() error within db.php. Basically the phpdotenv stuff won't work unless that namespace is removed. One line was causing the problem, something that was taken from the original migration script template I had used that Brad wrote. – James White May 2 '18 at 8:40
  • Alright, glad you got it working. It's just a little bit strange because the default web/index that comes with a new Craft installation doesn't have the namespace Craft and loads all this stuff before the bootstrap is included... So it does everything you changed by default. Seems like yours was edited in some way or another. – Robin Schambach May 2 '18 at 8:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.