55namespace Wunderio \GrumPHP \Drupal ;
66
77use DrupalFinder \DrupalFinder ;
8- use Drupal \Core \DependencyInjection \ContainerNotInitializedException ;
98use Drush \Drush ;
109use Nette \Utils \Finder ;
1110use PHPUnit \Framework \Test ;
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.
@@ -143,6 +79,32 @@ public function register(string $drupalRoot): void {
14379 }
14480 }
14581
82+ $ this ->registerIncludeModuleFiles ();
83+ $ this ->registerIncludeThemeFiles ();
84+
85+ if (class_exists (Drush::class)) {
86+ $ reflect = new \ReflectionClass (Drush::class);
87+ if ($ reflect ->getFileName () !== FALSE ) {
88+ $ levels = 2 ;
89+ if (Drush::getMajorVersion () < 9 ) {
90+ $ levels = 3 ;
91+ }
92+ $ drushDir = dirname ($ reflect ->getFileName (), $ levels );
93+ /** @var \SplFileInfo $file */
94+ foreach (Finder::findFiles ('*.inc ' )->in ($ drushDir . '/includes ' ) as $ file ) {
95+ // phpcs:ignore PHPCS_SecurityAudit.Misc.IncludeMismatch.ErrMiscIncludeMismatchNoExt
96+ require_once $ file ->getPathname ();
97+ }
98+ }
99+ }
100+
101+ $ this ->registerIncludeServicesFromYamls ();
102+ }
103+
104+ /**
105+ * Helper for register() method to include module files.
106+ */
107+ private function registerIncludeModuleFiles () {
146108 foreach ($ this ->moduleData as $ extension ) {
147109 $ this ->loadExtension ($ extension );
148110
@@ -177,6 +139,12 @@ public function register(string $drupalRoot): void {
177139 }
178140 }
179141 }
142+ }
143+
144+ /**
145+ * Helper for register() method to include theme files.
146+ */
147+ private function registerIncludeThemeFiles () {
180148 foreach ($ this ->themeData as $ extension ) {
181149 $ this ->loadExtension ($ extension );
182150 $ theme_dir = $ this ->drupalRoot . '/ ' . $ extension ->getPath ();
@@ -185,23 +153,14 @@ public function register(string $drupalRoot): void {
185153 $ this ->loadAndCatchErrors ($ theme_settings_file );
186154 }
187155 }
156+ }
188157
189- if (class_exists (Drush::class)) {
190- $ reflect = new \ReflectionClass (Drush::class);
191- if ($ reflect ->getFileName () !== FALSE ) {
192- $ levels = 2 ;
193- if (Drush::getMajorVersion () < 9 ) {
194- $ levels = 3 ;
195- }
196- $ drushDir = dirname ($ reflect ->getFileName (), $ levels );
197- /** @var \SplFileInfo $file */
198- foreach (Finder::findFiles ('*.inc ' )->in ($ drushDir . '/includes ' ) as $ file ) {
199- // phpcs:ignore PHPCS_SecurityAudit.Misc.IncludeMismatch.ErrMiscIncludeMismatchNoExt
200- require_once $ file ->getPathname ();
201- }
202- }
203- }
204-
158+ /**
159+ * Helper for register() method to include services.
160+ *
161+ * @todo Fix this method not being properly used - see https://github.com/wunderio/code-quality/issues/96 for more info.
162+ */
163+ private function registerIncludeServicesFromYamls () {
205164 foreach ($ this ->serviceYamls as $ extension => $ serviceYaml ) {
206165 $ yaml = Yaml::parseFile ($ serviceYaml );
207166 // Weed out service files which only provide parameters.
@@ -246,147 +205,4 @@ public function register(string $drupalRoot): void {
246205 }
247206 }
248207
249- /**
250- * Load legacy includes.
251- */
252- protected function loadLegacyIncludes (): void {
253- /** @var \SplFileInfo $file */
254- foreach (Finder::findFiles ('*.inc ' )->in ($ this ->drupalRoot . '/core/includes ' ) as $ file ) {
255- // phpcs:ignore PHPCS_SecurityAudit.Misc.IncludeMismatch.ErrMiscIncludeMismatchNoExt
256- require_once $ file ->getPathname ();
257- }
258- }
259-
260- /**
261- * Add core test namespaces.
262- */
263- protected function addTestNamespaces (): void {
264- $ core_tests_dir = $ this ->drupalRoot . '/core/tests/Drupal ' ;
265- $ this ->namespaces ['Drupal \\BuildTests ' ] = $ core_tests_dir . '/BuildTests ' ;
266- $ this ->namespaces ['Drupal \\FunctionalJavascriptTests ' ] = $ core_tests_dir . '/FunctionalJavascriptTests ' ;
267- $ this ->namespaces ['Drupal \\FunctionalTests ' ] = $ core_tests_dir . '/FunctionalTests ' ;
268- $ this ->namespaces ['Drupal \\KernelTests ' ] = $ core_tests_dir . '/KernelTests ' ;
269- $ this ->namespaces ['Drupal \\Tests ' ] = $ core_tests_dir . '/Tests ' ;
270- $ this ->namespaces ['Drupal \\TestSite ' ] = $ core_tests_dir . '/TestSite ' ;
271- $ this ->namespaces ['Drupal \\TestTools ' ] = $ core_tests_dir . '/TestTools ' ;
272- $ this ->namespaces ['Drupal \\Tests \\TestSuites ' ] = $ this ->drupalRoot . '/core/tests/TestSuites ' ;
273- }
274-
275- /**
276- * Add Drupal module namespaces.
277- */
278- protected function addModuleNamespaces (): void {
279- foreach ($ this ->moduleData as $ module ) {
280- $ module_name = $ module ->getName ();
281- $ module_dir = $ this ->drupalRoot . '/ ' . $ module ->getPath ();
282- $ this ->namespaces ["Drupal \\$ module_name " ] = $ module_dir . '/src ' ;
283-
284- // Extensions can have a \Drupal\Tests\extension namespace for test
285- // cases, traits, and other classes such
286- // as those that extend \Drupal\TestSite\TestSetupInterface.
287- // @see drupal_phpunit_get_extension_namespaces()
288- $ module_test_dir = $ module_dir . '/tests/src ' ;
289- if (is_dir ($ module_test_dir )) {
290- $ this ->namespaces ["Drupal \\Tests \\$ module_name " ] = $ module_test_dir ;
291- }
292-
293- $ servicesFileName = $ module_dir . '/ ' . $ module_name . '.services.yml ' ;
294- if (file_exists ($ servicesFileName )) {
295- $ this ->serviceYamls [$ module_name ] = $ servicesFileName ;
296- }
297- $ camelized = $ this ->camelize ($ module_name );
298- $ name = "{$ camelized }ServiceProvider " ;
299- $ class = "Drupal \\{$ module_name }\\{$ name }" ;
300-
301- $ this ->serviceClassProviders [$ module_name ] = $ class ;
302- $ serviceId = "service_provider. $ module_name.service_provider " ;
303- $ this ->serviceMap [$ serviceId ] = ['class ' => $ class ];
304- }
305- }
306-
307- /**
308- * Add Drupal theme namespaces.
309- */
310- protected function addThemeNamespaces (): void {
311- foreach ($ this ->themeData as $ theme_name => $ theme ) {
312- $ theme_dir = $ this ->drupalRoot . '/ ' . $ theme ->getPath ();
313- $ this ->namespaces ["Drupal \\$ theme_name " ] = $ theme_dir . '/src ' ;
314- }
315- }
316-
317- /**
318- * Register PS4 namespaces.
319- *
320- * @param array $namespaces
321- * An array of namespaces to load.
322- */
323- protected function registerPs4Namespaces (array $ namespaces ): void {
324- foreach ($ namespaces as $ prefix => $ paths ) {
325- if (is_array ($ paths )) {
326- foreach ($ paths as $ key => $ value ) {
327- $ paths [$ key ] = $ value ;
328- }
329- }
330- $ this ->autoloader ->addPsr4 ($ prefix . '\\' , $ paths );
331- }
332- }
333-
334- /**
335- * Loads in extensions (modules, themes, etc).
336- *
337- * Wrapper for \mglaman\PHPStanDrupal\Drupal\Extension->load().
338- *
339- * @param \mglaman\PHPStanDrupal\Drupal\Extension $extension
340- * Extension object.
341- */
342- protected function loadExtension (Extension $ extension ): void {
343- try {
344- $ extension ->load ();
345- }
346- catch (\Throwable $ e ) {
347- // Something prevented the extension file from loading.
348- // This can happen when drupal_get_path or drupal_get_filename are used
349- // outside the scope of a function.
350- }
351- }
352-
353- /**
354- * Wrapper for require_once() that catches errors.
355- *
356- * @param string $path
357- * Path to file.
358- */
359- protected function loadAndCatchErrors (string $ path ): void {
360- try {
361- // phpcs:ignore PHPCS_SecurityAudit.Misc.IncludeMismatch.ErrMiscIncludeMismatchNoExt
362- require_once $ path ;
363- }
364- catch (ContainerNotInitializedException $ e ) {
365- $ path = str_replace (dirname ($ this ->drupalRoot ) . '/ ' , '' , $ path );
366- // This can happen when drupal_get_path or drupal_get_filename are used
367- // outside the scope of a function.
368- @trigger_error ("$ path invoked the Drupal container outside of the scope of a function or class method. It was not loaded. " , E_USER_WARNING );
369- }
370- catch (\Throwable $ e ) {
371- $ path = str_replace (dirname ($ this ->drupalRoot ) . '/ ' , '' , $ path );
372- // Something prevented the extension file from loading.
373- @trigger_error ("$ path failed loading due to {$ e ->getMessage ()}" , E_USER_WARNING );
374- }
375- }
376-
377- /**
378- * Camelizes a string.
379- *
380- * @todo Should we use method from Symfony\Component\DependencyInjection\Container instead?
381- *
382- * @param string $id
383- * A string to camelize.
384- *
385- * @return string
386- * The camelized string.
387- */
388- protected function camelize (string $ id ): string {
389- return strtr (ucwords (strtr ($ id , ['_ ' => ' ' , '. ' => '_ ' , '\\' => '_ ' ])), [' ' => '' ]);
390- }
391-
392208}
0 commit comments