-
Notifications
You must be signed in to change notification settings - Fork 11.4k
[12.x] Add config_or_fail
helper
#56255
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 12.x
Are you sure you want to change the base?
Conversation
The implementation should behave similarly to the `\Illuminate\Support\Env::getOrFail()` method.
*/ | ||
public function getOrFail(string $key) | ||
{ | ||
return $this->get($key) ?? throw new RuntimeException("Configuration value for key [$key] is not set."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if the config is actually null this will not be ok.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is true, but also expected. If you know it may be null, you are probably better off using the regular get()
method. As I said, this is similar to the env()
helper.
What is your expectation on how the method should work? Only throw if the config key is missing? That would hardly be of any use, as most config keys should be static as they're build from the files in ./config/ returning arrays.
@macropay-solutions I've added my use case to the description so you may understand my intentions better now. What is your use case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dallyger in that case getNonNullOrFail would be a better naming.
We load all envs in a config dynamically and then we cache the config. We also use envs that are defined as null => configs that are defined as null.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not totally convinced yet, because your example seems to deviate from the default out of the box experience. And if you know you do that you should know not to use that helper. I mean this does not change any existing behavior, only adds some small new feature.
Let's wait for some more feedback from other peoples and check what they think about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getOrFail is analog to findOrFail firstOrFail in db. If the row is there is should not throw. Analog if the config exists, no matter the value it should not throw.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. Further testing showed me, that Env::getOrFail('FOO')
, which this change was based upon, does return null, if FOO=null
is set in .env
. This was indeed an oversight on my end and due to a lot of indirection in the code not trivial to understand. Do you have suggestions for the error message and the helper function too? config_non_null_or_fail()
seems like a rather long name for a small helper.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could use this trick to allow null
values.
It's done in multiple places throughout the framework such as here:
framework/src/Illuminate/Collections/Collection.php
Lines 175 to 196 in fac2d77
/** | |
* Determine if an item exists in the collection. | |
* | |
* @param (callable(TValue, TKey): bool)|TValue|string $key | |
* @param mixed $operator | |
* @param mixed $value | |
* @return bool | |
*/ | |
public function contains($key, $operator = null, $value = null) | |
{ | |
if (func_num_args() === 1) { | |
if ($this->useAsCallable($key)) { | |
$placeholder = new stdClass; | |
return $this->first($key, $placeholder) !== $placeholder; | |
} | |
return in_array($key, $this->items); | |
} | |
return $this->contains($this->operatorForWhere(...func_get_args())); | |
} |
*/ | ||
public function getOrFail(string $key) | ||
{ | ||
return $this->get($key) ?? throw new RuntimeException("Configuration value for key [$key] is not set."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return $this->get($key) ?? throw new RuntimeException("Configuration value for key [$key] is not set."); | |
$placeholder = new stdClass(); | |
$value = $this->get($key, $placeholder); | |
if ($value === $placeholder) { | |
throw new RuntimeException("Configuration value for key [$key] is not set."); | |
} | |
return $value; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you very much for this trick! However, I'm currently undecided on how I would like to proceed with this PR, as that would fix the issue mentioned above, but also deviate from my use case and no longer solve my issue. Will take some time to think about it.
@@ -8,6 +8,7 @@ | |||
use Illuminate\Support\Collection; | |||
use Illuminate\Support\Traits\Macroable; | |||
use InvalidArgumentException; | |||
use RuntimeException; | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use stdClass; |
I don't know but this doesn't read well. It looks … clunky 🤔 Maybe, we should consider adapting conventions like Ruby (Laravel is based on Rails anyway) has (e.g. |
For me personally, any style seems fine. Would be nice if they're consistent. My thought was, that there is a |
@dallyger a solution for you only via macro would be the best. No headaches. |
@macropay-solutions Thank you! How could I not think about macros? I was literally using one on the same line! Also iterated on your suggestion for a name better matching the action it does. My solution now is this: use Illuminate\Support\Facades\Config;
# AppServiceProvider.php
Config::macro('getNonNull', fn (string $key) => Config::get($key)
?? throw new RuntimeException("Configuration value for key [$key] is empty."));
# usage:
Config::getNonNull('foo.bar'); |
I get the point but I'm not following the reasoning. If you're deploying or expecting some config values to be set, checking them on runtime at the point of usage seems kind of dubious at best. You would check them all before doing anything (during bootstrapping etc.) to ensure nothing ends up partially broken or incorrect, not fail as it happens - especially on deployments. Most of those cases can be just written by throw_unless(config('deploy.key'), new RuntimeException('Deploy key is not set.')); or such where you can provide a more detailed error message if needed etc.. If you're conditionally throwing like in your example: if (config('services.xyz.active')) {
Http::post(config_or_fail('services.xyz.domain').'/up');
} you'll most likely want to throw a custom exception that can be handled by the global exception handler or try/catch for that specific case. |
Add
getOrFail()
to Config repository (with tests)Add
config_or_fail()
helper in FoundationThe implementation should behave similarly to the
\Illuminate\Support\Env::getOrFail()
method.My use-case for this would be to quickly check, that the user did not forget to set some environment variables while deployment. Some configs may not have a good default value but are also not that important to block an entire deployment if just that small feature fails.
Example config:
With that, you may use it like so: