Skip to content

Commit f2cbb22

Browse files
committed
Move from bootstrap file to extension.
Moving to an extension makes it possible to add information to the container, unblocking more advanced features.
1 parent 4d3ec18 commit f2cbb22

File tree

2 files changed

+101
-102
lines changed

2 files changed

+101
-102
lines changed

extension.neon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
parameters:
22
excludes_analyse:
33
- *.api.php
4-
bootstrap: %rootDir%/../../mglaman/phpstan-drupal/phpstan-bootstrap.php
54
fileExtensions:
65
- php
76
- module
87
- theme
98
- inc
109
extensions:
1110
rulesOverride: PHPStan\DependencyInjection\RulesOverrideExtension
11+
drupal: PHPStan\DependencyInjection\DrupalExtension
1212
rules:
1313
- PHPStan\Rules\Classes\PluginManagerInspectionRule
1414
- PHPStan\Rules\Drupal\Coder\DiscouragedFunctionsRule
Lines changed: 100 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
<?php declare(strict_types=1);
22

3-
namespace PHPStan\Drupal;
3+
namespace PHPStan\DependencyInjection;
44

55
use Composer\Autoload\ClassLoader;
6+
use Nette\DI\CompilerExtension;
7+
use Nette\DI\Config\Helpers;
8+
use Nette\Utils\Finder;
9+
use PHPStan\Drupal\Extension;
10+
use PHPStan\Drupal\ExtensionDiscovery;
611

7-
class Bootstrap
12+
class DrupalExtension extends CompilerExtension
813
{
914

15+
protected $defaultConfig = [
16+
'modules' => [],
17+
'themes' => [],
18+
];
19+
20+
private $autoloaderPath;
21+
1022
/**
1123
* @var \Composer\Autoload\ClassLoader
1224
*/
@@ -18,30 +30,33 @@ class Bootstrap
1830
private $drupalRoot;
1931

2032
/**
21-
* @var \PHPStan\Drupal\ExtensionDiscovery
33+
* List of available modules.
34+
*
35+
* @var \PHPStan\Drupal\Extension[]
2236
*/
23-
private $extensionDiscovery;
37+
protected $moduleData = [];
2438

2539
/**
26-
* @var array
40+
* List of available themes.
41+
*
42+
* @var \PHPStan\Drupal\Extension[]
2743
*/
28-
private $modules = [];
44+
protected $themeData = [];
2945

30-
/**
31-
* @var array
32-
*/
46+
private $modules = [];
3347
private $themes = [];
48+
private $extensionDiscovery;
3449

35-
public function __construct()
50+
public function loadConfiguration(): void
3651
{
37-
$autoload_file = $GLOBALS['autoloaderInWorkingDirectory'];
52+
53+
$this->autoloaderPath = $GLOBALS['autoloaderInWorkingDirectory'];
3854
/** @noinspection PhpIncludeInspection */
39-
$this->autoloader = require $autoload_file;
55+
$this->autoloader = require $this->autoloaderPath;
4056
if (!$this->autoloader instanceof ClassLoader) {
4157
throw new \InvalidArgumentException('Unable to determine the Composer class loader for Drupal');
4258
}
43-
44-
$realpath = realpath($autoload_file);
59+
$realpath = realpath($this->autoloaderPath);
4560
if ($realpath === false) {
4661
throw new \InvalidArgumentException('Cannot determine the realpath of the autoloader.');
4762
}
@@ -57,10 +72,15 @@ public function __construct()
5772
if ($this->drupalRoot === null) {
5873
throw new \InvalidArgumentException('Unable to determine the Drupal root');
5974
}
60-
}
6175

62-
public function register(): void
63-
{
76+
$builder = $this->getContainerBuilder();
77+
$builder->parameters['drupalRoot'] = $this->drupalRoot;
78+
79+
$config = Helpers::merge($this->config, $this->defaultConfig);
80+
81+
$this->modules = $config['modules'] ?? [];
82+
$this->themes = $config['themes'] ?? [];
83+
6484
$this->extensionDiscovery = new ExtensionDiscovery($this->drupalRoot);
6585
$this->extensionDiscovery->setProfileDirectories([]);
6686
$profiles = $this->extensionDiscovery->scan('profile');
@@ -69,48 +89,52 @@ public function register(): void
6989
}, $profiles);
7090
$this->extensionDiscovery->setProfileDirectories($profile_directories);
7191

72-
$this->modules = $this->extensionDiscovery->scan('module');
73-
$this->themes = $this->extensionDiscovery->scan('theme');
92+
$this->moduleData = $this->extensionDiscovery->scan('module');
93+
$this->themeData = $this->extensionDiscovery->scan('theme');
7494

75-
require $this->drupalRoot . '/core/includes/bootstrap.inc';
76-
require $this->drupalRoot . '/core/includes/common.inc';
77-
require $this->drupalRoot . '/core/includes/entity.inc';
78-
require $this->drupalRoot . '/core/includes/menu.inc';
79-
require $this->drupalRoot . '/core/includes/database.inc';
80-
require $this->drupalRoot . '/core/includes/file.inc';
81-
$core_namespaces = $this->getCoreNamespaces();
82-
$module_namespaces = $this->getModuleNamespaces();
83-
$theme_namespaces = $this->getThemeNamespaces();
95+
$this->loadLegacyIncludes();
8496

85-
$namespaces = array_merge($core_namespaces, $module_namespaces, $theme_namespaces);
97+
$this->addCoreNamespaces();
98+
$this->addModuleNamespaces();
99+
$this->addThemeNamespaces();
86100

87-
foreach ($namespaces as $prefix => $paths) {
88-
if (is_array($paths)) {
89-
foreach ($paths as $key => $value) {
90-
$paths[$key] = $value;
101+
foreach ($this->moduleData as $extension) {
102+
$this->loadExtension($extension);
103+
104+
$module_name = $extension->getName();
105+
$module_dir = $this->drupalRoot . '/' . $extension->getPath();
106+
// Add .post_update.php
107+
if (file_exists($module_dir . '/' . $module_name . '.post_update.php')) {
108+
require $module_dir . '/' . $module_name . '.post_update.php';
109+
}
110+
// Add misc .inc that are magically allowed via hook_hook_info.
111+
$magic_hook_info_includes = [
112+
'views',
113+
'views_execution',
114+
'tokens',
115+
'search_api',
116+
'pathauto',
117+
];
118+
foreach ($magic_hook_info_includes as $hook_info_include) {
119+
if (file_exists($module_dir . "/$module_name.$hook_info_include.inc")) {
120+
require $module_dir . "/$module_name.$hook_info_include.inc";
91121
}
92122
}
93-
$this->autoloader->addPsr4($prefix . '\\', $paths);
94123
}
124+
foreach ($this->themeData as $extension) {
125+
$this->loadExtension($extension);
126+
}
127+
}
95128

96-
// Add core test namespaces.
97-
$core_tests_dir = $this->drupalRoot . '/core/tests';
98-
$this->autoloader->add('Drupal\\Tests', $core_tests_dir);
99-
$this->autoloader->add('Drupal\\TestSite', $core_tests_dir);
100-
$this->autoloader->add('Drupal\\KernelTests', $core_tests_dir);
101-
$this->autoloader->add('Drupal\\FunctionalTests', $core_tests_dir);
102-
$this->autoloader->add('Drupal\\FunctionalJavascriptTests', $core_tests_dir);
103-
104-
$this->loadModules();
105-
$this->loadThemes();
129+
protected function loadLegacyIncludes(): void
130+
{
131+
/** @var \SplFileInfo $file */
132+
foreach (Finder::findFiles('*.inc')->in($this->drupalRoot . '/core/includes') as $file) {
133+
require $file->getPathname();
134+
}
106135
}
107136

108-
/**
109-
* @return array
110-
*
111-
* @see \Drupal\Core\DrupalKernel::compileContainer
112-
*/
113-
protected function getCoreNamespaces(): array
137+
protected function addCoreNamespaces(): void
114138
{
115139
$namespaces = [];
116140
foreach (['Core', 'Component'] as $parent_directory) {
@@ -127,14 +151,20 @@ protected function getCoreNamespaces(): array
127151
}
128152
}
129153
}
154+
$this->registerPs4Namespaces($namespaces);
130155

131-
return $namespaces;
156+
// Add core test namespaces.
157+
$core_tests_dir = $this->drupalRoot . '/core/tests';
158+
$this->autoloader->add('Drupal\\Tests', $core_tests_dir);
159+
$this->autoloader->add('Drupal\\TestSite', $core_tests_dir);
160+
$this->autoloader->add('Drupal\\KernelTests', $core_tests_dir);
161+
$this->autoloader->add('Drupal\\FunctionalTests', $core_tests_dir);
162+
$this->autoloader->add('Drupal\\FunctionalJavascriptTests', $core_tests_dir);
132163
}
133-
134-
protected function getModuleNamespaces(): array
164+
protected function addModuleNamespaces(): void
135165
{
136166
$namespaces = [];
137-
foreach ($this->modules as $module_name => $module) {
167+
foreach ($this->moduleData as $module_name => $module) {
138168
$module_dir = $this->drupalRoot . '/' . $module->getPath();
139169
$namespaces["Drupal\\$module_name"] = $module_dir . '/src';
140170

@@ -158,67 +188,36 @@ protected function getModuleNamespaces(): array
158188
}
159189
}
160190
}
161-
162-
return $namespaces;
191+
$this->registerPs4Namespaces($namespaces);
163192
}
164-
165-
protected function getThemeNamespaces(): array
193+
protected function addThemeNamespaces(): void
166194
{
167195
$namespaces = [];
168-
foreach ($this->themes as $theme_name => $theme) {
196+
foreach ($this->themeData as $theme_name => $theme) {
169197
$theme_dir = $this->drupalRoot . '/' . $theme->getPath();
170198
$namespaces["Drupal\\$theme_name"] = $theme_dir . '/src';
171199
}
172-
return $namespaces;
200+
$this->registerPs4Namespaces($namespaces);
173201
}
174202

175-
protected function loadModules(): void
203+
protected function registerPs4Namespaces(array $namespaces): void
176204
{
177-
foreach ($this->modules as $module_name => $module) {
178-
$module_dir = $this->drupalRoot . '/' . $module->getPath();
179-
// Need to ensure .module is enabled.
180-
if ($module->getExtensionFilename() !== null) {
181-
try {
182-
require $module_dir . '/' . $module->getExtensionFilename();
183-
} catch (\Throwable $e) {
184-
// Something prevent the extension file from loading.
185-
}
186-
}
187-
// Add .post_update.php
188-
if (file_exists($module_dir . '/' . $module_name . '.post_update.php')) {
189-
require $module_dir . '/' . $module_name . '.post_update.php';
190-
}
191-
// Add misc .inc that are magically allowed via hook_hook_info.
192-
$magic_hook_info_includes = [
193-
'views',
194-
'views_execution',
195-
'tokens',
196-
'search_api',
197-
'pathauto',
198-
];
199-
foreach ($magic_hook_info_includes as $hook_info_include) {
200-
if (file_exists($module_dir . "/$module_name.$hook_info_include.inc")) {
201-
require $module_dir . "/$module_name.$hook_info_include.inc";
205+
foreach ($namespaces as $prefix => $paths) {
206+
if (is_array($paths)) {
207+
foreach ($paths as $key => $value) {
208+
$paths[$key] = $value;
202209
}
203210
}
211+
$this->autoloader->addPsr4($prefix . '\\', $paths);
204212
}
205213
}
206-
207-
protected function loadThemes(): void
214+
protected function loadExtension(Extension $extension): void
208215
{
209-
foreach ($this->themes as $theme_name => $theme) {
210-
if ($theme_name === 'bootstrap') {
211-
continue;
212-
}
213-
$theme_dir = $this->drupalRoot . '/' . $theme->getPath();
214-
// Need to ensure .theme is enabled.
215-
if ($theme->getExtensionFilename() !== null) {
216-
try {
217-
require $theme_dir . '/' . $theme->getExtensionFilename();
218-
} catch (\Throwable $e) {
219-
// Something prevent the extension file from loading.
220-
}
221-
}
216+
try {
217+
$extension->load();
218+
} catch (\Throwable $e) {
219+
// Something prevented the extension file from loading.
220+
// This can happen when drupal_get_path or drupal_get_filename are used outside of the scope of a function.
222221
}
223222
}
224223
}

0 commit comments

Comments
 (0)