Laravel Posts

post

The Stripe Customer Portal is very useful for managing customer subscriptions like Upgrade, Downgrade, and Renew.

Customers can review their invoices directly and also check their history.

Portal billing setting

Do login into your stripe account

Navigate to the portal settings to configure the portal, and do below billing settings

setting

Create Product

First of all, we need to create products. Follow the below process for creating products.

Click on the “Products” menu from the sidebar and click on the “Add Product” button on the top right corner of the products page and create a product.

Here is an example of how to create a product.

Create two or three products as shown below.

product

Select product In portal settings

If you want to allow your customer to change their subscription by an upgrade, downgrade, cancel or renew you need to set products in your portal setting.

Now navigate to customer portal settings again, in the Products section, you will find a dropdown “Find or add a product..”, click on it you will find the plan you have added, select the price of this product.

portal settings

Don’t forget to save all these settings.

Then do the setup of your business information, also do branding settings in the “Appearance” section, and save it.

Once you are done with settings, you can preview the customer portal by clicking the Preview button beside the save button.

This will launch a preview of the portal so you can see how customers will use it for managing their subscriptions and billing details.

Integrate into Laravel

  • Get you API keys
    • Go to “Developers > API keys” here you will find your “Publishable key” and “Secret key

api keys

  • Create customer using stripe dashboard or by API
    • Create customer by Stripe API.
    • First of all, you’ll need to set your stripe secret key. For development mode, you can use test mode keys, but for production, you need to use your live mode keys
\Stripe\Stripe::setApiKey('sk_test_YOUR_KEY');

$customer = \Stripe\Customer::create([
    'name' => 'jenny rosen'
    'email' => 'jenny.rosen@example.com'
]);
  • Once you create a customer using stripe API, now you can create a billing session for that customer using stripe API.
    • Create a billing session of the customer by API
\Stripe\Stripe::setApiKey('sk_test_YOUR_KEY');
\Stripe\BillingPortal\Session::create([
   'customer' => 'cus_HnKDAQNjBniyFh',
   'return_url' => 'https://example.com/subscription',
]);

You’ll get a response, like the below object:

{
  "id": "pts_c5cfgf8gjfgf73m5748g6",
  "object": "billing_portal.session",
  "created": 453543534,
  "customer": "cus_bGFsnjJDcSiJu",
  "livemode": false,
  "return_url": "https://example.com/subscription'",
  "url":
"https://billing.stripe.com/session/{SESSION_SECRET}"
}

In the response body, there is a URL attribute:

Now redirect your customer to this URL immediately. For security purposes, this URL will expire in a few minutes.

After redirecting the customer to this URL, the portal will open and customers can manage their subscriptions and billing details in the portal. customers can return to the app by clicking the Return link on your company’s name or logo within the portal on the left side. They’ll redirect to the return_url you have provided at the time of creating the session or redirect URL set in your portal settings.

Listen to Webhooks

You must have a question, what is this Webhook!!!

It’s just an event, which will fire when a customer does any changes in his/her subscription in the portal, we can listen to this event in our app and make appropriate changes.

For example,

If a customer cancels his/her subscription in the portal, then how we will know about it!!

For it, when customers do any changes in his/her subscription

“customer.subscription.updated” event will be fired and we can listen for this event and, get to know the customer has changed subscription so we need to do appropriate changes in our app also.

Set webhook in your app

In the webhooks.php (in routes folder) file set up a route for handle webhook.

