Environmental Variables

It would be handy to have environmental variables in MODX. Currently working with a dev, staging and production workflow and not being able to set database and path variables based on environment is a definite hassle.

So my question is, could I use a plugin that runs onMODXInit to selectively set these variables at runtime from .env files? Has anyone done anything like this?

Could add them into $config_options in your core/config/config.inc.php as that’s already most likely an environment specific file.

Do note you’ll have to hardcode the key/values. Any logic/conditionals/function calls/variables will be undone when upgrading MODX, leaving only the actual value at upgrade time. Plain key/values will be kept.

As for OnMODXInit, sure that will also work. Call $modx->setOption('key', 'val') to store temporary config values for the request. In some cases if you want to change values for a specific extra that also runs on OnMODXInit, it may be necessary to play with the run order on the plugin event.

You could also create and set System Settings in a plugin attached to OnMODXInit (which would create permanent System Settings that wouldn’t be overwritten), but the calls below are made before that event fires, and I think it’s likely that they’d need some of the things you’ll be setting (which they would get from config.inc.php in getConfig()):

$this->getCacheManager();
$this->getConfig();
$this->_initContext($contextKey, false, $options);
$this->_loadExtensionPackages($options);
$this->_initSession($options);
$this->_initErrorHandler($options);
$this->_initCulture($options);

I don’t think config.inc.php is overwritten during MODX upgrades, but I could be wrong. If I’m right, that’s probably the best place to put your stuff as Mark has suggested.

Another option would be to modify the three config.core.php files, which I’m pretty sure are not ever changed by MODX. They are located in the MODX root, /connectors, and /manager directories (there’s also one in setup/includes, but it would be overwritten when upgrading).

Something else to consider here is using Teleport to handle the process of migration in this situation vs moving things around yourself. This is the heart of staging to production in MODX Cloud. Teleport Extract templates can define which content and environment things to move from origin to the follow-on environments and respect any settings. It may be overkill or maybe too out of left field for your scenario but it may not.

It’s because config.inc.php is environment specific that I would like this functionality. Having a separate one for each environment is causing my pain point and modifying a core file that could be overwritten in an update doesn’t seem to really address that, even if that file doesn’t get updated very often.

Maybe this is worth thinking about for MODX 3. If the config looked for the presence of a environmental variable and grabbed config details from an .env file based on that variable, that would definitely be ideal and in line with other frameworks.

Yeah, probably too late at that point. I’ll have a poke around and if I see anything helpful I’ll post back. Was hoping someone might already know. :grinning:

Not hosting on Cloud but good to know.

Teleport can be run in many environments other than Cloud. It’s just the OS tech that Cloud uses as part of our east buttons.

It is in fact overwritten, however it preserves most of the values you define there (unless you change the values in an advanced upgrade) by placing the values into a template. The config_options just has to be a basic array - it doesn’t preserve the textual way it’s defined, but its values as read by the setup when including the file.

To give an example of that, any standard scalar value you put into $config_options is preserved in upgrades. I.e., this would be copied allowing you to set different custom options per environment:

$config_options = array(
    'environment' => 'dev'
);

The following will not be preserved and instead get replaced with whatever read_dotenv() returned when the setup read the config file:

$config_options = read_dotenv();

I learned that the hard way in production. :wink:

To add to this, consistently using a an environment-specific config key through those config.core.php files would also be an interesting solution. As long as you also provide the right config key and don’t accidentally overwrite config.core.php files on upgrade with the wrong key…

There has actually been an issue with some ideas about this some time ago, I think that was about a year ago. Can’t find it right now but I think that may have also mentioned .env files or yaml or something like that… certainly would be interesting to explore further.

1 Like

I think the real issue here is the lack of a simple export / import feature. It is a pain, but you can clone the databases, duplicate the site, manually edit the paths, rerun setup. I think the easiest thing to do is to create contexts moving content from development to staging to live - but even that is overly complicated. If you are creating applications, it becomes much easier. Just keep everything disconnected from MODX except for a single field that allows for authentication, access to be checked via modUser.

Sorry for worry, could you provide small example please?
I’ve installed Dotenv env parser via composer and added following code to the top of config.inc.php file. But after reading your comment, I’m starting to doubt that I did everything right.

require_once __DIR__ . '/../../vendor/autoload.php';
$dotenv = \Dotenv\Dotenv::createImmutable( __DIR__ . '/../../' );
$dotenv->safeLoad();

$database_type = $_ENV['DB_TYPE'];
$database_server = $_ENV['DB_SERVER'];
$database_user = $_ENV['DB_USER'];
$database_password = $_ENV['DB_PASSWORD'];
$database_connection_charset = $_ENV['DB_CHARSET'];
$dbase = $_ENV['DB_NAME'];
$table_prefix = $_ENV['DB_PREFIX'];
$database_dsn = $_ENV['DB_DSN'];

Also what about config.core.php? all paths will be overwritten after updating modx. Right? How to resolve this issue?

Thanks so much.

Appreciate that this is an old thread but commenting as the situation does not appear to have changed in MODX3.

One simple approach to making sites more portable across environments would be to add

if (file_exists(dirname(__FILE__) .'/local.config.inc.php')) {
    require(dirname(__FILE__) . '/local.config.inc.php');
}

into the default config.inc.php after the initial variables but before the constants. This way per-environment overrides can be placed in a file that will not be impacted by ModX updates and developers can either ignore from version control or configure to use environment variables as they see fit.

I’m not sure of the rationale behind the hardcoded absolute system paths in the main config file and the config.core.php files but could these not be replaced with relative paths prefixed with dirname(__FILE__) to produce the same result whilst allowing the site to be moved/deployed elsewhere?

1 Like

Have pretty much disengaged from the community for reasons that should be clear to anyone reading "contriibutions’ to some of my other threads familiar with community standards in any open source project but this does seem like a big missed opportunity to address a problem that isn’t one in any other major framework.

@stephenn have you seen this extra it might help

Thanks @bennyb I don’t think, though I’d be happy to be corrected, that this can handle overriding the DB connections.