Laravel Posts

post

You must be thinking what is a webhook? Where it is used? What is the usage of it? And the most important why it’s used?

Webhooks are automated services, it is a way that the app can send automated messages or information to our system.

When something happens in the system then this service is fire and our system caches those services and can do according to changes in our system.

Let’s take an example of a stripe webhook

We have integrated Stripe payment gateway, we have according to payment fields in our system’s database. When our system user do the payment in stripe at that time payment is done in stripe, but now how will our system get to know about the customer has do payment or not?

When customer complete payment in stripe, it will send service(webhook) to our system which has information about customer payment detail, our system will cache this service, then our system will find that user in our system and if found then we can do payment changes in our customer detail.

August 28, 20201 MinutesauthorMonika Vaghasiya
post

Recently, we were working in a laravel app where we have a status column in multiple models. We have multiple processes going on for which we have different jobs.

Initially job status will be "Pending", then each job will take one record, change the status to "Running" and process that record, and update the status to either "Completed" or "Failed".

We have constants for each status. Something like below,

static $STATUS_PENDING = 0;
static $STATUS_RUNNING = 1;
static $STATUS_COMPLETED = 2;
static $STATUS_FAILED = 3;

And the problem is, we need to go and define the status in every model that we have (around 10+ models).

Then we have functions to update status and check the status in each model like,

public function markRunning($saveRecord = true)
{
    $this->status = static::$STATUS_RUNNING;

    if ($saveRecord) {
        $this->save();
    }
}

public function isRunning()
{
    return $this->status === static::$STATUS_RUNNING;
}

And above functions existed for each 4 status. so what we did is, we created a common StatusTrait which can be used across multiple models.

Here is the code of StatusTrait that you can find for that.

Then in each model, we use this trait. For e.g.,

class SavePdf extends Model
{
    use StatusTrait;

    .....
}

And then can use any method of trait in all the models,

...
$savePdf = new SavePdf();
$savePdf->markRunning();
...

Or we can check if the status of the model is running or not. For e.g.,

...
if ($savePdf->isRunning()) {
    // logic here
}
...

This is how we have saved tons of writing code and optimized the code. Another advantage is, we can just update the value of any status from one single place.

You can also check this kind of pattern and do something like this.

August 26, 20201 minuteauthorMitul Golakiya
post

Laravel Debugbar is a great package to debug laravel applications while development. But it's not just limited to debugging. You can use it to optimize the performance of your app a lot as well. Like,

  • number of models loaded in a memory
  • number of queries fired with timing
  • memory used and more.

In short, we can have a complete view of what's going on in each request.

But the less known and use feature it gives is the Timeline tab. Where you can see how much time is taken for each request. And more than that, how much time Laravel took to boot up and how much time our other code has taken. Check the below screenshot.

Timeline

Recently we came to the case, where one of our consultation clients' CRM application was taking too much time on the first load. Their developers were not able to spot a problem. They checked queries and other stuff which looked completely good. so we were not sure where the time has been spent by the application.

That's were debugbar came to rescue us. We used its measure function facility by which we can measure the time spent in each of the function wherever we want to use. It gives simply two functions startMeasure and stopMeasure to measure the time spent between these two statements.

so we can put startMeasure in the staring of function and put stopMeasure at the end of the function which will render something like this in the timeline tab.

public function searchClients($department)
{
    \Debugbar::startMeasure("searchClients");

    // logic here

    \Debugbar::stopMeasure("searchClients");

    return $result;
}

Once we put this, we get a time that searchClients is taking. Check the screenshot below,

Timeline

Hope this can help you to figure out what piece of code is taking the time and you can optimize it.

Happy Optimizing :)

August 22, 20201 minuteauthorMitul Golakiya
post
We work on projects with the admin panel every day. In which we mostly use data tables and we need to delete the record from the data table without page refresh.

So, today I will show you how to extract a record using Ajax. It's very easy to integrate.

Let take one example. I have a Category data table and I want to delete one category from the table without refresh the page. now, what am I doing for that? first of all, I add a class for the listen to a click event into the delete button and it's says delete-btn. 

See the following image for where I added a class.

I used SweetAlert for the confirmation popup. let add sweet alert's CSN into the index.blade.php.

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/sweetalert/1.1.3/sweetalert.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/sweetalert/1.1.3/sweetalert.min.js"></script>
let's declare routes of the delete record.

<script>
       let categoryUrl = '{{route('categories.index')}}';
</script>
next steps, I going to listen to the click event of the delete button. one more thing does not forget to add the record id into the data attribute to the delete button. see the above image for it. I highlighted with a yellow line.

So the general practices we use in Laravel is to write the following code to listen to a click event and delete a record,

