Laravel's post

post
Payments gateways are very useful components of any e-commerce store. One of the popular payment gateways is Stripe. it's becoming more popular nowadays. 

Stripe's simple definition is : 

We bring together everything that’s required to build websites and apps that accept payments and send payouts globally. Stripe’s products power payments for online and in-person retailers, subscription businesses, software platforms and marketplaces, and everything in between.  ~ Stripe

To begin this laravel tutorial, I hope you already have fresh laravel repo.

Stripe Configuration with Laravel

Run the following command to install stripe :

composer require stripe/stripe-php
if you don't have a Stripe account, you'll want to set that up and add your API keys. Add the following to your .env file.

STRIPE_KEY=your-stripe-key
STRIPE_SECRET=your-stripe-secret

Publish Migrations Files From Stripe

php artisan vendor:publish --tag="cashier-migrations" 

And Run migrations by hitting the following command

php artisan migrate 

Setup Stripe Controller

Now create a stripe controller by hitting the following command:

php artisan make:controller StripeController
namespace App\Http\Controllers;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Stripe\Checkout\Session;
use Stripe\Exception\ApiErrorException;
/**
 * Class FeaturedCompanySubscriptionController
 */
class StripeControlle extends AppBaseController
{
    public function createSession(Request $request)
    {
        setStripeApiKey();
        $session = Session::create([
            'payment_method_types' => ['card'],
            'customer_email'       => $userEmail,
            'line_items'           => [
                [
                    'price_data'  => [
                        'product_data' => [
                            'name' => 'Make '.$company->user->first_name.' as featured Company',
                        ],
                        'unit_amount'  => 100 * 100,
                        'currency'     => 'USD',
                    ],
                    'quantity'    => 1,
                    'description' => '',
                ],
            ],
            'client_reference_id'  => '1234',
            'mode'                 => 'payment',
            'success_url'          => url('payment-success').'?session_id={CHECKOUT_SESSION_ID}',
            'cancel_url'           => url('failed-payment?error=payment_cancelled'),
        ]);
        $result = [
            'sessionId' => $session['id'],
        ];
        return $this->sendResponse($result, 'Session created successfully.');
    }
    public function paymentSuccess(Request $request)
    {
        $sessionId = $request->get('session_id');
        // 
    }
   
    public function handleFailedPayment()
    {
        // 
    }
}

Define Routes

    Route::post('stripe-charge', 'StripeController@createSession');
    Route::get('payment-success', 'StripeController@paymentSuccess');
    Route::get('failed-payment',  'StripeController@handleFailedPayment');

Setup From View file


Here we are going to create stripe session from backend and redirect to stripe checkout page once we will receive the sessionId from backend.
Assume that makePaymentURL is something like "APP_URL/stripe-charge".
Now let's say when you hit the submit form of stripe it will call MakePaymentURL and that URL returns your session ID which we will use to redirect to the stripe checkout page. 

 $(document).on('click', '#makePayment', function () {
           
        $(this).addClass('disabled');
        $.post(makePaymentURL, payloadData).done((result) => {
            let sessionId = result.data.sessionId;
            stripe.redirectToCheckout({
                sessionId: sessionId,
            }).then(function (result) {
                $(this).html('Make Featured').removeClass('disabled');
                manageAjaxErrors(result);
            });
        }).catch(error => {
            $(this).html('Make Featured').removeClass('disabled');
            manageAjaxErrors(error);
        });
    });
That's it, after entering proper details into stripe you will get a success callback to a related route, where you can perform related actions. 
Invalid date2 minutesauthorVishal Ribdiya
post
While developing complex applications, sometimes we have to validate fields and data in a totally customized way, at that time you can use laravel's custom validations rules functionality. 

In this tutorial, we are going to create our own custom validation rule to compare UUID. In our case, I have to check the UUID which is actually a binary string, that exists on DB or not.
Laravel doesn't provide any rule to compare that binary UUID string, so we will create our own validation rule. 

So let's create our custom validation rule::

Generate Custom Validation Class

So here we have created new class with named UuidExists into App\Rules

namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
use Ramsey\Uuid\Uuid;
class UuidExists implements Rule
{
   
    protected $table;
    protected $column;

