Quick summary: I need to programmatically clear the routes cache (unless there is another way using the RouteServiceProvider?) but Artisan::call('route:cache');
is throwing an error.
I have routes that are bound to arrays of slugs we pull out of our database. This is all working great except that on our CMS side, if we add a new entry the app gives us a 404 on that new URL because the routes are all already cached. I can’t be ssh-ing in and running php artisan route:cache
every time someone makes an edit.
I’ve tried to add an observer to the relevant model that runs route:cache
whenever there is a change to a slug or a new entry is added, but that’s throwing an exception. I can’t replicate it in my local setup because my routes aren’t cached locally!
Here are some snippets of what’s going on:
My RouteServiceProvider is set up like below (to serve the routes {location}
). Is there something I could be doing differently here?
// this does not seem to update the routes every time the app boots
public function boot()
{
$locations = implode('|', Location::get()->pluck('slug')->toArray());
Route::pattern('location', '(' . $locations . ')');
parent::boot();
}
So, to reiterate, if I add a new Location
or modify an existing one, I get a 404 until having run php artisan route:cache
. But, I don’t want to have to clear the route cache manually, so I set up an observer like this:
use IlluminateSupportFacadesArtisan;
use myAppModelsAppLocation;
// this model observer is hardly a glowing example of DRY credo
class LocationObserver
{
public function created(Location $location)
{
Artisan::call('route:cache');
}
public function updated(Location $location)
{
if($location->isDirty('name')) {
Artisan::call('route:cache');
}
}
My app’s not really called ‘MyApp’, I’ve changed it here for privacy’s sake. Also, slug
changes whenever name
changes so I’m just checking for that.
But that gives an error. Here’s a screenshot from my logs:
Also interesting is that in php artisan tinker
I get a deprecated error when trying to run Artisan::call('route:cache')
which I’ve found a couple GitHub issues related to this but can’t work out how to solve it on my side.
Advertisement
Answer
First of all, I would use a diferent aproach where you simply have 1 route & 1 controller.
$router->get('location/{slug}', 'LocationController@show');
Then in your show method you can just try to fetch a Location from the database and return a 404 if none was found by that slug. That’s how I’d do it.
public function show(string $slug) {
$location = Location::where('slug', '=', $slug)->first;
if (!$location) {
throw new LocationNotFoundException()
}
// rest of the code
}
If you go your route, what your error is indicating is some filesystem
permission error.
Please verify the owner of the file bootstrap/cache/routes.php
with ls -la
and make sure that it is the same one as the user running your php process (ps aux | grep php
)