Extending Laravel UploadedFile functionality using Macros

Gopal Date: May 21, 2020

I’ve been working on a project where each module of the application needs to upload an image and multiple images and I was unaware of the SEO working regarding image naming. I directly used the “store” function to save an image that generates a random string name for image. The project was almost going to complete and ready for production then the client verifies the SEO part of the project and he found such an issue. It was not difficult for us but the problem was, if we replace function with “saveAs” then we have to specify the filename and its extension but client format is specified as defined below.

“system_filename_randon_string.jpg”

In this format, we will need to write three lines of code at every place where we used the “store” function.

  • Get filename without extension
  • Generate random string
  • Concat filename and random string with ‘_’ with having file extension.

My clean code became messy if I put the above code and also generate dublicacy in code and I did not want this. Then I planned to override the “store” function but the problem if the client tells any other specific name pattern for a particular module then?

After doing google for sometime, I came across micros functionality of laravel. It is just a trait named microable which help us to increase the function of any class having microable trait. I study and went through following materials. 

https://laravel.com/docs/7.x/requests#retrieving-uploaded-files

https://tighten.co/blog/the-magic-of-laravel-macros/

So now a question came into my mind that why we should use micros there is no other way except this? I check, store function is specified in UploadedFile class and it was in a vendor under laravel package. Modify and Extending UploadedFile class does not make any sense for me but this class using microable trait.

After that, I decided to go with micros and create a function “storeFile” in a custom service provider named UploadedFileServiceProvider you can see my code as below. Microable trait has some magic functions through this it handles such functionality.

And in the whole project I just needed to replace a “store” function with “storeFile”.


class UploadedFileServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        UploadedFile::macro('storeFile', function($path,$filename = '', $options =[])
        {
            if(!$filename) {
                $filename = pathinfo($this->getClientOriginalName(),PATHINFO_FILENAME);
                $filename = Str::snake($filename).'_'.Str::random(40).'.'.$this->clientExtension();
            }

            return $this->storeAs($path, $filename, $options);
        });
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}