You can use the [Laravel Cashier Package (https://laravel.com/docs/8.x/billing) to handle webhooks.

To set up a webhook for your portal navigate to the “Developers > Webhooks” menu you will find the below screen, here I have added a webhook to handle subscription cancel and update events, it will fire when customers update subscription, and you will receive it.

webhook

Click on the “Add endpoint” button and the below pop up will open. In Endpoint URL set the route you have created in the webhooks.php file. Select subscription updated and deleted events.

webhook endpoint

All done.

For more details, you can use stripe customer portal integration

July 25, 20203 MinutesauthorMonika Vaghasiya
post

Recently Spatie released a brand new package for multi-tenancy called laravel-multitenancy.

It comes with great support to work out of the box with sub-domains like,

https://zluck.infychat.com

https://infyom.infychat.com

https://vasundhara.infychat.com

It identified the tenant based on the sub-domain and sets a database runtime for your tenant-specific models.

Recently, we used it in one of our client for Snow Removal CRM. Here we have two models,

  1. Freemium Model - with no sub-domain (application will work on main domain only)
  2. Premium Model - where the tenant will get its subdomain

And user can convert his account from Freemium to Premium at any point of time by just subscribing to the plan.

So what we want is, on the backend, we want to have a separate database for each tenant, but the application should run on main as well as a sub-domain.

So what we want to have is the ability to extend/customize the tenant detection mechanism. And Spatie does a very good job at there where you can customize the logic.

You can create your own TenantFinder class and configure it in the config file of the package. And there is very good documentation for that here: https://docs.spatie.be/laravel-multitenancy/v1/installation/determining-current-tenant/

To do that, what we did is, we have a field called tenant_id in our users table. All of our users are stored into the main database since we may have user access across the tenant.

And when any user does a login, we listen for the event Illuminate\Auth\Events\Login which is documented in Laravel Docs over here.

When a user does a login, our listener will be called and will create a cookie called tenant on the browser with the tenant id of the user. So our listener will look like,

<?php

namespace App\Listeners;

use App\Models\User;
use Cookie;
use Illuminate\Auth\Events\Login;

class LoginListener
{
    public function handle(Login $event)
    {
        /** @var User $authUser */
        $authUser = $event->user;

        Cookie::forget('tenant');
        Cookie::queue(Cookie::forever('tenant', encrypt($authUser->tenant_id)));
    }
}

Also, we encrypt the cookie on our end, so we do not want Laravel to encrypt it again, so we added tenant cookie into except array of EncryptCookies middleware as per documentation here. so our middleware looks like,

<?php

namespace App\Http\Middleware;

use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;

class EncryptCookies extends Middleware
{
    /**
     * The names of the cookies that should not be encrypted.
     *
     * @var array
     */
    protected $except = [
        'tenant'
    ];
}

Now at the last point, we extended our logic to find a tenant and get it to work on the main domain as well as sub-domain.

We have created our own custom class called InfyChatTenantFinder, which looks like,

<?php

namespace App\TenantFinder;

use App\Models\Account;
use App\Models\SubDomain;
use Illuminate\Http\Request;
use Spatie\Multitenancy\Models\Concerns\UsesTenantModel;
use Spatie\Multitenancy\Models\Tenant;
use Spatie\Multitenancy\TenantFinder\TenantFinder;

class InfyChatTenantFinder extends TenantFinder
{
    use UsesTenantModel;

    public function findForRequest(Request $request): ?Tenant
    {
        $host = $request->getHost();

        list($subDomain) = explode('.', $host, 2);

        // Get Tenant by subdomain if it's on subdomain
        if (!in_array($subDomain, ["www", "admin", "infychat"])) {
            return $this->getTenantModel()::whereDomain($host)->first();
        }

        // Get Tenant from user's account id if it's main domain
        if (in_array($subDomain, ["www", "infychat"])) {

            if ($request->hasCookie('tenant')) {
                $accountId = $request->cookie('tenant');

                $accountId = decrypt($accountId);

                $account = $this->getTenantModel()::find($accountId);

                if (!empty($account)) {
                    return $account;
                }

                \Cookie::forget('tenant');
            }
        }

        return null;
    }
}

So basically, first we check if the sub-domain is there, then find tenant from the sub-domain.

If the domain is the main domain then get the tenant id from the cookie and return the account (tenant) model.

So this is how you can customize the logic the way you want to have a custom tenant identification system.

July 24, 20203 minutesauthorMitul Golakiya
post
[Livewire](https://laravel-livewire.com/docs/2.x/quickstart) is a very awesome thing that I have ever seen, the old school developers are still using the jquery and ajax concept to not refresh the page. But forget the jquery and ajax stuff. If you are good at PHP then you can do the same with Laravel Livewire. ### Wait what? ## Load dynamic data on the page without using ajax? Yes, it is possible with Laravel Livewire. So that is all about laravel livewire, and in this tutorial, we will see how to build laravel pagination with laravel livewire. Let's start and I hope you already have set up the livewire. Let's say you already have created a component named `UsersListing` Now in the users listing, we want to paginate all users and we will list 10 records per page. ## How to use pagination with Laravel Livewire Livewire provides a trait called `WithPagination` and you have to add it into your component `UsersListing`. Check out the following code: ``` use Livewire\WithPagination; use Livewire\Component; class UsersListing extends Component { use WithPagination; public function render() { return view('livewire.users.index', [ 'users' => User::paginate(10), ]); } } ``` And to load pagination you have to add following code: ``` 
 @foreach ($users as $user) ... @endforeach {{ $users->links() }} ``` That's it, and your laravel pagination now works like charm without page refresh. There is much more about pagination like how to use it with a custom view, how to use it with a custom theme. We will see it in our next tutorial, until then enjoy the code
July 11, 20201 minuteauthorVishal Ribdiya
post
The OneSingnal is the market leader in push notification providers. It provides the mobile + web push, email & in-app messages and easy way to send notifications. OneSignal provides an officially core PHP APIs but not Laravel package. We are using OneSignal in many projects and write a bunch of line code in all projects where we needed OneSingnal.

One day I had an Idea in my mind why I should not write a Laravel wrapper for OneSignal?. Finally, I wrote the shailesh-ladumor/one-signal Laravel Wrapper for it. Using this package, we can write neat & clean code and just a few lines of code.

OneSignal add this package in his docs here.. and watch the video tutorial  here

This package also works with the previous Laravel version.

Today we are going to see how we can use Laravel OneSignal Wrapper in Laravel. Let's see step by step, how we can do that.

Install Packages

Install shailesh-ladumor/one-signal by the following command,

composer require ladumor/one-signal
Publish the config file

Run the following command to publish config file,

php artisan vendor:publish --provider="Ladumor\OneSignal\OneSignalServiceProvider"
Add Provider

Add the provider to your config/app.php into provider section if using lower version of Laravel,

Ladumor\OneSignal\OneSignalServiceProvider::class,
Add Facade

Add the Facade to your config/app.php into aliases section,

'OneSignal' => \Ladumor\OneSignal\OneSignal::class,
configure a .env file with following keys

ONE_SIGNAL_APP_ID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
ONE_SIGNAL_AUTHORIZE=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
X
ONE_SIGNAL_AUTH_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
ONE_SIGNAL_AUTH_KEY is optional if you do not want to create an app. I hope you are familiar with the OneSignal Platform and know how to get APP_ID and AUTHORIZE. If not, you should see the below image for how to get it.

So, we are done. let's check how to send push notifications.

Checkout this code to send a push notification.

use Ladumor\OneSignal\OneSignal;
$fields['include_player_ids'] = ['xxxxxxxx-xxxx-xxx-xxxx-yyyyy']
$message = 'hey!! This is a test push.!'
OneSignal::sendPush($fields, $message);
Video tutorial also available here

July 02, 20202 minutesauthorShailesh Ladumor
post

Recently, the Laravel team announced a Laravel Fortify. A framework agnostic authentication backend for laravel applications. It provides registration, authentication along with two-factor authentication.

As said above, it is a framework agnostic, so it doesn't provide any blade views with it. You can implement views of your choice of the frontend. Blade, Vue, React with Bootstrap or TailwindCSS, or any other CSS framework.

Today we are going to see how we can use Laravel Fortify with one of the most popular Bootstrap 4 theme AdminLTE v3.

We can actually do that in minutes with the package that we already developed called Laravel UI AdminLTE.

This package also works with the previous laravel version to have an authentication system with Laravel UI for Laravel Frontend Scaffolding.

Let's see step by step, how we can do that.

Install Packages

Install Laravel Fortify and Laravel UI AdminLTE by the following command,

composer require laravel/fortify infyomlabs/laravel-ui-adminlte

Publish Fortify Resources

This command will publish all required actions in the app/Actions directory along with the Fortify configuration file and migration for two-factor authentication.

php artisan vendor:publish --provider="Laravel\Fortify\FortifyServiceProvider"

Run Migrations

Then run migrations,

php artisan migrate

Add Fortify Service Provider

Next step, add published FortifyServiceProvider to config/app.php

Run AdminLTE Fortify Command

Run the following command,

php artisan ui adminlte-fortify --auth

Install Node Modules and Run a Build

As a next step, install required npm modules and run a build,

npm install && npm run dev

And we are done. Now visit the home page and you should be able to see the full authentication system working including,

  • Login
  • Registration
  • Forgot Password
  • Reset Password
  • Home page

Laravel AdminLTE UI also provides a starting layout with a sidebar menu and header once you do login. so you are all set to go.

June 27, 20202 minutesauthorMitul Golakiya
post

Sometimes we need to load a large amount of data into memory. Like all the models we have in the database.

For e.g. PDF Printing, Perform some global updates, etc.

So the general practices we use in Laravel is to write the following code,

$users = User::all();

Just imagine I have 10,000 users in the database and when I load all the users in one shot.

But it takes a really high amount of memory to load all the records and prepare Laravel Model class objects. And sometimes we also load them in chunks to save the memory, but in some use cases, chunking can not be the option.

Here is the screenshot of mine when I load 10,000 users into memory with the above code.


10k Models


It's using 37MB memory. Also, imagine the required memory if we are loading some relationships as well with these 10,000 records.

The Eloquent model is a great way to handle operations with lots of features like Mutators, Relationships, and much more.

But we really do not use these features all the time. We simply output or use the direct values which are stored in the table. So ideally, we do not need an eloquent model at all, if we are not going to use these features.

In those cases, Laravel also has a handy function toBase(). By calling this function it will retrieve the data from the database but it will not prepare the Eloquent models, but will just give us raw data and help us to save a ton of memory.

So my revised code will look something like this,

$users = User::toBase()->get();

Check the revised memory screenshot after adding the toBase function.


10k Models toBase


So it almost saves 50% of the memory. It's reduced from 35MB to 20MB and the application also works much much faster, because it doesn't need to spend time in preparing 10,000 Eloquent models.

So if you are not really going to use features of Eloquent and loading a large amount of data, then the toBase function can be really useful.

Here you can find a full video tutorial for the same.

June 21, 20202 minutesauthorMitul Golakiya
post

Recently, I've started working on one project where we follow modules pattern and for the same, we have different assets folder for the different modules and the folder named common for assets which are common across all the modules.

So our public folder looks like the following,

Module Asset Functions

The problem that I started facing was everywhere I need to give a full path to import/include any of the files from any of the folders. For e.g.

<img src="{{ asset('assets/tasks/images/delete.png') }}" alt="Delete Task">

Even if we have some folder in images to group similar images then it was even becoming longer. For e.g.

<img src="{{ asset('assets/tasks/images/social/facebook.png') }}" alt="Facebook">

The workaround that I used is, I created one file called helpers.php and created dedicated asset functions for each of the modules. For e.g., for tasks,

if (!function_exists('tasks_asset')) {
    /**
     * Generate an asset path for tasks module folder.
     *
     * @param  string  $path
     * @param  bool|null  $secure
     * @return string
     */
    function tasks_asset($path, $secure = null)
    {
        $path = "assets/tasks/".$path;
        return app('url')->asset($path, $secure);
    }
}

With this function, I can use,

<img src="{{ tasks_asset('images/delete.png') }}" alt="Delete Task">

Other advantages it gives are,

  1. if in future if the path of tasks folder changed, then I do not need to go and update every single import/include.
  2. I (or any new developer) do not need to remember the long paths and can always use direct function names for modules.

Even I like this pattern so much, so I went further and created dedicated image function as well,

if (!function_exists('tasks_image')) {
    /**
     * Generate an asset path for tasks module images folder.
     *
     * @param  string  $path
     * @param  bool|null  $secure
     * @return string
     */
    function tasks_image($path, $secure = null)
    {
        $path = "images/".$path;
        return tasks_asset($path, $secure);
    }
}

So I can use it as,

<img src="{{ tasks_image('delete.png') }}" alt="Delete Task">

Simple and handy functions to use everywhere.

May 16, 20202 minutesauthorMitul Golakiya
post

Last month, I got consulting of one Laravel project where we have to perform some complex validations.

The scenario was while creating an order, either customer can select the existing address from the dropdown or he may have an option to create a new address with all address fields.

And when a customer hits enter, the backend needs to validate, if address_id is sent into request then it needs to check if that address id exists and then use that address_id for that particular order. Otherwise, it needs to check if required fields (address1, city, zip, country) for address are sent then use them, create a new address and use that new address_id.

so far how validation was happening was manual, so in controller this all manual validation was happening. But I don't find that a proper way. The goal was to do validation from CreateOrderRequest only. so it goes back with proper laravel error messages from a request only and displays them on the page. so we actually do not need to make any manual efforts to make this happen.

That's where required_without validation rule helped us.

The UI was something like this,

required-without-laravel-validation-rule.png

In the above UI, customers can either type Address1, Address2, City and Zip or just go and select an existing address from the dropdown.

To do this validation from form request, we used the required_without rule as following, 'address_id' => 'required_without:address_1,city,zip|sometimes|nullable|exists:addresses,id',

Now let's try to understand what's happening here. To understand it better let's divide the rules

  1. required_without:address_1,city,zip
  2. sometimes
  3. nullable
  4. exist:addresses,id

1. required_without:address _1,city,zip

This rule validates that address_id field is required without the presence of address_1, city and zip fields

2. sometimes

This means, address_id fields will be passed only sometimes and not required all the time. We need this because when address_1, city and zip fields will be present then we do not need it at all.

3. nullable

This means, address_id fields can be null since it will be null when a customer does not select the address from the dropdown.

4. exist:addresses,id

The passed value in address_id fields, must exist in the addresses table.

So this is how we solved this complex validation in a very easy way by using multiple powerful laravel validation rules.

Hope this can help others as well.

January 07, 20202 minutesauthorMitul Golakiya