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()):
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.
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:
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.
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.
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.