How to upload files to Google Cloud using Laravel
Aghwotu Ovuoke
Posted on March 19, 2021
The aim of this tutorial is to accomplish these tasks
- Prequisities
- Create a Laravel API that creates and stores PDF locally
- Uploading files to Google Cloud Storage
- Send Email Notification
Prequisities
- Install Composer
- Get a Google Cloud account
- Install Postman or your preferred API testing tool
- Mailtrap account
Create a Laravel API that creates and stores PDF locally
INITIALIZE PROJECT
First, we will initialize a new Laravel project into a pdf-generator
directory using composer:
composer create-project laravel/laravel pdf-generator
USE COMPOSER PACKAGE
The composer package we will be using is laravel-dompdf. To use this package in our project we will use this command:
composer require barryvdh/laravel-dompdf
From the laravel-dompdf
documentation:
Add the ServiceProvider to the providers array in config/app.php
Barryvdh\DomPDF\ServiceProvider::class,
You can optionally use the facade for shorter code. Add this to your facades:
'PDF' => Barryvdh\DomPDF\Facade::class,
CREATE SYMBOLIC LINK
To store our generated file, we need to create a symbolic link.
From the Laravel Documentation:
To make these files accessible from the web, you should create a symbolic link from public/storage to storage/app/public. Utilizing this folder convention will keep your publicly accessible files in one directory that can be easily shared across deployments when using zero down-time deployment systems like Envoyer.
To create the symbolic link, you may use the storage:link
Artisan command:
php artisan storage:link
Now, we will create a pdf
directory in the public/storage
directory. Every directory and file created/stored here will be mirrored in the storage/app/public
directory.
CREATING THE BLADE TEMPLATE FILE
Our next step is to create a blade template file
for our pdf view. This view will display two values: the $firstname
and $email
of the user. We will name ours: pdfdocument.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Laravel PDF demo</title>
</head>
<body>
<h1>Laravel PDF demo</h1>
<p>Firstname: {{$firstname}} </p>
<p>Email: {{$email}} </p>
</body>
</html>
Blade template files are created in the
resources/views
directory
CREATE CONTROLLER
At this stage we have
- Initialized a laravel project
- Pulled in the laravel-dompdf package to generate pdf
- Created a symbolic link and folder to store the generated pdf
- Created a blade template file which will be used for the pdf
Now, let us create the controller to bring it all together.
We will create a Controller in an Api
folder with this artisan command:
php artisan make:controller Api/PdfGeneratorController
<?php
namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\App;
class PdfGeneratorController extends Controller
{
/**
* Store a newly created resource in storage.
*
* @param Request $request
* @return JsonResponse
*/
public function store(Request $request) : JsonResponse
{
$validatedData = $request->validate([
'firstname' => ['required', 'min:3', 'max:50'],
'email' => ['required', 'email'],
]);
$pdf = App::make('dompdf.wrapper');
$pdf->loadView('pdfdocument', $validatedData);
$filename = $request['firstname'] . '.pdf';
$fileStoragePath = '/storage/pdf/' . $filename;
$publicPath = public_path($fileStoragePath);
$pdf->save($publicPath);
return response()->json([
"status" => "success",
"message" => "PDF saved successfully ",
"data" => [
"url" => url($fileStoragePath)
]
]);
}
}
You can use the laravel-jsend package to generate JSend-compliant responses for your Laravel app
ROUTING THE REQUEST
Next, we will create a route in our api.php
file that will point to the store()
method in the PdfGeneratorController
.
The
api.php
file is located in thepdf-generator/routes
directory
The line below ensures that only post requests are made to the store
method with a slug of generate-pdf
Route::post('/Api/generate-pdf', [PdfGeneratorController::class, 'store']);
TESTING OUR CODE
For testing, we will use Postman or any API testing tools of your choice. We will make a post request to the store method
[POST] http://127.0.0.1:8000/api/Api/generate-pdf
Set the Headers
to
KEY VALUE
Accept application/json
And the body of the request to JSON
{
"firstname" : "YourFirstName",
"email" : "yourEmailAddress@domain.com"
}
SUCCESSFUL RESPONSE
A successful response returns this JSON
{
"status": "success",
"message": "PDF saved successfully ",
"data": {
"url": "url-of-the-generated-pdf-file"
}
}
Uploading files to Google Cloud Storage
CREATING THE BUCKET
Buckets are the basic containers that hold your data. Everything that you store in Cloud Storage must be contained in a bucket. You can use buckets to organize your data and control access to your data, but unlike directories and folders, you cannot nest buckets.
To create a bucket on Google Cloud Storage, you can follow this tutorial and skip to 02:13 to 03:44
to first create a Service Account and then skip to 05:21 to 05:31
to create Cloud Storage.
Optionally, you can also check out this slide on How to create a bucket on Google Cloud that contains a guide similar to the YouTube video above
CONFIGURATION FILES AND VARIABLES
Rename the json key generated to googlecloud.json
and move/copy it into the config
directory like so: config/googlecloud.json
.
Next, in the .env
file, create add these environment variables:
# GOOGLE CLOUD
GOOGLE_CLOUD_PROJECT_ID=laravel-tutorial
GOOGLE_CLOUD_STORAGE_BUCKET=laravel-pdf-bucket
Now, we will create a configuration file that will access the environment variables in the .env
file. Create a file in in the config
directory and name it googlecloud.php
like so: config/googlecloud.php
and pass in this code:
<?php
return [
/*
|--------------------------------------------------------------------------
| Google Cloud configuration
|--------------------------------------------------------------------------
|
| This file is for storing the credentials for Google Cloud
|
|
|
|
*/
'project_id' => env('GOOGLE_CLOUD_PROJECT_ID'),
'storage_bucket' => env('GOOGLE_CLOUD_STORAGE_BUCKET'),
];
Run this command after making the configuration changes:
composer dump-autoload
php artisan config:clear
php artisan config:cache
USING THE GOOGLE CLOUD PACKAGE
Our next step is to use the Google Cloud Storage Client for PHP.
We pull in the package with this composer command
composer require google/cloud-storage
Next, we will add the class
use Google\Cloud\Storage\StorageClient;
And now we will upload our generated file to Google Cloud and return the google cloud storage url in the response()->json()
$googleConfigFile = file_get_contents(config_path('googlecloud.json'));
$storage = new StorageClient([
'keyFile' => json_decode($googleConfigFile, true)
]);
$storageBucketName = config('googlecloud.storage_bucket');
$bucket = $storage->bucket($storageBucketName);
$fileSource = fopen($publicPath, 'r');
$newFolderName = $request['firstname'].'_'.date("Y-m-d").'_'.date("H:i:s");
$googleCloudStoragePath = $newFolderName.'/'.$filename;
/* Upload a file to the bucket.
Using Predefined ACLs to manage object permissions, you may
upload a file and give read access to anyone with the URL.*/
$bucket->upload($fileSource, [
'predefinedAcl' => 'publicRead',
'name' => $googleCloudStoragePath
]);
return response()->json([
"status" => "success",
"message" => "PDF saved successfully ",
"data" => [
"url" => url($fileStoragePath),
"google_storage_url" => 'https://storage.cloud.google.com/'.$storageBucketName.'/'.$googleCloudStoragePath
]
]);
If you see this error: ext-json is missing in composer.json
, this solves it:
"require": {
"ext-json": "*"
},
Send Email Notification
After signing up on mailtrap.io, you can get your configuration settings from your inbox by clicking the settings icon:
And selecting your desired language from the dropdown:
Your smtp settings will be displayed below the dropdown. Copy the settings and add them to your .env
file.
Run this command after making the configuration changes:
composer dump-autoload
php artisan config:clear
php artisan config:cache
Now we will create a nofication using Laravel's Artisan command
php artisan make:notification PdfNotification
This command will place a fresh notification class in the app/Notifications
directory.
In the __constructor()
add this code:
<?php
/**
* @var string
*/
public $filePath;
/**
* @var string
*/
public $fileUrl;
/**
* Create a new notification instance.
*
* @param string $filePath
* @param string $fileUrl
*/
public function __construct(string $filePath, string $fileUrl)
{
$this->filePath = $filePath;
$this->fileUrl = $fileUrl;
}
In the toMail()
method, add this code:
<?php
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return MailMessage
*/
public function toMail($notifiable): MailMessage
{
return (new MailMessage)
->subject('Laravel Notification')
->from('youremail@domain.com')
->greeting("Dear " . $notifiable->name . ",")
->line("Please find attached your document")
->line('Thank you for using our application!')
->action('Download File', url($this->fileUrl))
->attach($this->filePath);
}
In the PdfGeneratorController
, add these classes:
use App\Models\User;
use Illuminate\Support\Facades\Notification;
Next, inside the store()
method, before the returning the response()->json()
create a User
and send them a notification:
<?php
$user = new User([
'email' => $request['email'],
'name' => $request['firstname']
]);
Notification::send($user, new PdfNotification($publicPath, url($fileStoragePath)));
Posted on March 19, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.