    public function __construct($table, $column)
    {
        $this->table = $table;
        $this->column = $column;
    }
    public function passes($attribute, $value)
    {
        $value = Uuid::fromString(strtolower($value))->getBytes();
        return \DB::table($this->table)->where($this->column, $value)->exists();
    }
    public function message()
    {
        return 'The validation error message.';
    }
}


Add Rule to AppService Provider

Add your rule to AppServiceProvider.php into boot() method. here I have to give the named uuid_exists to my custom rule. you can give your own name whatever you want. 

\Validator::extend('uuid_exists', function ($attribute, $value, $parameters, $validator) {
  list($table, $column) = $parameters;
  return (new UuidExists($table, $column))->passes($attribute, $value);
});

How to use custom Rule ?

You can use your custom rule as follows. here we have using required and uuid_exists rule, where we are passing attribute and values to our custom rule, which will be used to passes($attribute, $value) function.

'tenant_id' => ['required', 'uuid_exists:tenant_id,uuid']

Keep connected to us for more interesting posts about Laravel.


January 18, 20211 minuteauthorVishal Ribdiya
post

Here we will learn how to send real-time notifications using Pusher + Laravel.

First of all, you need to create an account in the Pusher and get API keys from there.

Setting up your Laravel application

Now we need to install Pusher SDK, you can install it by the composer using the below command,

composer require pusher/pusher-php-server

After the composer is done, we will need to configure Laravel to use Pusher as its broadcast driver, update the below variables in the .env file,

PUSHER_APP_ID=123456
BROADCAST_DRIVER=pusher

// Get the API Keys from your pusher dashboard

PUSHER_APP_ID=XXXXX
PUSHER_APP_KEY=XXXXXXX
PUSHER_APP_SECRET=XXXXXXX

Open config/app.phpand uncomment the "App\Providers\BroadcastServiceProvider::class".

Now we need an event that will broadcast to the pusher driver. Let's create a NotificationEvent.

php artisan make:event NotificationEvent

This command will create a below file

namespace App\Events;
use Illuminate\Queue\SerializesModels;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class NotificationEvent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;
    public $username;
    public $message;
    public function __construct($username)
    {
        $this->username = $username;
        $this->message  = "{$username} send you a notification";
    }
    public function broadcastOn()
    {
        //it is a broadcasting channel you need to add this route in channels.php file
        return ['notification-send'];
    }
}

Add broadcasting route in channels.php file

Broadcast::channel('notification-send', function ($user) {
    return true;
}); 

Cache Event at Javascript Side

// Initiate the Pusher JS library

var pusher = new Pusher('YOUR_API_KEY', {
    encrypted: true
});

// Subscribe to the channel we used in our Laravel Event

var channel = pusher.subscribe('notification-send');
channel.bind('App\\Events\\NotificationEvent', function(data) {
    // this is called when the event notification is received...
});

Testing and Setup

Using the below route we can send a notification.

Route::get('test', function () {
    event(new App\Events\NotificationEvent('Monika'));
    return "Event has been sent!";
});
January 18, 20211 minuteauthorMonika Vaghasiya
post
Hope you guys are familiar with Spatie Media Library. It's a very useful and time-saving package to manage file uploading.

It's also providing support to convert your images to thumbnails while storing images. you can generate a thumbnail of the image with the size (height, width) you want.

They are calling thumbnails to Conversions. You can generate multiple thumbnails with different sizes as you want.

So let's see some short example which helps us to create thumbnails of an uploaded image.

Implement the HasMediaTrait into your Model 

Here we have a User model and we want to generate a thumbnail of the user upload his profile image. you have to add  HasMediaTrait to the User model and need to extend  HasMedia.

use IlluminateDatabaseEloquentModel;
use SpatieMediaLibraryModelsMedia;
use SpatieMediaLibraryHasMediaHasMedia;
use SpatieMediaLibraryHasMediaHasMediaTrait;

class User extends Model implements HasMedia
{
    use HasMediaTrait;

    public function registerMediaConversions(Media $media = null)
    {
        $this->addMediaConversion('profile-thumb')
              ->width(150)
              ->height(150);
    }
}

Here we have defined function registerMediaConversions in which we can manage the size of a thumbnail, which means how much height or width we want for the thumbnail.

So when we upload an image using the media library, 

$media = User::first()->addMedia($pathToImage)->toMediaCollection();
it will auto-generate the thumbnails with given height and width. 

How to fetch the generated thumbnail? 












$media->getPath();  // the path to the where the original image is stored
$media->getPath('profile-thumb') // the path to the converted image with dimensions 150*150

$media->getUrl();  // the url to the where the original image is stored
$media->getUrl('profile-thumb') // the url to the converted image with dimensions 150*150

How to generate multiple thumbnails for a single image? 








..... in User Model .....
use SpatieImageManipulations;


    public function registerMediaConversions(Media $media = null)
    {
        $this->addMediaConversion('profile-thumb')
              ->width(150)
              ->height(150);
    }

        $this->addMediaConversion('old-profile-thumb')
              ->sepia()
              ->border(8, 'black', Manipulations::BORDER_OVERLAY);
    }
so, it will generate 2 thumbnails with different image properties. you can use different image properties directly while generating thumbnails.

That's it, you can read more about the spatie media library conversions (thumbnails) here

Keep connected to us for more interesting posts about laravel.  


January 05, 20212 minutesauthorVishal Ribdiya
post
Zoom Marketplace is providing APIs to create zoom meeting direct using the web interface and calling its API. So first of you need to create your zoom ap into zoom marketplace and need to generate the API Keys and credentials.

Create a Zoom Application
  1. Go to Zoom marketplace and do sign in
  2. Click Develop button on header and select Build App menu.
  3. Choose the JWT and create an application with the app name that you want.
  4. Input required information and click Continue until your app will be activated. 
I hope you already have installed fresh laravel. now you have to add the following packages to your composer.json  to integrate the zoom API.

composer require firebase/php-jwt
composer require guzzlehttp/guzzle
And Now run composer update

And don't forget that we also need to modify .env files to set the zoom API credentials.

ZOOM_API_URL="https://api.zoom.us/v2/"
ZOOM_API_KEY="INPUT_YOUR_ZOOM_API_KEY"
ZOOM_API_SECRET="INPUT_YOUR_ZOOM_API_SECRET"

You can find the zoom credentials from your zoom app.

Now just copy given ZoomMeetingTrait to your controller and call-related methods.

<?php

namespace
App\Traits;

use GuzzleHttp\Client;
use Log;

/**
 * trait ZoomMeetingTrait
 */
trait
ZoomMeetingTrait
{
    public $client;
    public $jwt;
    public $headers;

    public function __construct()
    {
        $this->client = new Client();
        $this->jwt = $this->generateZoomToken();
        $this->headers = [
            'Authorization' => 'Bearer '.$this->jwt,
            'Content-Type'  => 'application/json',
            'Accept'        => 'application/json',
        ];
    }
    public function generateZoomToken()
    {
        $key = env('ZOOM_API_KEY', '');
        $secret = env('ZOOM_API_SECRET', '');
        $payload = [
            'iss' => $key,
            'exp' => strtotime('+1 minute'),
        ];

        return \Firebase\JWT\JWT::encode($payload, $secret, 'HS256');
    }

    private function retrieveZoomUrl()
    {
        return env('ZOOM_API_URL', '');
    }

    public function toZoomTimeFormat(string $dateTime)
    {
        try {
            $date = new \DateTime($dateTime);

            return $date->format('Y-m-d\TH:i:s');
        } catch (\Exception $e) {
            Log::error('ZoomJWT->toZoomTimeFormat : '.$e->getMessage());

            return '';
        }
    }

    public function create($data)
    {
        $path = 'users/me/meetings';
        $url = $this->retrieveZoomUrl();

        $body = [
            'headers' => $this->headers,
            'body'    => json_encode([
                'topic'      => $data['topic'],
                'type'       => self::MEETING_TYPE_SCHEDULE,
                'start_time' => $this->toZoomTimeFormat($data['start_time']),
                'duration'   => $data['duration'],
                'agenda'     => (! empty($data['agenda'])) ? $data['agenda'] : null,
                'timezone'     => 'Asia/Kolkata',
                'settings'   => [
                    'host_video'        => ($data['host_video'] == "1") ? true : false,
                    'participant_video' => ($data['participant_video'] == "1") ? true : false,
                    'waiting_room'      => true,
                ],
            ]),
        ];

        $response =  $this->client->post($url.$path, $body);

        return [
            'success' => $response->getStatusCode() === 201,
            'data'    => json_decode($response->getBody(), true),
        ];
    }
   
    public function update($id, $data)
    {
        $path = 'meetings/'.$id;
        $url = $this->retrieveZoomUrl();

        $body = [
            'headers' => $this->headers,
            'body'    => json_encode([
                'topic'      => $data['topic'],
                'type'       => self::MEETING_TYPE_SCHEDULE,
                'start_time' => $this->toZoomTimeFormat($data['start_time']),
                'duration'   => $data['duration'],
                'agenda'     => (! empty($data['agenda'])) ? $data['agenda'] : null,
                'timezone'     => 'Asia/Kolkata',
                'settings'   => [
                    'host_video'        => ($data['host_video'] == "1") ? true : false,
                    'participant_video' => ($data['participant_video'] == "1") ? true : false,
                    'waiting_room'      => true,
                ],
            ]),
        ];
        $response =  $this->client->patch($url.$path, $body);

        return [
            'success' => $response->getStatusCode() === 204,
            'data'    => json_decode($response->getBody(), true),
        ];
    }
   
    public function get($id)
    {
        $path = 'meetings/'.$id;
        $url = $this->retrieveZoomUrl();
        $this->jwt = $this->generateZoomToken();
        $body = [
            'headers' => $this->headers,
            'body'    => json_encode([]),
        ];

        $response =  $this->client->get($url.$path, $body);

        return [
            'success' => $response->getStatusCode() === 204,
            'data'    => json_decode($response->getBody(), true),
        ];
    }

    /**
     *
@param string $id
     *
     *
@return bool[]
     */
    public function
delete($id)
    {
        $path = 'meetings/'.$id;
        $url = $this->retrieveZoomUrl();
        $body = [
            'headers' => $this->headers,
            'body'    => json_encode([]),
        ];

        $response =  $this->client->delete($url.$path, $body);
       
        return [
            'success' => $response->getStatusCode() === 204,
        ];
    }
}
And add the following constants to your controller.

const MEETING_TYPE_INSTANT = 1;
const MEETING_TYPE_SCHEDULE = 2;
const MEETING_TYPE_RECURRING = 3;
const MEETING_TYPE_FIXED_RECURRING_FIXED = 8;
So the final controller will look like, 


<?php

namespace
App\Http\Controllers;

use App\Models\ZoomMeeting;
use App\Traits\ZoomMeetingTrait;
use Illuminate\Http\Request;

class MeetingController extends AppBaseController
{
    use ZoomMeetingTrait;

    const MEETING_TYPE_INSTANT = 1;
    const MEETING_TYPE_SCHEDULE = 2;
    const MEETING_TYPE_RECURRING = 3;
    const MEETING_TYPE_FIXED_RECURRING_FIXED = 8;

    public function show($id)
    {
        $meeting = $this->get($id);

        return view('meetings.index', compact('meeting'));
    }

    public function store(Request $request)
    {
        $this->create($request->all());

        return redirect()->route('meetings.index');
    }

    public function update($meeting, Request $request)
    {
        $this->update($meeting->zoom_meeting_id, $request->all());

        return redirect()->route('meetings.index');
    }

    public function destroy(ZoomMeeting $meeting)
    {
        $this->delete($meeting->id);

        return $this->sendSuccess('Meeting deleted successfully.');
    }
}

So this is all you need to integrate zoom API, so easy 😊  Right. Enjoy the code. 
December 26, 20201 minuteauthorVishal Ribdiya
post
Nowdays, laravel livewire is becoming more trendy for geeks. as most of developers are using it, more and more issues they are facing while developing the products. one of them is searching the records. 

Recently we have developed the livewire common searchable component which makes your searching easier, as you can specify which fields you want to search by just giving the field name into the component.

What you have to do is just create SearchableComponent a class into your App\Http\Livewire directory.  just copy the following class on the given namespace.

<?php

namespace App\Http\Livewire;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Livewire\Component;
use Livewire\WithPagination;
use Str;

abstract class SearchableComponent extends Component
{
    use WithPagination;

