Skip to content

[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

Draft
wants to merge 2 commits into
base: 12.x
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/Illuminate/Config/Repository.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Illuminate\Support\Collection;
use Illuminate\Support\Traits\Macroable;
use InvalidArgumentException;
use RuntimeException;

Copy link
Contributor

@rojtjo rojtjo Jul 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
use stdClass;

class Repository implements ArrayAccess, ConfigContract
{
Expand Down Expand Up @@ -57,6 +58,19 @@ public function get($key, $default = null)
return Arr::get($this->items, $key, $default);
}

/**
* Get the specified configuration value.
*
* @param string $key
* @return mixed
*
* @throws \RuntimeException
*/
public function getOrFail(string $key)
{
return $this->get($key) ?? throw new RuntimeException("Configuration value for key [$key] is not set.");

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.

Copy link
Contributor Author

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?

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.

Copy link
Contributor Author

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.

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.

Copy link
Contributor Author

@dallyger dallyger Jul 10, 2025

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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;

Copy link
Contributor Author

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.

}

/**
* Get many configuration values.
*
Expand Down
13 changes: 13 additions & 0 deletions src/Illuminate/Foundation/helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,19 @@ function config($key = null, $default = null)
}
}

if (! function_exists('config_or_fail')) {
/**
* Get the specified configuration value.
*
* @param string $key
* @return mixed
*/
function config_or_fail(string $key)
{
return app('config')->getOrFail($key);
}
}

if (! function_exists('config_path')) {
/**
* Get the configuration path.
Expand Down
14 changes: 14 additions & 0 deletions tests/Config/RepositoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Illuminate\Support\Collection;
use InvalidArgumentException;
use PHPUnit\Framework\TestCase;
use RuntimeException;

class RepositoryTest extends TestCase
{
Expand Down Expand Up @@ -151,6 +152,19 @@ public function testGetWithDefault()
$this->assertSame('default', $this->repository->get('not-exist', 'default'));
}

public function testGetOrFailGets()
{
$this->assertSame('bar', $this->repository->getOrFail('foo'));
}

public function testGetOrFailFails()
{
$this->expectException(RuntimeException::class);
$this->expectExceptionMessageMatches('#^Configuration value for key \[not-exist\] is not set.#');

$this->repository->getOrFail('not-exist');
}

public function testSet()
{
$this->repository->set('key', 'value');
Expand Down