Skip to content

Commit 4bd3e46

Browse files
fix(parser): work without a booted application
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.
1 parent 93809bc commit 4bd3e46

3 files changed

Lines changed: 109 additions & 2 deletions

File tree

src/KmlParser.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66
use PlinCode\KmlParser\Enums\GeometryType;
77
use PlinCode\KmlParser\Exceptions\KmlParserException;
88
use PlinCode\KmlParser\Traits\ParsesCoordinates;
9+
use PlinCode\KmlParser\Traits\ReadsPackageConfig;
910
use PlinCode\KmlParser\Validators\KmlValidator;
1011
use SimpleXMLElement;
1112

1213
class KmlParser
1314
{
1415
use ParsesCoordinates;
16+
use ReadsPackageConfig;
1517

1618
protected ?SimpleXMLElement $xml = null;
1719

@@ -21,7 +23,7 @@ class KmlParser
2123

2224
public function __construct()
2325
{
24-
$this->namespace = config('kml-parser.namespace', $this->namespace);
26+
$this->namespace = $this->packageConfig('kml-parser.namespace', $this->namespace);
2527
$this->validator = new KmlValidator($this->supportedNamespaces());
2628
}
2729

@@ -33,7 +35,7 @@ public function __construct()
3335
*/
3436
protected function supportedNamespaces(): array
3537
{
36-
$supported = config('kml-parser.supported_namespaces', KmlValidator::DEFAULT_NAMESPACES);
38+
$supported = $this->packageConfig('kml-parser.supported_namespaces', KmlValidator::DEFAULT_NAMESPACES);
3739

3840
return array_values(array_unique(array_merge([$this->namespace], (array) $supported)));
3941
}

src/Traits/ReadsPackageConfig.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace PlinCode\KmlParser\Traits;
4+
5+
trait ReadsPackageConfig
6+
{
7+
/**
8+
* Read a package config value, falling back when there is no application.
9+
*
10+
* The parser and the extractor are both useful outside a booted Laravel
11+
* application: a console script, a plain PHPUnit test, a queue bootstrap
12+
* that has not resolved the config repository yet. The config() helper
13+
* does not degrade there, it throws BindingResolutionException, so the
14+
* container is only consulted once something is actually bound to it.
15+
*/
16+
protected function packageConfig(string $key, mixed $default): mixed
17+
{
18+
if (! function_exists('config') || ! function_exists('app') || ! app()->bound('config')) {
19+
return $default;
20+
}
21+
22+
return config($key, $default);
23+
}
24+
}

tests/StandaloneUsageTest.php

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<?php
2+
3+
use Illuminate\Container\Container;
4+
use PlinCode\KmlParser\KmlParser;
5+
6+
function withoutBoundConfig(callable $callback): mixed
7+
{
8+
$application = Container::getInstance();
9+
10+
Container::setInstance(new Container);
11+
12+
try {
13+
return $callback();
14+
} finally {
15+
Container::setInstance($application);
16+
}
17+
}
18+
19+
$kml = <<<'XML'
20+
<?xml version="1.0" encoding="UTF-8"?>
21+
<kml xmlns="http://www.opengis.net/kml/2.2">
22+
<Document>
23+
<name>Standalone</name>
24+
<Placemark>
25+
<name>Lago Blu</name>
26+
<Point>
27+
<coordinates>7.7300965,45.8635629,0</coordinates>
28+
</Point>
29+
</Placemark>
30+
</Document>
31+
</kml>
32+
XML;
33+
34+
it('can be constructed with no config repository bound', function () {
35+
expect(withoutBoundConfig(fn () => new KmlParser))->toBeInstanceOf(KmlParser::class);
36+
});
37+
38+
it('parses with no config repository bound', function () use ($kml) {
39+
$placemarks = withoutBoundConfig(fn () => (new KmlParser)->loadFromString($kml)->getPlacemarks());
40+
41+
expect($placemarks)->toHaveCount(1)
42+
->and($placemarks[0]['name'])->toBe('Lago Blu');
43+
});
44+
45+
it('falls back to the default namespaces with no config repository bound', function () {
46+
$legacy = <<<'XML'
47+
<?xml version="1.0" encoding="UTF-8"?>
48+
<kml xmlns="http://earth.google.com/kml/2.1">
49+
<Document>
50+
<Placemark>
51+
<Point>
52+
<coordinates>7.7,45.8,0</coordinates>
53+
</Point>
54+
</Placemark>
55+
</Document>
56+
</kml>
57+
XML;
58+
59+
$placemarks = withoutBoundConfig(fn () => (new KmlParser)->loadFromString($legacy)->getPlacemarks());
60+
61+
expect($placemarks)->toHaveCount(1);
62+
});
63+
64+
it('still reads the config when the application provides one', function () {
65+
config()->set('kml-parser.supported_namespaces', ['http://example.test/kml']);
66+
67+
$kml = str_replace('http://www.opengis.net/kml/2.2', 'http://example.test/kml', <<<'XML'
68+
<?xml version="1.0" encoding="UTF-8"?>
69+
<kml xmlns="http://www.opengis.net/kml/2.2">
70+
<Document>
71+
<Placemark>
72+
<Point>
73+
<coordinates>7.7,45.8,0</coordinates>
74+
</Point>
75+
</Placemark>
76+
</Document>
77+
</kml>
78+
XML);
79+
80+
expect((new KmlParser)->loadFromString($kml)->getPlacemarks())->toHaveCount(1);
81+
});

0 commit comments

Comments
 (0)