Skip to content

Commit abfd001

Browse files
committed
added DI extensions auto-discovery
1 parent a319abd commit abfd001

1 file changed

Lines changed: 101 additions & 1 deletion

File tree

src/Bootstrap/Configurator.php

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ class Configurator
6565
\Traversable::class,
6666
];
6767

68+
/** @var bool whether to auto-discover extensions from installed packages */
69+
public bool $autoDiscovery = true;
70+
71+
/** @var string[] extension names to exclude from auto-discovery */
72+
protected array $excludeExtensions = [];
73+
6874
protected array $staticParameters;
6975
protected array $dynamicParameters = [];
7076
protected array $services = [];
@@ -165,6 +171,26 @@ public function addServices(array $services): static
165171
}
166172

167173

174+
/**
175+
* Disables auto-discovery of extensions from installed packages.
176+
*/
177+
public function disableAutoDiscovery(): static
178+
{
179+
$this->autoDiscovery = false;
180+
return $this;
181+
}
182+
183+
184+
/**
185+
* Excludes specific extensions from auto-discovery.
186+
*/
187+
public function disableExtension(string ...$names): static
188+
{
189+
$this->excludeExtensions = array_merge($this->excludeExtensions, $names);
190+
return $this;
191+
}
192+
193+
168194
protected function getDefaultParameters(): array
169195
{
170196
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
@@ -244,6 +270,78 @@ public function addConfig(string|array $config): static
244270
}
245271

246272

273+
/**
274+
* Discovers extensions from installed Composer packages.
275+
* Reads extra.nette.di-extensions from vendor/composer/installed.json
276+
* @return array<string, string|array{class: class-string, args: array}>
277+
*/
278+
protected function discoverExtensions(): array
279+
{
280+
$vendorDir = $this->staticParameters['vendorDir'] ?? null;
281+
if (!$vendorDir) {
282+
return [];
283+
}
284+
285+
$installedJson = $vendorDir . '/composer/installed.json';
286+
if (!is_file($installedJson)) {
287+
return [];
288+
}
289+
290+
$installed = @json_decode(Nette\Utils\FileSystem::read($installedJson), true); // @ may not exist
291+
if (!$installed) {
292+
return [];
293+
}
294+
295+
$packages = $installed['packages'] ?? $installed; // Composer 2.x vs 1.x format
296+
$extensions = [];
297+
298+
foreach ($packages as $package) {
299+
$netteExtra = $package['extra']['nette'] ?? null;
300+
if (!$netteExtra || !isset($netteExtra['di-extensions'])) {
301+
continue;
302+
}
303+
304+
foreach ($netteExtra['di-extensions'] as $name => $definition) {
305+
// Normalize: string "Class" → ["class" => "Class", "args" => []]
306+
if (is_string($definition)) {
307+
$extensions[$name] = $definition;
308+
} else {
309+
$extensions[$name] = [
310+
$definition['class'],
311+
$definition['args'] ?? [],
312+
];
313+
}
314+
}
315+
}
316+
317+
return $extensions;
318+
}
319+
320+
321+
/**
322+
* Returns merged extensions (discovered + default, with excludes applied).
323+
* Default extensions take precedence over discovered ones.
324+
* @return array<string, string|array>
325+
*/
326+
protected function getExtensions(): array
327+
{
328+
if (!$this->autoDiscovery) {
329+
$extensions = $this->defaultExtensions;
330+
} else {
331+
// Discovered extensions first, then defaults override
332+
$discovered = $this->discoverExtensions();
333+
$extensions = array_merge($discovered, $this->defaultExtensions);
334+
}
335+
336+
// Remove excluded extensions
337+
foreach ($this->excludeExtensions as $name) {
338+
unset($extensions[$name]);
339+
}
340+
341+
return $extensions;
342+
}
343+
344+
247345
/**
248346
* Returns system DI container.
249347
*/
@@ -301,7 +399,7 @@ public function generateContainer(DI\Compiler $compiler): void
301399
$builder = $compiler->getContainerBuilder();
302400
$builder->addExcludedClasses($this->autowireExcludedClasses);
303401

304-
foreach ($this->defaultExtensions as $name => $extension) {
402+
foreach ($this->getExtensions() as $name => $extension) {
305403
[$class, $args] = is_string($extension)
306404
? [$extension, []]
307405
: $extension;
@@ -331,6 +429,8 @@ protected function generateContainerKey(): array
331429
class_exists(ClassLoader::class) // composer update
332430
? filemtime((new \ReflectionClass(ClassLoader::class))->getFilename())
333431
: null,
432+
$this->autoDiscovery,
433+
$this->excludeExtensions,
334434
];
335435
}
336436

0 commit comments

Comments
 (0)