Laravel Posts

post

Generally, we are using a Swagger in Laravel. it will take time if we set up swagger manually. so, In this article, I going to show you very easy steps for setup in Laravel.

You can watch the following video tutorial as well.

Steps 1:

You should download these assets from here. unzip the folder and go to the public directory. you can found the swagger directory in the side public folder. let open the swagger directory and you can see the following files.

  • jquery-2.1.4.min.js
  • style.css
  • swagger-bundle.js
  • swagger.yaml

If are you still confuse then visit this link for files.

now, Copy the swagger directory and put it in your laravel application on the same path.

Steps 2:

We need to load swagger with proper swagger UI. so, let navigate to resources/views on the downloaded source code project.

You can see the swagger directory inside the views directory. copy the swagger directory to your laravel application on the same path. I don't think you need to do anything in this view file. let's go to the next step.

Steps 3:

You need to update this swagger.yaml file. you should update the following details first. and then add APIs documentation in this file. Api document example given here. you can refer it.

info:
  description: LPT APis
  version: 1.0.0
  title: LPT Frontend API's
basePath: /api/

Steps 4:

In this step, you need to create a route for loading swagger docs. so, let's open the web.php file add the following few lines of code.

Route::get('/docs', function () {
    return view('swagger.index');
});

Now, run a command php artisan serve and open http://127.0.0.1:8000/docs or open a virtualHostDomain/docs if you have one.

You should watch this tutorial as well if you using InfyOm Generator

September 22, 20212 minutesauthorShailesh Ladumor
post

Nowadays multi-tenant applications are more useful than single-tenant applications. We can use multi-tenant with multiple databases or single databases as per our need. But it's better to use a single DB with a multi-tenant when you have a small application.

In this tutorial, we are going to use multi-tenant with a single database.

We will implement multi-tenant with single DB by using the following package: https://github.com/archtechx/tenancy

Assuming you already have Laravel 8 repo setup. Now please follow the given steps to implement multi-tenancy with a single DB.

Package Installation

Run following commands :

  1. composer require stancl/tenancy

  2. php artisan tenancy:install

  3. php artisan migrate

Add following service provider to config/app.php

App\Providers\TenancyServiceProvider::class

Create Custom Model

Now create modal named MultiTenant into app\Models

MultiTenant.php

 SavingTenant::class,
        'saved'    => TenantSaved::class,
        'creating' => CreatingTenant::class,
        //        'created' => TenantCreated::class,
        'updating' => UpdatingTenant::class,
        'updated'  => TenantUpdated::class,
        'deleting' => DeletingTenant::class,
        'deleted'  => TenantDeleted::class,
    ];
}

Update Tenancy Configuration

As we have added custom model we also need to define that model into config/tenancy.php

Please change tenant_model value to our custom model.

'tenant_model' => \App\Models\MultiTenant::class,

Add Resolver

To use multi tenant with single DB we also need to add our customer resolver, that will be used into Middlewares that we will create ahead.

Create MultiTenantResolver into app\Resolvers

App\Resolvers\MultiTenantResolver.php

find(Auth::user()->tenant_id)) {
            return $tenant;
        }

        throw new TenantCouldNotBeIdentifiedByPathException($id);
    }

    public function getArgsForTenant(Tenant $tenant): array
    {
        return [
            [$tenant->id],
        ];
    }
}

Add Middleware

We will create our custom middleware that will set the current tenant into cache, and that will used by package to fire default query where('tenant_id', "tenant id we have set into middleware")

App\Http\Middleware\MultiTenantMiddleware.php

