Laravel 8 Media Upload to Cloudinary on Heroku

Laravel 8 Media Upload to Cloudinary on Heroku

Testing Laravel apps with file uploads on Heroku

After building the app the file uploads don't work on Heroku right? Yeah not to bother this article will sort it out...

In the previous article hosting laravel application on Heroku we promised to implement laravel file uploads on Heroku using Cloudinary.

This is because the Heroku filesystem is ephemeral - that means that any changes to the filesystem whilst the dyno is running only last until that dyno is shut down or restarted. Each dyno boots with a clean copy of the filesystem from the most recent deployment. In addition, under normal operations, dynos will restart every day in a process known as "Cycling".

These two facts mean that the filesystem on Heroku is not suitable for persistent storage of data.

In this article, we'll be looking at laravel file uploads on Heroku using Cloudinary

Why Cloudinary ?

Media experience is everything. But behind the fast, visual-rich websites and apps you love today are technologies automating what would typically be a massive media management headache.

Cloudinary was built from the ground up by developers who knew there had to be a better way to upload, manage and deliver tens of thousands to millions of images and videos. Using artificial intelligence (AI), automation, and advanced patent-pending image and video processing capabilities, we make it easier for brands to deliver fast and flawless visual experiences at scale.

We'll continue from the previous authentication app used for this [tutorial(alemsbaja.hashnode.dev/hosting-laravel-apps..) which means we'll skip to creating views for the upload form and the display media on the user dashboard. The source code for this tutorial can be found here

You could clone the repository or start from the section below to implement cloudinary on your project.

We'll be using the jrm2k6/cloudder cloudinary package.

First

composer require jrm2k6/cloudder:^0.6.0

Next

Open the config\app.php file and add the following codes

Add this to the providers array

        JD\Cloudder\CloudderServiceProvider::class,

image.png

Add this to the aliases array

        'Cloudder' => JD\Cloudder\Facades\Cloudder::class,

image.png

Next publish the package using the command below

php artisan vendor:publish --provider="JD\Cloudder\CloudderServiceProvider"

This will create a cloudder configuration file config/cloudder.php

Go to your .env file and paste this configuration for cloudinary

CLOUDINARY_API_KEY=
CLOUDINARY_API_SECRET=
CLOUDINARY_CLOUD_NAME=

Let's obtain those credentials from cloudinary

You can create a cloudinary account here

If you've got an account login and you'll see the details for remotely accessing your Cloudinary account on the dashboard.

cloudinary-dashboard.png

Next copy the cloudname, API key, API secret and paste on your .env file

Note you can create a folder in your Cloudinary account to affect the categorization of file uploads.

Click on the media library tab and create a folder with your desired name

For this tutorial we created a folder called laravel_tutorial

folder-tutorial.png

Update the .env file with your credentials

CLOUDINARY_API_KEY=437347347347
CLOUDINARY_API_SECRET=o898eh7e8
CLOUDINARY_CLOUD_NAME=laravel_upload

That's all for cloudinary, Yea!

Create a route for displaying and submitting form upload

<?php

use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\MediaController;


Route::get('/', function () {
    return view('welcome');
});

Auth::routes();

Route::middleware(['auth'])->group(function () {
    Route::view('home', 'home')->name('home');
    Route::match(['get', 'post'], '/upload', [MediaController::class, 'media'])->name('upload.media');
});

route cloudinary.png

Next we'll create a controller called MediaController and add the media method to handle upload and display

php artisan make:controller MediaController

Here's is the snippet for the media method

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use JD\Cloudder\Facades\Cloudder;

class MediaController extends Controller
{
    public function media(Request $request)
    {
        if ($request->isMethod('post')) {
            $this->validate($request, [
                'avatar' => 'image|mimes:jpeg,png,jpg|max:1048|required',
            ]);


            $image_name = $request->file('avatar')->getRealPath();
//the upload method handles the uploading of the file and can accept attributes to define what should happen to the image

//Also note you could set a default height for all the images and Cloudinary does a good job of handling and rendering the image.
            Cloudder::upload($image_name, null, array(
                "folder" => "laravel_tutorial",  "overwrite" => FALSE,
                "resource_type" => "image", "responsive" => TRUE, "transformation" => array("quality" => "70", "width" => "250", "height" => "250", "crop" => "scale")
            ));

//Cloudinary returns the publicId of the media uploaded which we'll store in our database for ease of access when displaying it.

$public_id = Cloudder::getPublicId();

            $width = 250;
            $height = 250;

//The show method returns the URL of the media file on Cloudinary
 $image_url = Cloudder::show(Cloudder::getPublicId(), ["width" => $width, "height" => $height, "crop" => "scale", "quality" => 70, "secure" => "true"]);

//In a situation where the user has already uploaded a file we could use the delete method to remove the media and upload a new one.
            if ($public_id != null) {
                $image_public_id_exist = User::select('public_id')->where('id', Auth::user()->id)->get();
                Cloudder::delete($image_public_id_exist);
            }

            $user = User::find(Auth::user()->id);
            $user->public_id = $public_id;
            $user->avatar_url = $image_url;
            $user->update();
            return back()->with('success_msg', 'Media successfully updated!');
        } else {
            return view('media');
        }
    }
}

Views

Dashboard image.png

Media Form

image.png

The media view file can be found on the source code

This will work locally but for the purposes of the tutorial, we'll focus on Heroku.

Run the following to push the code updates to Git and deploy on Heroku for testing

git add .
git commit -m "Laravel Media uploads on Heroku to cloudinary"
git push origin -u main
git push heroku main

Run the following to set environment variables for Cloudinary on Heroku

heroku config:add CLOUDINARY_API_KEY=437347347347
heroku config:add CLOUDINARY_API_SECRET=o898eh7e8
heroku config:add CLOUDINARY_CLOUD_NAME=laravel_upload

Visit the URL

Register

reg-cloudinary.png

Upload

upload form.png

You might encounter this error when you try to upload to cloudinary

class cloudinary  not found.png

Here's how to resolve it.. Go to composer.json file

Add this line to the require object

 "cloudinary/cloudinary_php": "1.20",

composer.png

Next

composer update

Run the following git commands to update the repository and deploy to Heroku

git add .
git commit -m "Fix Cloudinary Class not Found Error"
git push origin -u main
git push heroku main

Awesome!!!

Visit the URL refresh, register and upload again. Go to dashboard to see the media uploaded.

Upload again you should see the view

uploaded.png

Dashboard

image uploaded - home display.png

Congratulations!!!!

You can now test your Laravel application for free with media upload on Heroku to Cloudinary

Thank you for reading this article.

Please kindly share with your network and feel free to use the comment section for questions, answers, and contributions.

You love this article?? please follow me on Hashnode or Twitter @alemsbaja to stay updated for more on articles.

Did you find this article valuable?

Support Alemoh Rapheal Baja by becoming a sponsor. Any amount is appreciated!