InfyOm Blog

latest-post

In this article, I show you an easy way to set up browser push notifications. fist of all, you have a question what is push notification? let me explain a bit more. Push notification is the fastest way to get up and running with Javascript desktop notifications. Push notifications are messages that can be sent directly to a user's Desktop via browser.

You can watch the following tutorial and you can continue reading this article.

Follow the Steps given here for setup push notification.

Step 1: You can quickly install Push via npm

npm install push.js --save

Step 2: Update webpack.mix.js

Add following code into webpack.mix.js for copy and publish assets like js in the public directory. you can see the example here

mix.copy('node_modules/push.js/bin/push.min.js',
    'public/assets/js/push.min.js');

I hope you know how to use laravel mix. you can watch this video tutorial if you want to know more about the laravel mix.

fire, npm run dev command and publish js.

Step 3: Add assets in blade file

Add script before closing body tag.

Step 4: Add this code where you want to show a push

// add logo in public dir and use it here
const iconPath = '{{ asset('logo.PNG') }}
 Push.create("Hello Shailesh!",{
       body: "Welcome to the Dashboard.",
       timeout: 5000,
       icon: iconPath
});
December 03, 20213 MinutesuserShailesh Ladumor

Posts

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 it 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 the .htaccess file in our root folder.

We can copy the .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]

By adding the above file to the root folder we can use laravel projects 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

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
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 identifies 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 clients 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 a user can convert his account from Freemium to Premium at any point in 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 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 in 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 the 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 should not be encrypted.

      @var array
     /
    protected $except = [undefined];
}

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 a 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

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 patterns and for the same, we have different assets folders 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 needed 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 the 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 the 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

In chapter 5 of Gita, Karma-Sanyas-Yog, Lord Shree Krishna said in verse 8,

યોગયુક્ત તત્વને જાણનારો મનુષ્ય જુએ, સાંભળે, સ્પર્શ કરે, સૂંઘે, ખાય, ચાલે, ઊંઘે, શ્વાસ લે, બોલે, મળત્યાગ કરે, ગ્રહણ કરે, નેત્ર ઉઘાડે તથા મીંચે તો પણ "ઇન્દ્રિયોના વિષયોમાં ઇન્દ્રિયો વર્તે છે" એમ સમજી "હું કાંઈ જ કરતો નથી" એમ મને છે.

The wise person knows, just like breathing, smelling, opening and closing eyelid, eating, sleep happens automatically, just like that He believes that everything is happening by itself. I’m just doing nothing.

Same in business, do not try to micro-manage things. Some things happen by themselves. And let them happen in their own way. If you will spend your time micro-managing those small things then you will never be able to focus on other important things.

The another important thing is,

જ્ઞાનીઓ વિદ્યાવિનયયુક્ત બ્રાહ્મણમાં, ગાયમાં, હાથીમાં, કૂતરામાં તથા ચાંડાલમાં પણ સમાન દ્રષ્ટિ રાખવાવાળા હોય છે.

Sometimes people only respect certain people. Like some people only give respect to rich and financially sound people but they don’t pay attention to middle or lower income group people. Such behavior is not proper. Same way in the office as well, we give attention to some people and we might not give attention to the office boy, pun, watchman, cleaner, etc., or Senior Developer vs Junior Developer. One must consider each and everyone with equality. Each and everyone should be respected. Just say Hi or Hello and see the Joy that you and they get.

You can also listen to the full podcast here.

February 07, 20201 minuteauthorMitul Golakiya
post

In Last Podcast and Blog Post, we discussed how we need to create 4 departments in our business and become A-Karta in our organization.

But just becoming A-Karta doesn't work. So in verse 7 & 8, Lord Shree Krishna said and this is one of the most popular verses of Bhagavad Gita,

यदा यदा हि धर्मस्य ग्लानिर्भवति भारत |

अभ्युत्थानमधर्मस्य तदात्मानं सृजाम्यहम् || 7 ||

परित्राणाय साधूनां विनाशाय च दुष्कृताम् |

