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.

8
  • 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. Commented Apr 27, 2018 at 14:41
  • @RobinSchambach I figured bootstrap.php was the preferred mechanism to do migrations like this. Given it ships with Craft. Commented Apr 27, 2018 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 Commented Apr 27, 2018 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! Commented Apr 27, 2018 at 15:27
  • @JamesWhite be sure and share your solution as an official answer once you get it working! :) Commented Apr 30, 2018 at 23:59

1 Answer 1

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?

8
  • The namespace doesn't matter. You can include/remove whatever namespace you want as long as you include the correct classes Commented May 2, 2018 at 8:32
  • @RobinSchambach OK. So looks like this is a working solution then! Commented May 2, 2018 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. Commented May 2, 2018 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. Commented May 2, 2018 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. Commented May 2, 2018 at 8:44

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.