@@ -79,6 +79,10 @@ class Configurator
7979 /** @var array<string, mixed> */
8080 private array $ defaultParameters ;
8181
82+ /** @var string[] extension names to exclude from auto-discovery */
83+ private array $ excludeExtensions = [];
84+ private bool $ autoDiscovery = true ;
85+
8286
8387 public function __construct ()
8488 {
@@ -173,6 +177,21 @@ public function addServices(array $services): static
173177 }
174178
175179
180+ /**
181+ * Disables auto-discovery of extensions from installed packages.
182+ * Without arguments disables completely, with arguments disables only specified extensions.
183+ */
184+ public function excludeExtension (string ...$ extensions ): static
185+ {
186+ if (count ($ extensions ) === 0 ) {
187+ $ this ->autoDiscovery = false ;
188+ } else {
189+ $ this ->excludeExtensions = array_merge ($ this ->excludeExtensions , $ extensions );
190+ }
191+ return $ this ;
192+ }
193+
194+
176195 /** @return array<string, mixed> */
177196 protected function getDefaultParameters (): array
178197 {
@@ -258,6 +277,30 @@ public function addConfig(string|array $config): static
258277 }
259278
260279
280+ /**
281+ * Discovers extensions from installed Composer packages.
282+ * Reads extra.nette.di-extensions from vendor/composer/installed.json
283+ * @return array<string, string|array{class: class-string, args: array}>
284+ */
285+ protected function discoverExtensions (): array
286+ {
287+ $ vendorDir = $ this ->staticParameters ['vendorDir ' ] ?? null ;
288+ if (!$ vendorDir || !is_file ($ installedJson = $ vendorDir . '/composer/installed.json ' )) {
289+ return [];
290+ }
291+
292+ $ installed = json_decode (Nette \Utils \FileSystem::read ($ installedJson ), true );
293+ $ extensions = [];
294+ foreach ($ installed ['packages ' ] ?? [] as $ package ) {
295+ foreach ($ package ['extra ' ]['nette ' ]['di-extensions ' ] ?? [] as $ name => $ def ) {
296+ $ extensions [$ name ] = is_string ($ def ) ? $ def : [$ def ['class ' ], $ def ['args ' ] ?? []];
297+ }
298+ }
299+
300+ return $ extensions ;
301+ }
302+
303+
261304 /**
262305 * Returns system DI container.
263306 */
@@ -319,7 +362,10 @@ public function generateContainer(DI\Compiler $compiler): void
319362 $ builder = $ compiler ->getContainerBuilder ();
320363 $ builder ->addExcludedClasses ($ this ->autowireExcludedClasses );
321364
322- foreach ($ this ->defaultExtensions as $ name => $ extension ) {
365+ $ extensions = $ this ->autoDiscovery ? $ this ->discoverExtensions () : [];
366+ $ extensions = array_merge ($ extensions , $ this ->defaultExtensions );
367+ $ extensions = array_diff_key ($ extensions , $ this ->excludeExtensions );
368+ foreach ($ extensions as $ name => $ extension ) {
323369 [$ class , $ args ] = is_string ($ extension )
324370 ? [$ extension , []]
325371 : $ extension ;
@@ -351,6 +397,7 @@ protected function generateContainerKey(): array
351397 class_exists (ClassLoader::class) // composer update
352398 ? filemtime ((new \ReflectionClass (ClassLoader::class))->getFilename ())
353399 : null ,
400+ $ this ->autoDiscovery ? $ this ->excludeExtensions : null ,
354401 ];
355402 }
356403
0 commit comments