@@ -78,6 +78,10 @@ class Configurator
7878 /** @var list<string|array<string, mixed>> */
7979 protected array $ configs = [];
8080
81+ /** @var string[] extension names to exclude from auto-discovery */
82+ private array $ excludeExtensions = [];
83+ private bool $ autoDiscovery = true ;
84+
8185
8286 public function __construct ()
8387 {
@@ -175,6 +179,21 @@ public function addServices(array $services): static
175179 }
176180
177181
182+ /**
183+ * Disables auto-discovery of extensions from installed packages.
184+ * Without arguments disables completely, with arguments disables only specified extensions.
185+ */
186+ public function excludeExtension (string ...$ extensions ): static
187+ {
188+ if (count ($ extensions ) === 0 ) {
189+ $ this ->autoDiscovery = false ;
190+ } else {
191+ $ this ->excludeExtensions = array_merge ($ this ->excludeExtensions , $ extensions );
192+ }
193+ return $ this ;
194+ }
195+
196+
178197 protected function getDefaultParameters (): array
179198 {
180199 $ trace = debug_backtrace (DEBUG_BACKTRACE_IGNORE_ARGS );
@@ -255,6 +274,30 @@ public function addConfig(string|array $config): static
255274 }
256275
257276
277+ /**
278+ * Discovers extensions from installed Composer packages.
279+ * Reads extra.nette.di-extensions from vendor/composer/installed.json
280+ * @return array<string, string|array{class: class-string, args: array}>
281+ */
282+ protected function discoverExtensions (): array
283+ {
284+ $ vendorDir = $ this ->staticParameters ['vendorDir ' ] ?? null ;
285+ if (!$ vendorDir || !is_file ($ installedJson = $ vendorDir . '/composer/installed.json ' )) {
286+ return [];
287+ }
288+
289+ $ installed = json_decode (Nette \Utils \FileSystem::read ($ installedJson ), true );
290+ $ extensions = [];
291+ foreach ($ installed ['packages ' ] ?? [] as $ package ) {
292+ foreach ($ package ['extra ' ]['nette ' ]['di-extensions ' ] ?? [] as $ name => $ def ) {
293+ $ extensions [$ name ] = is_string ($ def ) ? $ def : [$ def ['class ' ], $ def ['args ' ] ?? []];
294+ }
295+ }
296+
297+ return $ extensions ;
298+ }
299+
300+
258301 /**
259302 * Returns system DI container.
260303 */
@@ -312,7 +355,10 @@ public function generateContainer(DI\Compiler $compiler): void
312355 $ builder = $ compiler ->getContainerBuilder ();
313356 $ builder ->addExcludedClasses ($ this ->autowireExcludedClasses );
314357
315- foreach ($ this ->defaultExtensions as $ name => $ extension ) {
358+ $ extensions = $ this ->autoDiscovery ? $ this ->discoverExtensions () : [];
359+ $ extensions = array_merge ($ extensions , $ this ->defaultExtensions );
360+ $ extensions = array_diff_key ($ extensions , $ this ->excludeExtensions );
361+ foreach ($ extensions as $ name => $ extension ) {
316362 [$ class , $ args ] = is_string ($ extension )
317363 ? [$ extension , []]
318364 : $ extension ;
@@ -342,6 +388,7 @@ protected function generateContainerKey(): array
342388 class_exists (ClassLoader::class) // composer update
343389 ? filemtime ((new \ReflectionClass (ClassLoader::class))->getFilename ())
344390 : null ,
391+ $ this ->autoDiscovery ? $ this ->excludeExtensions : null ,
345392 ];
346393 }
347394
0 commit comments