1+ <?php
2+
3+ namespace Drush \Commands \core_development ;
4+
5+ use Consolidation \AnnotatedCommand \AnnotationData ;
6+ use Drupal \Core \DrupalKernel ;
7+ use Drupal \Core \Site \Settings ;
8+ use Drush \Commands \core \CacheCommands ;
9+ use Drush \Drush ;
10+ use Symfony \Component \Console \Command \Command ;
11+ use Symfony \Component \Console \Input \ArgvInput ;
12+ use Symfony \Component \Console \Input \InputInterface ;
13+ use Symfony \Component \HttpFoundation \Request ;
14+
15+ /**
16+ * Replaces the cache:rebuild command to correctly work with symlinked Drupal.
17+ *
18+ * This prevents contrib modules from vanishing when the cache:rebuild command
19+ * is run.
20+ *
21+ * For maintainability, changes from the original are marked 'CHANGE'.
22+ */
23+ class DevelopmentProjectCommands extends CacheCommands {
24+
25+ /**
26+ * @hook replace-command cache:rebuild
27+ */
28+ public function rebuild ($ options = ['cache-clear ' => true ]) {
29+ if (!$ options ['cache-clear ' ]) {
30+ $ this ->logger ()->info (dt ("Skipping cache-clear operation due to --no-cache-clear option. " ));
31+ return true ;
32+ }
33+
34+ // CHANGE: Get the app root ourselves instead of using DRUPAL_ROOT.
35+ $ app_root = $ this ->getAppRoot ();
36+ chdir ($ this ->getAppRoot ());
37+
38+ // We no longer clear APC and similar caches as they are useless on CLI.
39+ // See https://github.com/drush-ops/drush/pull/2450
40+
41+ $ autoloader = $ this ->loadDrupalAutoloader (DRUPAL_ROOT );
42+ require_once DRUSH_DRUPAL_CORE . '/includes/utility.inc ' ;
43+
44+ $ request = Drush::bootstrap ()->getRequest ();
45+ DrupalKernel::bootEnvironment ();
46+
47+ // Avoid 'Only variables should be passed by reference'
48+ // CHANGE: Don't use DRUPAL_ROOT.
49+ $ root = $ app_root ;
50+ $ site_path = DrupalKernel::findSitePath ($ request );
51+ Settings::initialize ($ root , $ site_path , $ autoloader );
52+
53+ // drupal_rebuild() calls drupal_flush_all_caches() itself, so we don't do it manually.
54+ // CHANGE: call our own version of drupal_rebuild().
55+ $ this ->drupal_rebuild ($ autoloader , $ request );
56+ $ this ->logger ()->success (dt ('Cache rebuild complete. ' ));
57+ }
58+
59+ /**
60+ * Replacement for drupal_rebuild().
61+ *
62+ * This passes the app root to DrupalKernel.
63+ */
64+ function drupal_rebuild ($ class_loader , Request $ request ) {
65+ // Remove Drupal's error and exception handlers; they rely on a working
66+ // service container and other subsystems and will only cause a fatal error
67+ // that hides the actual error.
68+ restore_error_handler ();
69+ restore_exception_handler ();
70+
71+ // Invalidate the container.
72+ // Bootstrap up to where caches exist and clear them.
73+ // CHANGE: Pass the correct app root to DrupalKernel.
74+ $ kernel = new DrupalKernel ('prod ' , $ class_loader , TRUE , $ this ->getAppRoot ());
75+ $ kernel ->setSitePath (DrupalKernel::findSitePath ($ request ));
76+ $ kernel ->invalidateContainer ();
77+ $ kernel ->boot ();
78+ $ kernel ->preHandle ($ request );
79+ // Ensure our request includes the session if appropriate.
80+ if (PHP_SAPI !== 'cli ' ) {
81+ $ request ->setSession ($ kernel ->getContainer ()->get ('session ' ));
82+ }
83+
84+ drupal_flush_all_caches ($ kernel );
85+
86+ // Disable recording of cached pages.
87+ \Drupal::service ('page_cache_kill_switch ' )->trigger ();
88+
89+ // Restore Drupal's error and exception handlers.
90+ // @see \Drupal\Core\DrupalKernel::boot()
91+ set_error_handler ('_drupal_error_handler ' );
92+ set_exception_handler ('_drupal_exception_handler ' );
93+ }
94+
95+ /**
96+ * Gets the app root.
97+ *
98+ * @return string
99+ * The app root.
100+ */
101+ protected function getAppRoot (): string {
102+ // This core belongs to the project template, so we can hardcode the
103+ // location of this file relative to the project root, and the scaffold
104+ // location defined in the project's composer.json.
105+ return dirname (__DIR__ , 3 ) . '/web ' ;
106+ }
107+
108+ }
0 commit comments