    /**
     * @var string
     */
    public $search = '';

    /**
     * @var int
     */
    protected $paginate = 12;

    /** @var Builder */
    private $query;

    /**
     * SearchableComponent constructor.
     *
     * @param $id
     */
    public function __construct($id)
    {
        parent::__construct($id);

        $this->prepareModelQuery();
    }

    /**
     *  Prepare query
     */
    private function prepareModelQuery()
    {
        /** @var Model $model */
        $model = app($this->model());

        $this->query = $model->newQuery();
    }

    /**
     * @return mixed
     */
    abstract function model();

    /**
     * Reset model query
     */
    protected function resetQuery()
    {
        $this->prepareModelQuery();
    }

    /**
     * @return Builder
     */
    protected function getQuery()
    {
        return $this->query;
    }

    /**
     * @param  Builder  $query
     */
    protected function setQuery(Builder $query)
    {
        $this->query = $query;
    }

    /**
     * @param  bool  $search
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
     */
    protected function paginate($search = true)
    {
        if ($search) {
            $this->filterResults();
        }

        $all = $this->query->paginate($this->paginate);
        $currentPage = $all->currentPage();
        $lastPage = $all->lastPage();
        if ($currentPage > $lastPage) {
            $this->page = $lastPage;
        }

        return $this->query->paginate($this->paginate);
    }

    /**
     * @return Builder
     */
    protected function filterResults()
    {
        $searchableFields = $this->searchableFields();
        $search = $this->search;

        $this->query->when(! empty($search), function (Builder $q) use ($search, $searchableFields) {
            $searchString = '%'.$search.'%';
            foreach ($searchableFields as $field) {
                if (Str::contains($field, '.')) {
                    $field = explode('.', $field);
                    $q->orWhereHas($field[0], function (Builder $query) use ($field, $searchString) {
                        $query->whereRaw("lower($field[1]) like ?", $searchString);
                    });
                } else {
                    $q->orWhereRaw("lower($field) like ?", $searchString);
                }
            }
        });

        return $this->query;
    }

    /**
     * @return mixed
     */
    abstract function searchableFields();
}
Now you have to extend your existing laravel component by SearchableComponent. let's say we already have Tags livewire component. and its looks like following.

<?php

namespace App\Http\Livewire;

use App\Models\Tag;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;

class Tags extends SearchableComponent
{
    public function render()
    {
        $tags = $this->searchTags();

        return view('livewire.tags', [
            'tags' => $tags,
        ])->with("search");
    }

    /**
     * @return LengthAwarePaginator
     */
    public function searchTags()
    {
        $this->setQuery($this->getQuery());

        return $this->paginate();
    }

    function model()
    {
        return Tag::class;
    }

    function searchableFields()
    {
        return [
            'name',
        ];
    }
}
So here we have extended our existing Tags component by SearchingComponent.  

In searchable fields you can specify the field name that you want to search. and replace the Model with your records Model.

That it. Now you don't need to write search queries again and again. just extend your livewire component by searchable component.

Here are some Interesting livewire tutorials that you need to check :


December 19, 20201 minuteauthorVishal Ribdiya
post
Most of the developers are facing select2 styles removing issue when livewire render the component.

We can resolve this issue by using a livewire javascript hook.

Here is my screen with select2 before livewire component rendering.
select2-after-renrering-livewire-component
select2-before-livewire-render.png 37.21 KB


And when the livewire component is refreshed means re-render the select2 style is gone ☹️

select2-after-renrering-livewire-component
select2-after-renrering-livewire-component.png 62.48 KB

How to Fix it ?? 🤔


Well you just need to add some JQuery code to your livewire component. here we are going to use afterDomUpdate webhook of livewire. add following code to your livewire component :


document.addEventListener('livewire:load', function (event) {
    window.livewire.hook('afterDomUpdate', () => {
        $('#select2ID').select2();
    });
});

livewire:load is listening events when livewire component is load and we can add our code within it.

And now when your livewire component is refreshed your select2 style will be still there as we are again applying it.


Other Livewire Posts :

Stay tuned to us for more interesting stuffs about livewire. 


December 11, 20201 minuteauthorVishal Ribdiya
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.

November 28, 20201 MinutesauthorMonika Vaghasiya