Skip to content

Conversation

BernhardBaumrock
Copy link
Contributor

@BernhardBaumrock BernhardBaumrock commented Mar 31, 2023

Hey @ryancramerdesign

This is a tiny PR that makes ProcessWire load config-local.php if it is present.

This is different from the technique used on config-dev.php in a way that it will not include config-local.php instead of config.php but rather additionally load it after the regular config.php file has been loaded.

Why this is useful

When deploying PW to multiple locations such as DEV/STAGING/PRODUCTION you need to maintain some settings differently depending on where you are (for example $config->debug = true on DEV but false on Production). Other settings should be the same for all environments (eg $config->appendTemplateFile).

You would typically add config.php to your git repo and make sure config-local.php is NOT in the repo and only added manually to DEV/STAGING/PRODUCTION

So if you want to add/change a global setting you add it to config.php and do a git push. If you want to add a local setting (like dbUser or forcing tracy debugger into development mode) you add it to config-local.php.

It's definitely a topic for many of us and it seems that everybody comes up with a similar but slightly different solution, which in my opinion is not good. See https://processwire.com/talk/topic/18719-maintain-separate-configs-for-livedev-like-a-boss/

Example

This is the global config file that all environments share:

// site/config.php
$config->debug = false;
$config->useFunctionsAPI = false;
$config->usePageClasses = true;
$config->useMarkupRegions = false;
$config->prependTemplateFile = '_init.php';
$config->appendTemplateFile = '_main.php';
$config->templateCompile = false;

$config->dbPort = '3306';
$config->dbCharset = 'utf8mb4';
$config->dbEngine = 'InnoDB';

$config->chmodDir = '0755'; // permission for directories created by ProcessWire
$config->chmodFile = '0644'; // permission for files created by ProcessWire

$config->timezone = 'Europe/Vienna';

Then I have this on local DEV:

// site/config-local.php
/** @var Config $config */
$config->debug = true;
$config->advanced = true;
$config->dbName = 'db';
$config->dbUser = 'db';
$config->dbPass = 'db';
$config->dbHost = 'db';
$config->httpHosts = ['example.com.ddev.site'];
$config->sessionFingerprint = false;

// tracy config for ddev development
$config->tracy = [
  'outputMode' => 'development',
  'guestForceDevelopmentLocal' => true,
  'forceIsLocal' => true,
  'localRootPath' => '/Users/bernhard/baumrock/example.com/',
  'numLogEntries' => 100, // for RockMigrations
];

On staging that file could look like this:

// site/config-local.php
/** @var Config $config */
$config->debug = true;
$config->advanced = true;
$config->dbName = 'user_db1';
$config->dbUser = 'user_db1';
$config->dbPass = '123';
$config->dbHost = 'localhost';
$config->httpHosts = ['staging.example.com'];

On production it would look something like this:

// site/config-local.php
/** @var Config $config */
$config->dbName = 'user_db2';
$config->dbUser = 'user_db2';
$config->dbPass = '456';
$config->dbHost = 'localhost';
$config->httpHosts = ['www.example.com'];

@BernhardBaumrock
Copy link
Contributor Author

@ryancramerdesign another reason why this would be useful is that RockMigrations deployment uses this convention:

vscode

See line 9726 where RockMigrations automatically creates a symlink after deployment that points to ../../shared/site/config-local.php

@teppokoivula
Copy link
Contributor

It's definitely a topic for many of us and it seems that everybody comes up with a similar but slightly different solution, which in my opinion is not good.

Perhaps worth noting that there's potentially a lot of nuance there: for an example in one of our environments a separate config file must always exist, and thus it gets loaded with require. If it can't be found, the process should stop right there. And in another environment instead of a config file we're calling a method of a shared class at the end of the config. Etc.

Those are just a couple of examples that use something very similar, but wouldn't be solved by this addition.

Just to be clear I'm not strongly opposed to this addition, but kind of feel like it's a bit... unnecessary. From my point of view it adds slight overhead — literally, but also by being another feature to know/remember — without bringing much to the table 🤷

@BernhardBaumrock
Copy link
Contributor Author

BernhardBaumrock commented Apr 3, 2023

Hey @teppokoivula thx for sharing your opinion!

IMHO your examples somewhat prove what I'm trying to say: Everybody has something in place, but we don't have a common convention.

And in my opinion THAT is the point that leads to "another thing to know/remember" and what my proposal could solve. At the moment I have to think about how to include the config-local.php file in every single installation. Sure, it's just copy&pasting this:

$localConfig = __DIR__ . "/config-local.php";
if (is_file($localConfig)) include $localConfig;

But it is still something to remember and it's something to explain when working on a project together. Whereas having a config-local.php is a super simple convention and would be use and forget.

Or imagine you were working for different clients with different PW installations built by different companies. What would cause more headache: Everybody loads the config a little differently VS. everybody had a config-local.php in place?

Another huge argument for my proposal: If you read my thread about how to maintain seperate configs like a boss you'll see that the concept has changed over time. Why?

Because other approaches that I had in place before simply did not work well! For example I used to use a solution that relied on one of the $SERVER httphost variable until I realised that this approach has a problem: https://processwire.com/talk/topic/18719-maintain-separate-configs-for-livedev-like-a-boss/?do=findComment&comment=191189

What was the problem? Bootstrapping of PW did not work! And I only realised that months after launching that site when we added that feature. So I had to revert the whole config which might add up to completely overhaul an automated deployment workflow!

Suddenly such a little thing get's a huge thing!! And everything could have been avoided with a little feature called config-local.php....

@teppokoivula
Copy link
Contributor

The two examples I mentioned above were ones that could not be solved with this: if a local config file was missing, the site must not start at all. This means that I would still have to add a check for that, and config would be a good place for it, which somewhat defeats the purpose of suggested local-config.

I do see your point here, and sympathize, but personally I feel that replacing a single include with a magically included file is kind of a vertical step. And in my opinion it's easier to grasp that ProcessWire automatically loads site/config.php and in that file there may be other includes, than knowing that ProcessWire automatically loads site/config.php (in which there may still be other includes) and site/local-config.php (in which there may be other includes).

But again, that's just me. Obviously our experiences matter: for an example I can see that you got burnt by this, while in my case that hasn't (yet) happened; and on the other hand literally all sites I work these days use a global setup so I don't have to worry about these things on a case by case basis; etc.

My point was and is that while a local-config may make sense for some users, there's nuance there — cases it will not solve.

That being said, if it solves most cases, then it absolutely makes sense as a global feature for everyone. For me personally it might not make sense, but I can just ignore it. Which, to be fair, is no different from what I do with much of what core does; and that, too, is perfectly fine :)

@BernhardBaumrock
Copy link
Contributor Author

Hi @teppokoivula thx for the follow-up :) All valid points. Let's see what Ryan has to add.

Actually now that you are saying it I'm not sure any more why I wouldn't change this:

$localConfig = __DIR__ . "/config-local.php";
if (is_file($localConfig)) include $localConfig;

to this:

require __DIR__ . "/config-local.php";

It seems that when using a separate-config-approach it is logical that PW should not boot if it can't find that local config. I'm not sure why exactly I had a different approach, but I think actually the earlier implementation introduced problems in that it had the potential to load a wrong config which is obviously a no-go. I'm talking about this old implementation:

// try to load config
foreach([
  "/path/to/your/live/config.php",
  __DIR__."/config-local.php",
  ] as $c) {
  if(!is_file($c)) continue;
  return include($c);
}
die("no config found");

Now that I've found the config-local approach this looks totally ugly and bad.

That's the whole point that I wanted to solve I guess: It seems to be harder than one might think to come up with a good and proven setup for maintaining separate configs for dev/staging/live.

I'm not sure anymore if the PR would be the best solution to that problem though. Maybe a paragraph in the docs about the site config and about a recommended way to load separate configs for different environments would be better:

image

@MrSnoozles
Copy link
Contributor

MrSnoozles commented Apr 16, 2023

IMO the local config file should also be added to the projects .gitignore.

What I'm doing in all my projects is at the end of site/config.php add

if(file_exists(__DIR__ . '/config.local.php')) {
    require(__DIR__ . '/config.local.php');
}

So I'm all up for this very useful change 👍 (and was never a fan of site/config-dev.php)


Edit: Thinking about it more I could imagine this change to be added (maybe commented by default) in site/config.php, instead of in wire/
Makes it more transparent to the user what's happening.

@BernhardBaumrock
Copy link
Contributor Author

@ryancramerdesign yet another thread in the forum that shows: 3 people having 3 different approaches where a simple config-local.php would be all you need :) https://processwire.com/talk/topic/28556-do-you-trick-your-local-web-server/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants