Skip to content

fix(parser): work without a booted application - #23

Merged
danielebarbaro merged 1 commit into
mainfrom
fix/config-outside-a-booted-app
Sep 8, 2026
Merged

fix(parser): work without a booted application#23
danielebarbaro merged 1 commit into
mainfrom
fix/config-outside-a-booted-app

Conversation

@danielebarbaro

Copy link
Copy Markdown
Contributor

Problem

public function __construct()
{
    $this->namespace = config('kml-parser.namespace', $this->namespace);
    $this->validator = new KmlValidator($this->supportedNamespaces());
}

The second argument to config() looks like a safe fallback. It is not. The helper resolves config out of the container first, and when nothing is bound there it does not fall back, it throws:

Illuminate\Contracts\Container\BindingResolutionException: Target class [config] does not exist.

So new KmlParser is fatal anywhere outside a booted application: a console script, a plain PHPUnit test that does not boot Laravel, a queue bootstrap that has not resolved the config repository yet.

There is a second version of the same problem. composer.json requires illuminate/contracts, not illuminate/support. The config() and app() helpers live in illuminate/support, so on an install that pulls only what this package declares, the helper is not defined at all and the constructor is a fatal Call to undefined function.

Fix

A ReadsPackageConfig trait with one method:

protected function packageConfig(string $key, mixed $default): mixed
{
    if (! function_exists('config') || ! function_exists('app') || ! app()->bound('config')) {
        return $default;
    }

    return config($key, $default);
}

The container is consulted only once something is actually bound to it. Otherwise the documented default is returned, which is what the second argument to config() always looked like it was doing.

Inside a real application nothing changes: config is bound, the helper runs, published config values win exactly as before.

The trait lives next to ParsesCoordinates and is deliberately separate from KmlParser, because KmzExtractor needs the same thing as soon as temp_directory is implemented.

Tests

tests/StandaloneUsageTest.php swaps in a bare Illuminate\Container\Container with nothing bound, runs the parser, and restores the real application in a finally:

  • the parser can be constructed with no config repository bound
  • it parses a document and returns the placemarks
  • it falls back to the built-in namespace list, so a legacy earth.google.com/kml/2.1 document still loads
  • with an application present, a supported_namespaces value set in the config is still honoured, so the fallback did not replace the real lookup

The first three fail on main with BindingResolutionException. The fourth passes on both, and is there to prove the guard did not turn config reading off.

Suite 65 to 69. PHPStan and Pint clean.

Note

The function_exists() half of the guard cannot be exercised from this suite, since both helpers are always defined once testbench is loaded. It stays because the illuminate/contracts-only install is a real shape a consumer can end up in, and the check costs nothing.

The constructor called the config() helper directly. That helper does
not degrade when no application is running, it resolves 'config' out of
the container and throws BindingResolutionException, so `new KmlParser`
was fatal in a console script, a plain PHPUnit test, or anything else
outside a booted Laravel app. The package requires illuminate/contracts
rather than illuminate/support, so on a bare install the helper may not
even be defined.

Config is now read through packageConfig(), which consults the container
only once something is bound to it and otherwise returns the documented
default. Behaviour inside an application is unchanged.
@danielebarbaro
danielebarbaro merged commit 4bd3e46 into main Sep 8, 2026
19 checks passed
@danielebarbaro
danielebarbaro deleted the fix/config-outside-a-booted-app branch September 8, 2026 13:44
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.

1 participant