tenancy = $tenancy;
        $this->resolver = $resolver;
    }

    /**
     * Handle an incoming request.
     *
     * @param  Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $tenant = Auth::user()->tenant_id;

        return $this->initializeTenancy(
            $request, $next, $tenant
        );
    }
}

Also, don't forget to add middleware alias into App\Http\kernel.php

 protected $routeMiddleware = [
        ..............
        'multi_tenant' => MultiTenantMiddleware::class,
];

Now we will apply this multi_tenant middleware to our routes.

Add Trait to tenant-specific models

We have to add BelongsToTenant trait to all of our tenant-specific models.

Say if we want to add tenant_id into the users table then we must have to add BelongsToTenant to the app\Models\User model.

That trait will by default add following query everytime when we will try to fetch records or update records.

Where('tenant_id', 'tenant id will taken from cache')

Add tenant_id to tenant-specific migrations

As we have added the tenant trait, we must have to add tenant_id into tenant-specific migrations as specified below.

public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            ...........................

            $table->string('tenant_id');

            $table->foreign('tenant_id')
                ->references('id')
                ->on('tenants')
                ->onUpdate('cascade')
                ->onDelete('cascade');

            $table->timestamps();
        });

Update TenancyServiceProvider

Replace the App\Providers\TenactServiceProvider by the following code.

 [],
            Events\TenantCreated::class => [
                JobPipeline::make([
                    Jobs\CreateDatabase::class,
                    Jobs\MigrateDatabase::class,
                    // Jobs\SeedDatabase::class,

                    // Your own jobs to prepare the tenant.
                    // Provision API keys, create S3 buckets, anything you want!

                ])->send(function (Events\TenantCreated $event) {
                    return $event->tenant;
                })->shouldBeQueued(false), // `false` by default, but you probably want to make this `true` for production.
            ],
            Events\SavingTenant::class => [],
            Events\TenantSaved::class => [],
            Events\UpdatingTenant::class => [],
            Events\TenantUpdated::class => [],
            Events\DeletingTenant::class => [],
            Events\TenantDeleted::class => [
                JobPipeline::make([
                    Jobs\DeleteDatabase::class,
                ])->send(function (Events\TenantDeleted $event) {
                    return $event->tenant;
                })->shouldBeQueued(false), // `false` by default, but you probably want to make this `true` for production.
            ],

            // Domain events
            Events\CreatingDomain::class => [],
            Events\DomainCreated::class => [],
            Events\SavingDomain::class => [],
            Events\DomainSaved::class => [],
            Events\UpdatingDomain::class => [],
            Events\DomainUpdated::class => [],
            Events\DeletingDomain::class => [],
            Events\DomainDeleted::class => [],

            // Database events
            Events\DatabaseCreated::class => [],
            Events\DatabaseMigrated::class => [],
            Events\DatabaseSeeded::class => [],
            Events\DatabaseRolledBack::class => [],
            Events\DatabaseDeleted::class => [],

            // Tenancy events
            Events\InitializingTenancy::class => [],
            Events\TenancyInitialized::class => [
//                Listeners\BootstrapTenancy::class,
            ],

            Events\EndingTenancy::class => [],
            Events\TenancyEnded::class => [
                Listeners\RevertToCentralContext::class,
            ],

            Events\BootstrappingTenancy::class => [],
            Events\TenancyBootstrapped::class => [],
            Events\RevertingToCentralContext::class => [],
            Events\RevertedToCentralContext::class => [],

            // Resource syncing
            Events\SyncedResourceSaved::class => [
                Listeners\UpdateSyncedResource::class,
            ],

            // Fired only when a synced resource is changed in a different DB than the origin DB (to avoid infinite loops)
            Events\SyncedResourceChangedInForeignDatabase::class => [],
        ];
    }

    public function register()
    {
        //
    }

    public function boot()
    {
        $this->bootEvents();
//        $this->mapRoutes();

        $this->makeTenancyMiddlewareHighestPriority();
    }

    protected function bootEvents()
    {
        foreach ($this->events() as $event => $listeners) {
            foreach (array_unique($listeners) as $listener) {
                if ($listener instanceof JobPipeline) {
                    $listener = $listener->toListener();
                }

                Event::listen($event, $listener);
            }
        }
    }

    protected function mapRoutes()
    {
        if (file_exists(base_path('routes/tenant.php'))) {
            Route::namespace(static::$controllerNamespace)
                ->group(base_path('routes/tenant.php'));
        }
    }

    protected function makeTenancyMiddlewareHighestPriority()
    {
        $tenancyMiddleware = [
            // Even higher priority than the initialization middleware
            Middleware\PreventAccessFromCentralDomains::class,

            Middleware\InitializeTenancyByDomain::class,
            Middleware\InitializeTenancyBySubdomain::class,
            Middleware\InitializeTenancyByDomainOrSubdomain::class,
            Middleware\InitializeTenancyByPath::class,
            Middleware\InitializeTenancyByRequestData::class,
        ];

        foreach (array_reverse($tenancyMiddleware) as $middleware) {
            $this->app[\Illuminate\Contracts\Http\Kernel::class]->prependToMiddlewarePriority($middleware);
        }
    }
}

Create / Fetch Tenant

Now we have to create a tenant and give that tenant_id to related users.

each user contains their specific tenant_id.

Use the following code to create a tenant :

 $tenant1 = \App\Models\MultiTenant::create([
     'name' => 'Tenant 1'
 ]);

 $tenant2 = \App\Models\MultiTenant::create([
     'name' => 'Tenant 2'
  ]);

That will create tenant into tenants table and values will be stored into data column as a son.

$tenant1 = App\Models\MultiTenant::where('data->name', 'Tenant 1')->first();

$tenant2 = App\Models\MultiTenant::where('data->name', 'Tenant 2')->first();

$tenant1User = User::where('id', 'user id here')->update(['tenant_id' => $tenant1->id]);

$tenant2User = User::where('id', 'user id here')->update(['tenant_id' => $tenant2->id]);

Now we have 2 tenants with 2 separate users who contain separate tenant ids.

Add Middleware to Routes

Now do login with User 1 and try to fetch all users from the database, it will return users of logged-in users' tenants only.

As we have the BelongToTenant trait into the User model.

Route::group(['middleware' => ['auth', 'multi_tenant']], function () { Route::get('users', function() {

 // only tenant-1 users will be returned because we are setting the logged-in user tenant into the cache from `multi_tenant`middleware.
 $allUsers = User::all();
});

});

You can use the same for other models too.

Hope this helps you.

August 14, 20212 minutesauthorVishal Ribdiya
post

Nowadays, people are hacking secure data systems, so will See the security testing criteria for reCAPTCHA forms.

reCAPTCHA is a technology that assesses the probability that the entity that uses your web code (page, app, portal, etc.) is a human and not a bot (or the other way around). Grabbing information of behavior (of a user or a bot) encapsulates it in the token that gets sent to your server. On your server, the token is being sent again to Google for returning the assessment on how probable it is that the token was generated by a human. Part of the response returned from Google to your server:

Let's See the points how to Test 🛠️

First, we validate from the frontend

on any reCAPTCHA from removing that div from inspect element and then trying to save there must be valid and records should not store on the backend as shown in the image.

2021-07-22-60f90c027ead1

Remove this div then save the form there should be a validation message for reCAPTCHA verification and the form should not be saved, if the form is submitted then the data were stored in the data table which was False to the system.

Now Let's see how we validate from the postman

First, add testing form URL on browser and apply Post method and on body add all fields which are added in form lets see on the image.

2021-07-22-60f90c12e0f33

Now add on the header at Key column CSRF token, X-Requested, cookie and add its perspective value as shown in the image.

CSRF token and XSRF-TOKEN will store in the cookie which will get from the front page from inspect element.

2021-07-22-60f90c2315082

Now, click on send request and validate the status should be false as shown in the image

2021-07-22-60f90c3081ca1

If the status changes to true, then the data stored in a table & will create a problem, and the reCAPTCHA form will validate false.

Hence, reCAPTCHA form Test, Hope this helps.

July 24, 20213 minutesauthorShailesh Ladumor
post

Generally, we are using a Laravel One Signal package for push notification. if you are planning to use one signal in the mobile application then this package right for you.

Recently, I add a new feature UserDevice. let me explain why I added support for user Device APIs.

We need to create an API to register a device because One Signal sends a push notification using os player id. so, we need to store os_player_id in the backend from the mobile application. So, need to create an API for it.

Now. you can save your time using this package. you can Generate APIs using one artisan command,

php artisan one-signal.userDevice:publish

This command generates the following files,

  • UserDeviceAPIController
  • UserDeviceAPIRepository
  • UserDevice (model)
  • Migration So, everything is ready in minutes and delivered an API on the spot.

Also, do not forget to add the following routes to the api.php file.

use App\Http\Controllers\API\UserDeviceAPIController;

Route::post('user-device/register', [UserDeviceAPIController::class, 'registerDevice']);
Route::get('user-device/{playerId}/update-status', [UserDeviceAPIController::class, 'updateNotificationStatus']);

If you are a good Eye listener then you should watch the video tutorial

July 08, 20211 minuteauthorShailesh Ladumor
post

People nowadays are becoming more intelligent, so better to protect our application's content/data from those who are calling themself hackers.

One of the best examples is the data URLs from AWS buckets. it's not a good idea to store sensitive data into a public AWS Bucket, as the URL is accessible by the people.

Of Course, you can store profile avatars and others data to the public bucket's that not contains any confidential information. so that's fine.

But when it's about confidential information like PAN CARD Details, AADHAR Card Details, Bank Informations we Must Recommend using AWS Protected Bucket.

In this tutorial, we are going to show that how we can prevent that kind of case, Or how we can integrate AWS Protected Bucket in our Laravel Application.

The following code will help you to generate a pre-signed AWS URL that will prevent our data, that URL is non-guessable and it will expire within some minutes/hours specified by us.

So let's start with some code :

$s3 = \Storage::disk(config('filesystems.s3_protected_disk'));
$client = $s3->getDriver()->getAdapter()->getClient();
$expiry = "+1 minutes";
$command = $client->getCommand('GetObject', [
  'Bucket' => \Config::get('filesystems.disks. s3_protected_disk.bucket'),
      'Key'    => 'Path to your file',
    ]);
$request = $client->createPresignedRequest($command, $expiry);
    return (string) $request->getUrl();

So here we have created an s3 instance and it's stored on the $s3 variable, we have specified the expiry time as 1 minute so the given URL for data will be expired within a minute.

Also, we have to specify the bucket name and path to our protected file to generate AWS pre-signed URL.

It will return the pre-signed URL and its looks like as the following URL.

https://pre-signed.s3.au-west-2.amazonaws.com/image.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=xxxxxxxx%2F20180210%2Feu-west-2%2Fs3%2Faws4_request&X-Amz-Date=20210210T171315Z&X-Amz-Expires=60&X-Amz-Signature=xxxxxxxx&X-Amz-SignedHeaders=host

Hope this helps.

July 16, 20212 minutesauthorVishal Ribdiya
post

Today we are going to see how we can image based on resolution. We have the most common issue of loading big images in small devices take time. So, the basic solution is to use the picture element to load a different image in different devices and resolutions.

The <picture> element will be for the art direction of responsive design.

The element contains two tags.

  • <source>
  • <img>

So, the browser will look for the first <source> element where the media query matches the current width, and then it will display the image. The <picture> element is required as the last child of the <picture> element.

Let me show you an example of how to display a different image in different widths.

Here is a Code example,

<picture>
    <source media="(min-width:900px)" srcset="infyom_logo_lg.jpg">
    <source media="(min-width:700px)" srcset="infyom_logo_md.jpg">
    <source media="(min-width:500px)" srcset="infyom_logo_sm.jpg">
    <img src="infyom_logo_xl.jpg" alt="Flowers" style="width:auto;">
</picture>
June 18, 20211 minuteauthorShailesh Ladumor
post

Basically, we set up email/username and password login in all our projects. but, sometimes we need to implement s passwordless login in the laravel application,

First of all, what is passwordless login? passwordless login is an authentication method that allows the user to log in without entering a password.

In this article, I show you how to set up passwordless login laravel step by step.

Step 1:

one great laravel package Laravel Passwordless Login provides the ability to log in without a password.

This package provides a temporary signed URL link that logs in a user, What it does not provide is a way of actually sending the link to the route to the user. This is because I don't want to make any assumptions about how you communicate with your users.

Step 2:

Open the terminal and go to the project directory and fire the following command to install

composer require grosv/laravel-passwordless-login

Step 3:

Configure the following variables in your env file

LPL_USER_MODEL=App\User
  LPL_REMEMBER_LOGIN=false
  LPL_LOGIN_ROUTE=/magic-login
  LPL_LOGIN_ROUTE_NAME=magic-login
  LPL_LOGIN_ROUTE_EXPIRES=30
  LPL_REDIRECT_ON_LOGIN=/
  LPL_USER_GUARD=web
  LPL_USE_ONCE=false
  LPL_INVALID_SIGNATURE_MESSAGE="Expired or Invalid Link"

Step 4:

Create one function in your login controller. it looks like

use App\User;
use Grosv\LaravelPasswordlessLogin\LoginUrl;

function sendLoginLink(\Request $request)
{
    $user = User::where('email','=', $request->get('email))->first();

    $generator = new LoginUrl($user);
    $url = $generator->generate();

    //OR Use a Facade
    $url = PasswordlessLogin::forUser($user)->generate();

    $data['url'] = $generator->generate();
    $data['user'] = $user;

    Mail::to($user->email)->send(new UserLoginMail($data));

    return back();
}

Step 5:

Set following route in your web.php

Route::post('/user/login', [LoginController::class, 'sendLoginLink'])->name('userLogin');

Step 6:

Create one mailable. you can refer to a doc if not familiar. Also, fire the following command to create a mailable

php artisan make:mail UserLoginMail

Step 7: Create an Email UI as per your requirement.

Video tutorial available as well here

April 02, 20212 minutesauthorShailesh Ladumor
post

Lots of developers have a question: How do I create a global gitignore file? so, In this article, I show how to set up a global git ignore.

Reviewing pull requests, I often see contributors sneakily adding editor configuration to the repository’s .gitignore file.

If everyone would commit their environment-specific .gitignore rules, we’d have a long list to maintain! My repository doesn’t care about your editor configuration.

There’s a better solution to this: a personal, global .gitignore file for all your repositories. Here’s how you can set one up. create a .gitignore file for your global rules.

You need to set up your global core.excludesfile configuration file to point to this global ignore file. So, let's start step by step

Step1:

Create a file .gitignore on your profile C:\Users{username} for example C:\Users\Shailesh

Step 2:

Now you can set a .gitignore path with a three-way. we need to tell this to get this my global git to ignore file.

First Way: Using Windows git bash

Let's open Windows git bash and fire the following command,

git config --global core.excludesFile '~/.gitignore'

Second Way: Using Windows cmd

Let's open Windows cmd and fire the following command,

git config --global core.excludesFile "%USERPROFILE%\.gitignore"

Third Way: Using Windows PowerShell

Let's open Windows PowerShell and fire the following command,

git config --global core.excludesFile "$Env:USERPROFILE\.gitignore"

So, you can easily set the .gitignore global file. You can also see the video tutorial here as well.

March 06, 20211 minuteauthorShailesh Ladumor