Skip to content
Advertisement

Artisan::call(‘route:cache’) from within Laravel app, crashes

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: enter image description here

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. enter image description here

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)

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement