44
55namespace Wunderio \GrumPHP \Drupal ;
66
7- use Drupal \Core \DependencyInjection \ContainerNotInitializedException ;
87use DrupalFinder \DrupalFinderComposerRuntime ;
98use Drush \Drush ;
109use mglaman \PHPStanDrupal \Drupal \Extension ;
1817 *
1918 * Code re-used from https://github.com/mglaman/phpstan-drupal/blob/main/src/Drupal/DrupalAutoloader.php.
2019 */
21- class DrupalAutoloader {
22-
23- /**
24- * Drupal autoloader.
25- *
26- * @var \Composer\Autoload\ClassLoader
27- */
28- private $ autoloader ;
29-
30- /**
31- * Path to Drupal root.
32- *
33- * @var string
34- */
35- private $ drupalRoot ;
36-
37- /**
38- * List of available modules.
39- *
40- * @var array
41- */
42- protected $ moduleData = [];
43-
44- /**
45- * List of available themes.
46- *
47- * @var array
48- */
49- protected $ themeData = [];
50-
51- /**
52- * Array of Drupal service mapping.
53- *
54- * @var array
55- */
56- private $ serviceMap = [];
57-
58- /**
59- * Array of Drupal service yml files.
60- *
61- * @var array
62- */
63- private $ serviceYamls = [];
64-
65- /**
66- * Array of service class providers.
67- *
68- * @var array
69- */
70- private $ serviceClassProviders = [];
71-
72- /**
73- * ExtensionDiscovery object.
74- *
75- * @var \mglaman\PHPStanDrupal\Drupal\ExtensionDiscovery
76- */
77- private $ extensionDiscovery ;
78-
79- /**
80- * Array of Drupal namespaces.
81- *
82- * @var array
83- */
84- private $ namespaces = [];
20+ class DrupalAutoloader extends DrupalAutoloaderBase {
8521
8622 /**
8723 * Load in Drupal code from defined path.
@@ -142,6 +78,32 @@ public function register(string $drupalRoot): void {
14278 }
14379 }
14480
81+ $ this ->registerIncludeModuleFiles ();
82+ $ this ->registerIncludeThemeFiles ();
83+
84+ if (class_exists (Drush::class)) {
85+ $ reflect = new \ReflectionClass (Drush::class);
86+ if ($ reflect ->getFileName () !== FALSE ) {
87+ $ levels = 2 ;
88+ if (Drush::getMajorVersion () < 9 ) {
89+ $ levels = 3 ;
90+ }
91+ $ drushDir = dirname ($ reflect ->getFileName (), $ levels );
92+ /** @var \SplFileInfo $file */
93+ foreach (Finder::findFiles ('*.inc ' )->in ($ drushDir . '/includes ' ) as $ file ) {
94+ // phpcs:ignore PHPCS_SecurityAudit.Misc.IncludeMismatch.ErrMiscIncludeMismatchNoExt
95+ require_once $ file ->getPathname ();
96+ }
97+ }
98+ }
99+
100+ $ this ->registerIncludeServicesFromYamls ();
101+ }
102+
103+ /**
104+ * Helper for register() method to include module files.
105+ */
106+ private function registerIncludeModuleFiles () {
145107 foreach ($ this ->moduleData as $ extension ) {
146108 $ this ->loadExtension ($ extension );
147109
@@ -176,6 +138,12 @@ public function register(string $drupalRoot): void {
176138 }
177139 }
178140 }
141+ }
142+
143+ /**
144+ * Helper for register() method to include theme files.
145+ */
146+ private function registerIncludeThemeFiles () {
179147 foreach ($ this ->themeData as $ extension ) {
180148 $ this ->loadExtension ($ extension );
181149 $ theme_dir = $ this ->drupalRoot . '/ ' . $ extension ->getPath ();
@@ -184,23 +152,14 @@ public function register(string $drupalRoot): void {
184152 $ this ->loadAndCatchErrors ($ theme_settings_file );
185153 }
186154 }
155+ }
187156
188- if (class_exists (Drush::class)) {
189- $ reflect = new \ReflectionClass (Drush::class);
190- if ($ reflect ->getFileName () !== FALSE ) {
191- $ levels = 2 ;
192- if (Drush::getMajorVersion () < 9 ) {
193- $ levels = 3 ;
194- }
195- $ drushDir = dirname ($ reflect ->getFileName (), $ levels );
196- /** @var \SplFileInfo $file */
197- foreach (Finder::findFiles ('*.inc ' )->in ($ drushDir . '/includes ' ) as $ file ) {
198- // phpcs:ignore PHPCS_SecurityAudit.Misc.IncludeMismatch.ErrMiscIncludeMismatchNoExt
199- require_once $ file ->getPathname ();
200- }
201- }
202- }
203-
157+ /**
158+ * Helper for register() method to include services.
159+ *
160+ * @todo Fix this method not being properly used - see https://github.com/wunderio/code-quality/issues/96 for more info.
161+ */
162+ private function registerIncludeServicesFromYamls () {
204163 foreach ($ this ->serviceYamls as $ extension => $ serviceYaml ) {
205164 $ yaml = Yaml::parseFile ($ serviceYaml );
206165 // Weed out service files which only provide parameters.
@@ -245,147 +204,4 @@ public function register(string $drupalRoot): void {
245204 }
246205 }
247206
248- /**
249- * Load legacy includes.
250- */
251- protected function loadLegacyIncludes (): void {
252- /** @var \SplFileInfo $file */
253- foreach (Finder::findFiles ('*.inc ' )->in ($ this ->drupalRoot . '/core/includes ' ) as $ file ) {
254- // phpcs:ignore PHPCS_SecurityAudit.Misc.IncludeMismatch.ErrMiscIncludeMismatchNoExt
255- require_once $ file ->getPathname ();
256- }
257- }
258-
259- /**
260- * Add core test namespaces.
261- */
262- protected function addTestNamespaces (): void {
263- $ core_tests_dir = $ this ->drupalRoot . '/core/tests/Drupal ' ;
264- $ this ->namespaces ['Drupal \\BuildTests ' ] = $ core_tests_dir . '/BuildTests ' ;
265- $ this ->namespaces ['Drupal \\FunctionalJavascriptTests ' ] = $ core_tests_dir . '/FunctionalJavascriptTests ' ;
266- $ this ->namespaces ['Drupal \\FunctionalTests ' ] = $ core_tests_dir . '/FunctionalTests ' ;
267- $ this ->namespaces ['Drupal \\KernelTests ' ] = $ core_tests_dir . '/KernelTests ' ;
268- $ this ->namespaces ['Drupal \\Tests ' ] = $ core_tests_dir . '/Tests ' ;
269- $ this ->namespaces ['Drupal \\TestSite ' ] = $ core_tests_dir . '/TestSite ' ;
270- $ this ->namespaces ['Drupal \\TestTools ' ] = $ core_tests_dir . '/TestTools ' ;
271- $ this ->namespaces ['Drupal \\Tests \\TestSuites ' ] = $ this ->drupalRoot . '/core/tests/TestSuites ' ;
272- }
273-
274- /**
275- * Add Drupal module namespaces.
276- */
277- protected function addModuleNamespaces (): void {
278- foreach ($ this ->moduleData as $ module ) {
279- $ module_name = $ module ->getName ();
280- $ module_dir = $ this ->drupalRoot . '/ ' . $ module ->getPath ();
281- $ this ->namespaces ["Drupal \\$ module_name " ] = $ module_dir . '/src ' ;
282-
283- // Extensions can have a \Drupal\Tests\extension namespace for test
284- // cases, traits, and other classes such
285- // as those that extend \Drupal\TestSite\TestSetupInterface.
286- // @see drupal_phpunit_get_extension_namespaces()
287- $ module_test_dir = $ module_dir . '/tests/src ' ;
288- if (is_dir ($ module_test_dir )) {
289- $ this ->namespaces ["Drupal \\Tests \\$ module_name " ] = $ module_test_dir ;
290- }
291-
292- $ servicesFileName = $ module_dir . '/ ' . $ module_name . '.services.yml ' ;
293- if (file_exists ($ servicesFileName )) {
294- $ this ->serviceYamls [$ module_name ] = $ servicesFileName ;
295- }
296- $ camelized = $ this ->camelize ($ module_name );
297- $ name = "{$ camelized }ServiceProvider " ;
298- $ class = "Drupal \\{$ module_name }\\{$ name }" ;
299-
300- $ this ->serviceClassProviders [$ module_name ] = $ class ;
301- $ serviceId = "service_provider. $ module_name.service_provider " ;
302- $ this ->serviceMap [$ serviceId ] = ['class ' => $ class ];
303- }
304- }
305-
306- /**
307- * Add Drupal theme namespaces.
308- */
309- protected function addThemeNamespaces (): void {
310- foreach ($ this ->themeData as $ theme_name => $ theme ) {
311- $ theme_dir = $ this ->drupalRoot . '/ ' . $ theme ->getPath ();
312- $ this ->namespaces ["Drupal \\$ theme_name " ] = $ theme_dir . '/src ' ;
313- }
314- }
315-
316- /**
317- * Register PS4 namespaces.
318- *
319- * @param array $namespaces
320- * An array of namespaces to load.
321- */
322- protected function registerPs4Namespaces (array $ namespaces ): void {
323- foreach ($ namespaces as $ prefix => $ paths ) {
324- if (is_array ($ paths )) {
325- foreach ($ paths as $ key => $ value ) {
326- $ paths [$ key ] = $ value ;
327- }
328- }
329- $ this ->autoloader ->addPsr4 ($ prefix . '\\' , $ paths );
330- }
331- }
332-
333- /**
334- * Loads in extensions (modules, themes, etc).
335- *
336- * Wrapper for \mglaman\PHPStanDrupal\Drupal\Extension->load().
337- *
338- * @param \mglaman\PHPStanDrupal\Drupal\Extension $extension
339- * Extension object.
340- */
341- protected function loadExtension (Extension $ extension ): void {
342- try {
343- $ extension ->load ();
344- }
345- catch (\Throwable $ e ) {
346- // Something prevented the extension file from loading.
347- // This can happen when drupal_get_path or drupal_get_filename are used
348- // outside the scope of a function.
349- }
350- }
351-
352- /**
353- * Wrapper for require_once() that catches errors.
354- *
355- * @param string $path
356- * Path to file.
357- */
358- protected function loadAndCatchErrors (string $ path ): void {
359- try {
360- // phpcs:ignore PHPCS_SecurityAudit.Misc.IncludeMismatch.ErrMiscIncludeMismatchNoExt
361- require_once $ path ;
362- }
363- catch (ContainerNotInitializedException $ e ) {
364- $ path = str_replace (dirname ($ this ->drupalRoot ) . '/ ' , '' , $ path );
365- // This can happen when drupal_get_path or drupal_get_filename are used
366- // outside the scope of a function.
367- @trigger_error ("$ path invoked the Drupal container outside of the scope of a function or class method. It was not loaded. " , E_USER_WARNING );
368- }
369- catch (\Throwable $ e ) {
370- $ path = str_replace (dirname ($ this ->drupalRoot ) . '/ ' , '' , $ path );
371- // Something prevented the extension file from loading.
372- @trigger_error ("$ path failed loading due to {$ e ->getMessage ()}" , E_USER_WARNING );
373- }
374- }
375-
376- /**
377- * Camelizes a string.
378- *
379- * @todo Should we use method from Symfony\Component\DependencyInjection\Container instead?
380- *
381- * @param string $id
382- * A string to camelize.
383- *
384- * @return string
385- * The camelized string.
386- */
387- protected function camelize (string $ id ): string {
388- return strtr (ucwords (strtr ($ id , ['_ ' => ' ' , '. ' => '_ ' , '\\' => '_ ' ])), [' ' => '' ]);
389- }
390-
391207}
0 commit comments