Migration to Laravel, Vanity URLs, middleware for all requests, Auth::user and $errors issue

342 views Asked by At

I created a middleware class named PathParser which runs on every request. The purpose is to handle requests for "vanity URL paths" that we allowed users to create in our pre-Laravel vanilla PHP app. For example: A user created a URL path such as: http://example.com/i-love-this-place

What PathParser does is to check for 404 responses, and then look to see if the URL path matched one of our old vanity paths. Like this:

class PathParser
{   
    public function handle($request, Closure $next, $guard = null)
    {
        $next_response = $next($request);       
        $status_code = $next_response->getStatusCode();

        if ($status_code === 404) {
            $script_url = $request->server("SCRIPT_URL");

            $vanity_controller = new VanityController();
            $found_vanity_id = Search::findVanityPath($script_url);

            if (!empty($found_vanity_id)) {
                $next_response = response()->make($vanity_controller->one($found_vanity_id));
            }
        }

        return $next_response;
    }
}

Assume the following:

  1. A user has never created a URL path that would conflict with any route

  2. I must support a number of existing (pre-Laravel) vanity URL paths that are out in the wild -- posted to social media and so on.

In Kernel.php, I have the following:

protected $middleware = [
        \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
        \App\Http\Middleware\PathParser::class,
        //\Illuminate\Session\Middleware\StartSession::class,
        //\Illuminate\View\Middleware\ShareErrorsFromSession::class,
    ];

    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],    
    ];

In the $middleware array I tried added StartSession and ShareErrorsFromSession (uncommenting the 2 lines above), and this works partially. But with two major problems:

  • Auth::user is null, even for requests made to vanity paths by logged in users
  • $errors no longer gets populated on form submission (such as on the registration and login pages) when a user submits incorrect/invalid information

Is there a way both to check the route on all requests and get ahold of the authenticated user, also preserving $errors?

I have a feeling I don't understand the request lifecycle well enough to succeed. But maybe there is a way?

If it's not possible to do what I require, then use of 302 redirection to a standardized prefixed path (such as http://example.com/vanity/i-love-this-place) is a fine solution. But I'm hoping there is another means.

1

There are 1 answers

1
patricus On BEST ANSWER

A couple suggestions:

If you don't need auth/sessions/etc, then you can just handle the Symfony\Component\HttpKernel\Exception\NotFoundHttpException exception inside your application's exception handler.

In app/Exceptions/Handler.php, modify the render() method to look something like:

public function render($request, Exception $e)
{
    if ($e instanceof \Symfony\Component\HttpKernel\Exception\NotFoundHttpException) {
        // your code that returns a Response
    }

    return parent::render($request, Exception $e);
}

If you do need auth/sessions/etc, I would suggest creating a "catchall" route at the end of your routes file. For example, as the very last line in your routes/web.php file, put:

Route::any('{catchall}', 'VanityController@handle')->where('catchall', '(.*)');

Then, inside your VanityController, have a handle method that looks like:

public function handle(Request $request, $url)
{
    // logic to search and render your vanity page for $url

    // if no vanity page was found:
    throw new \Symfony\Component\HttpKernel\Exception\NotFoundHttpException();
}