@@ -92,9 +92,7 @@ public function install(string $repoUrl, ?string $branch = null, ?string $tag =
9292 $ this ->logRunning ('Running plugin install command... ' , $ repoName , $ userId );
9393 $ this ->runCommand ($ installCommand , $ repoName , $ userId );
9494
95- // Rebuild route cache so we pick up the new routes from the plugin
96- $ this ->logRunning ('Rebuilding route cache... ' , $ repoName , $ userId );
97- $ this ->runCommand ('route:cache ' , $ repoName , $ userId );
95+ $ this ->rebuildRouteCache ($ repoName , $ userId );
9896
9997 $ this ->logDone ('Plugin installed successfully ' , $ repoName , $ userId );
10098 }
@@ -129,9 +127,7 @@ public function uninstall(string $pluginName, ?int $userId = null): void
129127 $ this ->logRunning ('Removing plugin directory... ' , $ pluginName , $ userId );
130128 $ this ->deleteDirectory ($ pluginPath , $ pluginName , $ userId );
131129
132- // Rebuild route cache so we remove the routes from the plugin
133- $ this ->logRunning ('Rebuilding route cache... ' , $ pluginName , $ userId );
134- $ this ->runCommand ('route:cache ' , $ pluginName );
130+ $ this ->rebuildRouteCache ($ pluginName , $ userId );
135131
136132 $ this ->logDone ('Plugin uninstalled successfully ' , $ pluginName , $ userId );
137133 }
@@ -141,7 +137,7 @@ private function runCommand(string $command, string $pluginName, ?int $userId =
141137 // Use absolute path: web SAPI (php-fpm) cwd is not the app root, so plain "artisan" fails.
142138 //TODO: Change artisan_binary() for base_path('artisan')
143139 $ artisan = base_path ('artisan ' );
144- $ result = Process::run (array_filter ([
140+ $ result = Process::env ( $ this -> artisanEnvironment ())-> run (array_filter ([
145141 php_binary (),
146142 $ artisan ,
147143 $ command ,
@@ -161,6 +157,52 @@ private function runCommand(string $command, string $pluginName, ?int $userId =
161157 }
162158 }
163159
160+ /**
161+ * Rebuild the tenant's route cache in a fresh artisan process.
162+ *
163+ * The current request already booted without the plugin's providers, so
164+ * Artisan::call('route:cache') would persist stale routes. A subprocess
165+ * with TENANT set loads plugins from the tenant storage path and writes
166+ * the cache for that tenant.
167+ */
168+ private function rebuildRouteCache (string $ pluginName , ?int $ userId = null ): void
169+ {
170+ $ this ->logRunning ('Rebuilding route cache... ' , $ pluginName , $ userId );
171+ $ this ->runCommand ('route:cache ' , $ pluginName , $ userId );
172+ $ this ->reloadCachedRoutes ();
173+ }
174+
175+ /**
176+ * Environment variables for artisan subprocesses started from a web request.
177+ */
178+ private function artisanEnvironment (): array
179+ {
180+ $ environment = [];
181+ $ tenant = app ()->bound ('currentTenant ' ) ? app ('currentTenant ' ) : null ;
182+
183+ if (config ('app.multitenancy ' ) && $ tenant ) {
184+ $ environment ['TENANT ' ] = (string ) $ tenant ->id ;
185+ }
186+
187+ return $ environment ;
188+ }
189+
190+ /**
191+ * Load the freshly written route cache into the current process.
192+ *
193+ * Needed for Octane workers that keep the router in memory after
194+ * `route:cache` finishes in a subprocess.
195+ */
196+ private function reloadCachedRoutes (): void
197+ {
198+ $ cachedRoutesPath = app ()->getCachedRoutesPath ();
199+ if (!is_file ($ cachedRoutesPath )) {
200+ return ;
201+ }
202+
203+ require $ cachedRoutesPath ;
204+ }
205+
164206 /**
165207 * Install a plugin from a zip file path.
166208 *
@@ -231,9 +273,7 @@ public function installFromZip(string $zipPath, ?int $userId = null): void
231273 $ this ->logRunning ('Running plugin install command... ' , $ repoName , $ userId );
232274 $ this ->runCommand ($ installCommand , $ repoName , $ userId );
233275
234- // Rebuild route cache
235- $ this ->logRunning ('Rebuilding route cache... ' , $ repoName , $ userId );
236- $ this ->runCommand ('route:cache ' , $ repoName , $ userId );
276+ $ this ->rebuildRouteCache ($ repoName , $ userId );
237277
238278 $ this ->logDone ('Plugin installed successfully ' , $ repoName , $ userId );
239279 } finally {
@@ -271,6 +311,8 @@ public function toggle(string $pluginName, ?int $userId = null): bool
271311 throw new RuntimeException ("Failed to disable plugin: {$ pluginName }" );
272312 }
273313
314+ $ this ->rebuildRouteCache ($ pluginName , $ userId );
315+
274316 return false ;
275317 }
276318
@@ -283,6 +325,8 @@ public function toggle(string $pluginName, ?int $userId = null): bool
283325 throw new RuntimeException ("Failed to enable plugin: {$ pluginName }" );
284326 }
285327
328+ $ this ->rebuildRouteCache ($ enabledName , $ userId );
329+
286330 return true ;
287331 }
288332
0 commit comments