Creating PDFs from existing website pages / views is really simple thanks to one of the thousands of packages from the great guys at Spatie. In all of the code below, we are using their BrowserShot package.
In a few recent projects we have needed to create a PDF based off of a current page that is protected by an Authentication guard. Since BrowserShot is is essentially accessing this in a new browser session, it does not respect the authenticated state of your apps session.
In a standard Laravel project this is really straightforward as you can easily use the render()
method on any view
to grab the html and pass it to BrowserShot:
$html = view('invoice.blade.php', ['invoice' => $invoice])->render(); Browsershot::html($html)->pdf()
However, with an Inertia or Vue JS app, we do not have this luxury. I think there are many different solutions for this problem, but the following is how we have approached it.
First, we create a new Middleware
php artisan make:middleware AllowPrint
The purpose of this middleware is to allow traffic to these "printable" routes in 2 scenarios:
- if the user is Authenticated
- if our app sends an encrypted string (which we will use when generating PDFs)
We do this by adding a check to see if an encrypt
property is passed and if it is, we need to decrypt this value to ensure it is valid. This value used in this example is simply your APP_KEY
that is generated with you Laravel project in your .env
file.
The full middleware class is below.
AllowPrint.php
class AllowPrint { public function handle($request, Closure $next) { if( $request->encrypt && app('hash')->check(config('app.key'), $request->encrypt) || Auth::check()) { return $next($request); }1 return redirect(RouteServiceProvider::HOME);2}}
Next, in our Controller (or however you want to call BrowserShot), you make the request with the encrypted app key.
Browsershot::url(route('invoice.show', ['encrypt' => bcrypt(config('app.key'))])->pdf();
Finally, for any routes that need to be behind the Auth guard AND needs to be “printable” (exported to PDF), you simply add our new middleware.
Route::middleware(['print'])->group(function() { // your routes here });
Hopefully this provides some insight for one way to accomplish using Spatie BrowserShot on your Inertia / VueJS routes to generate a PDF.