DEV Community

Cover image for How to upload files to Google Cloud using Laravel
Aghwotu Ovuoke
Aghwotu Ovuoke

Posted on

How to upload files to Google Cloud using Laravel

The aim of this tutorial is to accomplish these tasks

Prequisities

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

From the laravel-dompdf documentation:
Add the ServiceProvider to the providers array in config/app.php

Barryvdh\DomPDF\ServiceProvider::class,
Enter fullscreen mode Exit fullscreen mode

You can optionally use the facade for shorter code. Add this to your facades:

'PDF' => Barryvdh\DomPDF\Facade::class,
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

Blade template files are created in the resources/views directory

CREATE CONTROLLER

At this stage we have

  1. Initialized a laravel project
  2. Pulled in the laravel-dompdf package to generate pdf
  3. Created a symbolic link and folder to store the generated pdf
  4. 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 
Enter fullscreen mode Exit fullscreen mode
<?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)
            ]
        ]);


    }

}

Enter fullscreen mode Exit fullscreen mode

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 the pdf-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']);
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Set the Headers to

KEY     VALUE
Accept  application/json
Enter fullscreen mode Exit fullscreen mode

And the body of the request to JSON

{
    "firstname" : "YourFirstName",
    "email" : "yourEmailAddress@domain.com"
}
Enter fullscreen mode Exit fullscreen mode

SUCCESSFUL RESPONSE

A successful response returns this JSON

{
    "status": "success",
    "message": "PDF saved successfully ",
    "data": {
        "url": "url-of-the-generated-pdf-file"
    }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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'),


];

Enter fullscreen mode Exit fullscreen mode

Run this command after making the configuration changes:

composer dump-autoload 
php artisan config:clear
php artisan config:cache
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Next, we will add the class

use Google\Cloud\Storage\StorageClient;
Enter fullscreen mode Exit fullscreen mode

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
  ]
]);
Enter fullscreen mode Exit fullscreen mode

If you see this error: ext-json is missing in composer.json, this solves it:

"require": {
  "ext-json": "*"
},
Enter fullscreen mode Exit fullscreen mode

Send Email Notification

After signing up on mailtrap.io, you can get your configuration settings from your inbox by clicking the settings icon:

image

And selecting your desired language from the dropdown:

image

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
Enter fullscreen mode Exit fullscreen mode

Now we will create a nofication using Laravel's Artisan command

php artisan make:notification PdfNotification
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

In the PdfGeneratorController, add these classes:

use App\Models\User;
use Illuminate\Support\Facades\Notification;
Enter fullscreen mode Exit fullscreen mode

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)));
Enter fullscreen mode Exit fullscreen mode

The email should look like this:
image

Top comments (0)