धर्मसंस्थापनार्थाय सम्भवामि युगे युगे || 8 ||

હે ભારત! જયારે જયારે ધર્મ ને હાનિ થાય છે અને અધર્મનું જોર વધે છે, ત્યારે ત્યારે હું જન્મ ધારણ કરું છું. સત્પુરુષોનાં રક્ષણ માટે, દુષ્ટોના વિનાશ માટે અને ધર્મની સારી રીતે સ્થાપના કરવા માટે હું યુગે યુગે પ્રકટું છું.

Whenever there is an increase in unrighteousness, Lord appears on earth age by age, to protect the righteous, to annihilate the wicked, and to re-establish the principles of dharma.

Same way when our 4 created departments do not do their work or perform their duties or do not produce desired results, then we also need to come into the picture time by time.

Whenever there is an increase in unrighteousness - People do not perform their duties or you do not get results

Lord appears on earth age by age - You need to come in the picture time by time

protect the righteous, to annihilate the wicked - to protect your culture & company & its people

and to re-establish the principles of dharma - to re-establish the balance and processes of the company.

You can also listen to the full podcast here.

February 01, 20201 minuteauthorMitul Golakiya
post

Shreemad Bhagavad Gita has a lot to say about business management. In the last Post of Karma-Yoga, we have seen how our actions should be for the benefits of the others. Today, let's see Chapter 4.

In Chapter 4, Karma-Brahm-Arpan-Yoga (Jñāna Karm Sanyās Yog), verse 13th and 14th, Lord Krishna said,

चातुर्वर्ण्यं मया सृष्टं गुणकर्मविभागश: |

तस्य कर्तारमपि मां विद्ध्यकर्तारमव्ययम् || 13 ||

The four categories of occupations were created by me according to people’s qualities and activities. Although I am the creator of this system, know me to be the non-doer and eternal. (source: holy-bhagavad-gita.org)

પ્રકૃતિના ત્રણ ગુણો એન્ડ કર્મોના વિભાગ પ્રમાણે મેં બ્રાહ્મણ, ક્ષત્રિય, વૈશ્ય અને શુદ્ર એમ ચાર વર્ણોની રચના કરી છે. તેનો હું કર્તા હોવા છતાં પણ તું મને અકર્તા અને અવિકારી જાણ.

न मां कर्माणि लिम्पन्ति न मे कर्मफले स्पृहा |

इति मां योऽभिजानाति कर्मभिर्न स बध्यते || 14 ||

Activities do not taint me, nor do I desire the fruits of action. One who knows me in this way is never bound by the karmic reactions of work.(source: holy-bhagavad-gita.org)

કોઈ કર્મો મને લેપતા નથી, કેમ કે કર્મોના ફળમાં મને લાલસા નથી. આ રીતે જે મનુષ્ય મને જાણે છે, તે પોતાના કર્મો વડે બંધાતો નથી.

Based on occupation & activities, God created the following 4 Varnas:

  • Brahmins - predisposed toward teaching and worship (how to get the God or go to heaven)
  • Kshatriyas - inclined toward administration and management of the kingdom
  • Vaishyas - form the business and agricultural class (Businessmen)
  • Shudras - working class (The actual person who works)

In the same way, we also need 4 Departments in our Business.

  • Brahmins - Marketing - Do the marketing & they actually help us to meet our God (Our Customer).
  • Kshatriya - HR - Form a Business, Hire Team, Appoint People, Make Policies, define Penalties, etc.
  • Vaishyas - Operations - Administration & Management (or your Top Management Team).
  • Shudra - Technical - Actual working people, our employees who actually do work

What God did is, created these 4 Varnas and given them their duties and activities that they need to perform and he simply became A-Karta (non-doer and eternal).

We as CEO, also need to do that same thing. Create these 4 Departments, assign them their duties and just become an external observer. Then all you need to do is, whenever they got stuck, help them, guide them or train them. That's it.

So just simply, Be a God of your Company.

You can also listen to the full podcast here.

January 24, 20202 minutesauthorMitul Golakiya