$(document).on('click', '.delete-btn', function (event) {
            const id = $(event.currentTarget).data('id');
            swal({
                    title: 'Delete !',
                    text: 'Are you sure you want to delete this Category" ?',
                    type: 'warning',
                    showCancelButton: true,
                    closeOnConfirm: false,
                    showLoaderOnConfirm: true,
                    confirmButtonColor: '#5cb85c',
                    cancelButtonColor: '#d33',
                    cancelButtonText: 'No',
                    confirmButtonText: 'Yes',
                },
                function () {
                    $.ajax({
                url: categoryUrl + '/' + id,
                type: 'DELETE',
                DataType: 'json',
                data:{"_token": "{{ csrf_token() }}"},
                success: function(response){
                    swal({
                                title: 'Deleted!',
                                text: 'Category has been deleted.',
                                type: 'success',
                                timer: 2000,
                            });
                    $('#categoryTbl').DataTable().ajax.reload(null, false);
                },
                error: function(error){
                    swal({
                                title: 'Error!',
                                text: error.responseJSON.message,
                                type: 'error',
                                timer: 5000,
                            })    
                }
            });
                });
        });
Now we are done with the front-end side and need to look into it backend side. 

Let's declare the destroy method into the category Controller. I hope are you generate crud with InfyOm Laravel Generator. so, the Destroy method and routes are there. if not please create a route. if the destroy method is there then need to change the response of that method.

The destroy method code looks like,

 public function destroy($id)
    {
        $category = $this->categoryRepository->find($id);

        if (empty($category)) {
            Flash::error('Category not found');

            return $this->sendError('Category not found.');
        }

        $this->categoryRepository->delete($id);

        return $this->sendSuccess('Category deleted successfully.');
    }
Now we are done. the video tutorial also available here

August 19, 20202 minutesauthorShailesh Ladumor
post

Recently, we have started working on one CRM System for client, where we offer a user to create an account and then can upload his excel file of Contracts and we will create contracts in the database, and then these contracts will be emailed to both the parties of the contract.

For this, the functionality we want is, we do not let users wait to do these all things, because this process may take longer based on the number of records the user has. Also, this process contains lots of computation like,

  1. Upload an Excel file
  2. Do field mappings
  3. Validate the record of contract
  4. Create a contract in the database along with all other information
  5. Create a PDF of contract (which take significant time)
  6. Email that PDF to both the parties.

Just imagine, if the user has uploaded a file with 10K records in a file it will take an hour to do this in a single process.

Here is where we used the Laravel Jobs & Queues where we can let use relax and we do our processing in backend with multiple Jobs running at the same time.

So we came up with architecture with Several Jobs in place with the following things in mind.

  1. We will have multiple Jobs to perform multiple things to have SRP (Single Responsibility Principle)
  2. When the one Job completes its duty, it will dispatch the next Job with the data that next job needs.
  3. The next job will do that same till the process ends

Another advantage we got here is, we can execute different jobs on different machines/servers based on the resources required. For e.g. We run a Job of Creating PDF on a powerful machine then sending an email.

Also, we can set different priorities for different Job Listeners. For e.g. Sending an Email Job will have a lower priority than others.

So here is the architecture that we came up with and used. I tried to architect the Jobs structure only and haven't mentioned small details of updating and creating records.

Implementing Efficient and Fast Data Import with Laravel Jobs & Queues

Hope it will help you to architect you a better Jobs and Queues architecture where you need to perform multiple things on the backend and do not let your users wait to finish those long-running processes.

Happy & Safe Queuing. :)

August 14, 20202 minutesauthorMitul Golakiya
post
Laravel Livewire is used to build dynamic web pages that work without ajax or any javascript code. we can build dynamic components with livewire with less code and more functionalities.

I hope this basic introduction will be enough to start laravel livewire.

Now let's move to installation steps, and I hope you already have setup your laravel project.

Install Livewire

 composer require livewire/livewire

Include the javascript and styles (On your master blade file)

  ...
     @livewireStyles
  </head>
  <body>
  ...

     @livewireScripts
  </body>
  </html>

Create Your Component

Here we are going to create a component to create a summation of 2 values without hitting any buttons, it will do a summation of 2 values as you type in text boxes.

Now let's create our component by hitting the following command :

php artisan make:livewire Summation

it will create 2 files as shown below:

// app/Http/Livewire/Summation/php
namespace App\Http\Livewire;

use Livewire\Component;

class Summation extends Component
{
    public function render()
    {
        return view('livewire.summation');
    } 
}

// resources/views/livewire/summation.blade.php
<div>
    ...
</div>

Include the component

Include created component to your view where you want to show.

 <head>
    ...
    @livewireStyles
 </head>
 <body>
    <livewire:summation />

    ...

    @livewireScripts
 </body>
 </html>

Now let's first do a change in our livewire component Summation.php

namespace App\Http\Livewire;

use Livewire\Component;

class Summation extends Component
{ 
   public $value1 = 0;
   public $value2 = 0;
   public $sum = 0;

   public function mount()
   {
      $this->sum = 0;
   }

   public function render()
   {
      $this->sum = $this->value1 + $this->value2;

      return view('livewire.summation');
   }
 }

Here we have to take 2 public properties value1, value2 and sum. and in mount method (which will be called when the page is load the first time) I have replaced the sum property value to 0.

And In the render method, I have done a summation of the 2 public property values. which will be directly accessed values of input from blade files directly here. but how ?? we will see soon.

Now let's change the livewire blade component.

  <div>
   <input type="text" class="" wire:model="value1">

    <input type="text" class="" wire:model="value2">

    <input type="text" disabled wire:model="sum">
  </div>

Here we have bind all properties by using wire:model. so as we will type in input box 1 it will be directly accessed by $value1 into the component.

and the property $sum will be changed as we change the input box values.

So that's how cool livewire is. you can create different dynamic components as you need by using livewire.

Stay tuned to read more interesting posts of a livewire.

August 07, 20202 minutesauthorVishal Ribdiya
post

While hosting on the Laravel project on cPanel, the traditional problem that lots of developers get is, /public path is appended to the URL. Because in most cases, we put a project directly into the public_html folder, so public_html is our root for the website and that's where our laravel application is also placed.

But to run the Laravel application, we need to point our domain root to the public folder of the laravel. It is possible to do with cPanel but you need to go through some steps which are not known by most of the people and also the tedious process. So to make it simple, what you can do is, there is a way we can do it via .htaccess file in our root folder.

We can copy .htaccess file from our public folder and then make modifications to it to work with the direct root folder and route every request to the public folder.

Here is the final .htaccess file,

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews -Indexes
    </IfModule>

    RewriteEngine On

    # Handle Authorization MemberHeader
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

    # Redirect Trailing Slashes If Not A Folder...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} (.+)/$
    RewriteRule ^ %1 [L,R=301]

    # Remove public URL from the path
    RewriteCond %{REQUEST_URI} !^/public/
    RewriteRule ^(.*)$ /public/$1 [L,QSA]

    # Handle Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]
</IfModule>

By adding the above file to the root folder we can use laravel project without the public path. Check out the following two lines:

  RewriteCond %{REQUEST_URI} !^/public/
  RewriteRule ^(.*)$ /public/$1 [L,QSA]

These two lines make magic and our application will work without public path in URL.

August 01, 20201 minuteauthorMitul Golakiya
post

Recently we use Spatie laravel-multitenancy package in our of our client's CRM project along with spatie/laravel-medialibrary.

The default behavior of the media library package is, it generates a folder for each media with its ID in our configured disk, like a public folder or s3 or whatever disk we configured.

This works really great when you are dealing with a single-tenant application. But while using multi-tenant, you got a media table in each of your tenant databases. so this pattern simply doesn't work. Because then you will end up having multiple media files under the same folder from different tenants.

So what we want to do is, instead of having a structure like,

public
-- media
---- 1
------ file.jpg
---- 2
------ file.jpg
...

What we want to achieve is, we want to have a folder structure where media of every tenant will be in a separate folder with tenant unique id,

public
-- media
---- abcd1234 // tenant1 Id
------ 1
-------- file.jpg
------ 2
-------- file.jpg
---- efgh5678 // tenant2 Id
------ 1
-------- file.jpg
------ 2
-------- file.jpg
...

Spatie Media library is very configurable out of the box where you can write your own media library path generator. That is documented very well over here: https://docs.spatie.be/laravel-medialibrary/v8/advanced-usage/using-a-custom-directory-structure

So what we did is, we wrote our own Path Generator, which can store files into tenants folder. Here is how it looks like,

<?php

namespace App\MediaLibrary;

use Spatie\MediaLibrary\MediaCollections\Models\Media;
use Spatie\MediaLibrary\Support\PathGenerator\DefaultPathGenerator;

class InfyCRMMediaPathGenerator extends DefaultPathGenerator
{
    /*
     * Get a unique base path for the given media.
     */
    protected function getBasePath(Media $media): string
    {
        $currentTenant = app('currentTenant');

        return $currentTenant->unique_id.DIRECTORY_SEPARATOR.$media->getKey();
    }
}

What we did here is, we just simply extended the Spatie\MediaLibrary\Support\PathGenerator\DefaultPathGenerator of Media Library and override the function getBasePath. We attached the prefix of the tenant's unique_id to the path. so instead of 1/file.png, it will return abcd1234/1/file.png.

All you need to make sure is, whenever you are uploading a media, your application should be tenant aware. Otherwise, it will not able to get the current tenant.

Hope this helps while using spatie media library along with spatie multi-tenant.

Even if you are not using a spatie multi-tenant, still you can create your own PathGenerator and use it your own way to have a media structure you want.

July 30, 20202 minutesauthorMitul Golakiya